/* * Copyright (c) 2018-2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Kernel::Memory { class AnonymousVMObject final : public VMObject { public: virtual ~AnonymousVMObject() override; static ErrorOr> try_create_with_size(size_t, AllocationStrategy); static ErrorOr> try_create_for_physical_range(PhysicalAddress paddr, size_t size); static ErrorOr> try_create_with_physical_pages(Span>); static ErrorOr> try_create_purgeable_with_size(size_t, AllocationStrategy); static ErrorOr> try_create_physically_contiguous_with_size(size_t); virtual ErrorOr> try_clone() override; [[nodiscard]] NonnullRefPtr allocate_committed_page(Badge); PageFaultResponse handle_cow_fault(size_t, VirtualAddress); size_t cow_pages() const; bool should_cow(size_t page_index, bool) const; ErrorOr set_should_cow(size_t page_index, bool); bool is_purgeable() const { return m_purgeable; } bool is_volatile() const { return m_volatile; } ErrorOr set_volatile(bool is_volatile, bool& was_purged); size_t purge(); private: class SharedCommittedCowPages; static ErrorOr> try_create_with_shared_cow(AnonymousVMObject const&, NonnullLockRefPtr, FixedArray>&&); explicit AnonymousVMObject(FixedArray>&&, AllocationStrategy, Optional); explicit AnonymousVMObject(PhysicalAddress, FixedArray>&&); explicit AnonymousVMObject(FixedArray>&&); explicit AnonymousVMObject(LockWeakPtr, NonnullLockRefPtr, FixedArray>&&); virtual StringView class_name() const override { return "AnonymousVMObject"sv; } AnonymousVMObject& operator=(AnonymousVMObject const&) = delete; AnonymousVMObject& operator=(AnonymousVMObject&&) = delete; AnonymousVMObject(AnonymousVMObject&&) = delete; virtual bool is_anonymous() const override { return true; } ErrorOr ensure_cow_map(); ErrorOr ensure_or_reset_cow_map(); Optional m_unused_committed_pages; Bitmap m_cow_map; // AnonymousVMObject shares committed COW pages with cloned children (happens on fork) class SharedCommittedCowPages final : public AtomicRefCounted { AK_MAKE_NONCOPYABLE(SharedCommittedCowPages); public: SharedCommittedCowPages() = delete; explicit SharedCommittedCowPages(CommittedPhysicalPageSet&&); ~SharedCommittedCowPages(); [[nodiscard]] bool is_empty() const { return m_committed_pages.is_empty(); } [[nodiscard]] NonnullRefPtr take_one(); void uncommit_one(); private: Spinlock m_lock { LockRank::None }; CommittedPhysicalPageSet m_committed_pages; }; LockWeakPtr m_cow_parent; LockRefPtr m_shared_committed_cow_pages; bool m_purgeable { false }; bool m_volatile { false }; bool m_was_purged { false }; }; }