/* * 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 KResultOr> try_create_with_size(size_t, AllocationStrategy); static KResultOr> try_create_for_physical_range(PhysicalAddress paddr, size_t size); static KResultOr> try_create_with_physical_pages(Span>); static KResultOr> try_create_purgeable_with_size(size_t, AllocationStrategy); static KResultOr> try_create_physically_contiguous_with_size(size_t); virtual KResultOr> 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; void set_should_cow(size_t page_index, bool); bool is_purgeable() const { return m_purgeable; } bool is_volatile() const { return m_volatile; } KResult set_volatile(bool is_volatile, bool& was_purged); size_t purge(); private: class SharedCommittedCowPages; explicit AnonymousVMObject(size_t, AllocationStrategy, Optional); explicit AnonymousVMObject(PhysicalAddress, size_t); explicit AnonymousVMObject(Span>); explicit AnonymousVMObject(AnonymousVMObject const&, NonnullRefPtr); 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; } Bitmap& ensure_cow_map(); void 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 : public RefCounted { 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(); public: SpinLock m_lock; CommittedPhysicalPageSet m_committed_pages; }; RefPtr m_shared_committed_cow_pages; bool m_purgeable { false }; bool m_volatile { false }; bool m_was_purged { false }; }; }