mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +00:00 
			
		
		
		
	Kernel: Start implementing purgeable memory support
It's now possible to get purgeable memory by using mmap(MAP_PURGEABLE). Purgeable memory has a "volatile" flag that can be set using madvise(): - madvise(..., MADV_SET_VOLATILE) - madvise(..., MADV_SET_NONVOLATILE) When in the "volatile" state, the kernel may take away the underlying physical memory pages at any time, without notifying the owner. This gives you a guilt discount when caching very large things. :^) Setting a purgeable region to non-volatile will return whether or not the memory has been taken away by the kernel while being volatile. Basically, if madvise(..., MADV_SET_NONVOLATILE) returns 1, that means the memory was purged while volatile, and whatever was in that piece of memory needs to be reconstructed before use.
This commit is contained in:
		
							parent
							
								
									7248c34e35
								
							
						
					
					
						commit
						dbb644f20c
					
				
					 13 changed files with 196 additions and 9 deletions
				
			
		|  | @ -24,6 +24,7 @@ | ||||||
| #include <Kernel/Net/UDPSocket.h> | #include <Kernel/Net/UDPSocket.h> | ||||||
| #include <Kernel/PCI.h> | #include <Kernel/PCI.h> | ||||||
| #include <Kernel/VM/MemoryManager.h> | #include <Kernel/VM/MemoryManager.h> | ||||||
|  | #include <Kernel/VM/PurgeableVMObject.h> | ||||||
| #include <LibC/errno_numbers.h> | #include <LibC/errno_numbers.h> | ||||||
| 
 | 
 | ||||||
| enum ProcParentDirectory { | enum ProcParentDirectory { | ||||||
|  | @ -262,6 +263,11 @@ Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier) | ||||||
|         region_object.add("writable", region.is_writable()); |         region_object.add("writable", region.is_writable()); | ||||||
|         region_object.add("stack", region.is_stack()); |         region_object.add("stack", region.is_stack()); | ||||||
|         region_object.add("shared", region.is_shared()); |         region_object.add("shared", region.is_shared()); | ||||||
|  |         region_object.add("purgeable", region.vmobject().is_purgeable()); | ||||||
|  |         if (region.vmobject().is_purgeable()) { | ||||||
|  |             region_object.add("volatile", static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile()); | ||||||
|  |         } | ||||||
|  |         region_object.add("purgeable", region.vmobject().is_purgeable()); | ||||||
|         region_object.add("address", region.vaddr().get()); |         region_object.add("address", region.vaddr().get()); | ||||||
|         region_object.add("size", (u32)region.size()); |         region_object.add("size", (u32)region.size()); | ||||||
|         region_object.add("amount_resident", (u32)region.amount_resident()); |         region_object.add("amount_resident", (u32)region.amount_resident()); | ||||||
|  | @ -716,6 +722,8 @@ Optional<KBuffer> procfs$all(InodeIdentifier) | ||||||
|         process_object.add("amount_virtual", (u32)process.amount_virtual()); |         process_object.add("amount_virtual", (u32)process.amount_virtual()); | ||||||
|         process_object.add("amount_resident", (u32)process.amount_resident()); |         process_object.add("amount_resident", (u32)process.amount_resident()); | ||||||
|         process_object.add("amount_shared", (u32)process.amount_shared()); |         process_object.add("amount_shared", (u32)process.amount_shared()); | ||||||
|  |         process_object.add("amount_purgeable_volatile", (u32)process.amount_purgeable_volatile()); | ||||||
|  |         process_object.add("amount_purgeable_nonvolatile", (u32)process.amount_purgeable_nonvolatile()); | ||||||
|         process_object.add("icon_id", process.icon_id()); |         process_object.add("icon_id", process.icon_id()); | ||||||
|         auto thread_array = process_object.add_array("threads"); |         auto thread_array = process_object.add_array("threads"); | ||||||
|         process.for_each_thread([&](const Thread& thread) { |         process.for_each_thread([&](const Thread& thread) { | ||||||
|  |  | ||||||
|  | @ -93,6 +93,7 @@ CXX_OBJS = \ | ||||||
|     VM/PageDirectory.o \
 |     VM/PageDirectory.o \
 | ||||||
|     VM/PhysicalPage.o \
 |     VM/PhysicalPage.o \
 | ||||||
|     VM/PhysicalRegion.o \
 |     VM/PhysicalRegion.o \
 | ||||||
|  |     VM/PurgeableVMObject.o \
 | ||||||
|     VM/RangeAllocator.o \
 |     VM/RangeAllocator.o \
 | ||||||
|     VM/Region.o \
 |     VM/Region.o \
 | ||||||
|     VM/VMObject.o \
 |     VM/VMObject.o \
 | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ | ||||||
| #include <Kernel/TTY/MasterPTY.h> | #include <Kernel/TTY/MasterPTY.h> | ||||||
| #include <Kernel/Thread.h> | #include <Kernel/Thread.h> | ||||||
| #include <Kernel/VM/InodeVMObject.h> | #include <Kernel/VM/InodeVMObject.h> | ||||||
|  | #include <Kernel/VM/PurgeableVMObject.h> | ||||||
| #include <LibC/errno_numbers.h> | #include <LibC/errno_numbers.h> | ||||||
| #include <LibC/signal_numbers.h> | #include <LibC/signal_numbers.h> | ||||||
| #include <LibELF/ELFLoader.h> | #include <LibELF/ELFLoader.h> | ||||||
|  | @ -224,6 +225,18 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params) | ||||||
|         return (void*)-EINVAL; |         return (void*)-EINVAL; | ||||||
| 
 | 
 | ||||||
|     // FIXME: The rest of this function seems like it could share more code..
 |     // FIXME: The rest of this function seems like it could share more code..
 | ||||||
|  |     if (flags & MAP_PURGEABLE) { | ||||||
|  |         auto vmobject = PurgeableVMObject::create_with_size(size); | ||||||
|  |         auto* region = allocate_region_with_vmo(VirtualAddress((u32)addr), size, vmobject, 0, name ? name : "mmap (purgeable)", prot); | ||||||
|  |         if (!region) | ||||||
|  |             return (void*)-ENOMEM; | ||||||
|  |         if (flags & MAP_SHARED) | ||||||
|  |             region->set_shared(true); | ||||||
|  | 
 | ||||||
|  |         region->set_mmap(true); | ||||||
|  |         return region->vaddr().as_ptr(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (flags & MAP_ANONYMOUS) { |     if (flags & MAP_ANONYMOUS) { | ||||||
|         auto* region = allocate_region(VirtualAddress((u32)addr), size, name ? name : "mmap", prot, false); |         auto* region = allocate_region(VirtualAddress((u32)addr), size, name ? name : "mmap", prot, false); | ||||||
|         if (!region) |         if (!region) | ||||||
|  | @ -312,6 +325,52 @@ int Process::sys$mprotect(void* addr, size_t size, int prot) | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int Process::sys$madvise(void* address, size_t size, int advice) | ||||||
|  | { | ||||||
|  |     auto* region = region_from_range({ VirtualAddress((u32)address), size }); | ||||||
|  |     if (!region) | ||||||
|  |         return -EINVAL; | ||||||
|  |     if (!region->is_mmap()) | ||||||
|  |         return -EPERM; | ||||||
|  |     if ((advice & MADV_SET_VOLATILE) && (advice & MADV_SET_NONVOLATILE)) | ||||||
|  |         return -EINVAL; | ||||||
|  |     if (advice & MADV_SET_VOLATILE) { | ||||||
|  |         if (!region->vmobject().is_purgeable()) | ||||||
|  |             return -EPERM; | ||||||
|  |         auto& vmobject = static_cast<PurgeableVMObject&>(region->vmobject()); | ||||||
|  |         vmobject.set_volatile(true); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     if (advice & MADV_SET_NONVOLATILE) { | ||||||
|  |         if (!region->vmobject().is_purgeable()) | ||||||
|  |             return -EPERM; | ||||||
|  |         auto& vmobject = static_cast<PurgeableVMObject&>(region->vmobject()); | ||||||
|  |         vmobject.set_volatile(false); | ||||||
|  |         bool was_purged = vmobject.was_purged(); | ||||||
|  |         vmobject.set_was_purged(false); | ||||||
|  |         return was_purged ? 1 : 0; | ||||||
|  |     } | ||||||
|  |     return -EINVAL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int Process::sys$purge() | ||||||
|  | { | ||||||
|  |     NonnullRefPtrVector<PurgeableVMObject> vmobjects; | ||||||
|  |     { | ||||||
|  |         InterruptDisabler disabler; | ||||||
|  |         MM.for_each_vmobject([&](auto& vmobject) { | ||||||
|  |             if (vmobject.is_purgeable()) | ||||||
|  |                 vmobjects.append(static_cast<PurgeableVMObject&>(vmobject)); | ||||||
|  |             return IterationDecision::Continue; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     int purged_page_count = 0; | ||||||
|  |     for (auto& vmobject : vmobjects) { | ||||||
|  |         purged_page_count += vmobject.purge(); | ||||||
|  |     } | ||||||
|  |     return purged_page_count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int Process::sys$gethostname(char* buffer, ssize_t size) | int Process::sys$gethostname(char* buffer, ssize_t size) | ||||||
| { | { | ||||||
|     if (size < 0) |     if (size < 0) | ||||||
|  | @ -842,7 +901,7 @@ void Process::dump_regions() | ||||||
|     kprintf("Process %s(%u) regions:\n", name().characters(), pid()); |     kprintf("Process %s(%u) regions:\n", name().characters(), pid()); | ||||||
|     kprintf("BEGIN       END         SIZE        ACCESS  NAME\n"); |     kprintf("BEGIN       END         SIZE        ACCESS  NAME\n"); | ||||||
|     for (auto& region : m_regions) { |     for (auto& region : m_regions) { | ||||||
|         kprintf("%08x -- %08x    %08x    %c%c%c%c%c     %s\n", |         kprintf("%08x -- %08x    %08x    %c%c%c%c%c%c    %s\n", | ||||||
|             region.vaddr().get(), |             region.vaddr().get(), | ||||||
|             region.vaddr().offset(region.size() - 1).get(), |             region.vaddr().offset(region.size() - 1).get(), | ||||||
|             region.size(), |             region.size(), | ||||||
|  | @ -851,6 +910,7 @@ void Process::dump_regions() | ||||||
|             region.is_executable() ? 'X' : ' ', |             region.is_executable() ? 'X' : ' ', | ||||||
|             region.is_shared() ? 'S' : ' ', |             region.is_shared() ? 'S' : ' ', | ||||||
|             region.is_stack() ? 'T' : ' ', |             region.is_stack() ? 'T' : ' ', | ||||||
|  |             region.vmobject().is_purgeable() ? 'P' : ' ', | ||||||
|             region.name().characters()); |             region.name().characters()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -2410,6 +2470,26 @@ size_t Process::amount_shared() const | ||||||
|     return amount; |     return amount; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | size_t Process::amount_purgeable_volatile() const | ||||||
|  | { | ||||||
|  |     size_t amount = 0; | ||||||
|  |     for (auto& region : m_regions) { | ||||||
|  |         if (region.vmobject().is_purgeable() && static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile()) | ||||||
|  |             amount += region.amount_resident(); | ||||||
|  |     } | ||||||
|  |     return amount; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t Process::amount_purgeable_nonvolatile() const | ||||||
|  | { | ||||||
|  |     size_t amount = 0; | ||||||
|  |     for (auto& region : m_regions) { | ||||||
|  |         if (region.vmobject().is_purgeable() && !static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile()) | ||||||
|  |             amount += region.amount_resident(); | ||||||
|  |     } | ||||||
|  |     return amount; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int Process::sys$socket(int domain, int type, int protocol) | int Process::sys$socket(int domain, int type, int protocol) | ||||||
| { | { | ||||||
|     int fd = alloc_fd(); |     int fd = alloc_fd(); | ||||||
|  |  | ||||||
|  | @ -139,6 +139,8 @@ public: | ||||||
|     int sys$munmap(void*, size_t size); |     int sys$munmap(void*, size_t size); | ||||||
|     int sys$set_mmap_name(void*, size_t, const char*); |     int sys$set_mmap_name(void*, size_t, const char*); | ||||||
|     int sys$mprotect(void*, size_t, int prot); |     int sys$mprotect(void*, size_t, int prot); | ||||||
|  |     int sys$madvise(void*, size_t, int advice); | ||||||
|  |     int sys$purge(); | ||||||
|     int sys$select(const Syscall::SC_select_params*); |     int sys$select(const Syscall::SC_select_params*); | ||||||
|     int sys$poll(pollfd*, int nfds, int timeout); |     int sys$poll(pollfd*, int nfds, int timeout); | ||||||
|     ssize_t sys$get_dir_entries(int fd, void*, ssize_t); |     ssize_t sys$get_dir_entries(int fd, void*, ssize_t); | ||||||
|  | @ -266,6 +268,8 @@ public: | ||||||
|     size_t amount_virtual() const; |     size_t amount_virtual() const; | ||||||
|     size_t amount_resident() const; |     size_t amount_resident() const; | ||||||
|     size_t amount_shared() const; |     size_t amount_shared() const; | ||||||
|  |     size_t amount_purgeable_volatile() const; | ||||||
|  |     size_t amount_purgeable_nonvolatile() const; | ||||||
| 
 | 
 | ||||||
|     Process* fork(RegisterDump&); |     Process* fork(RegisterDump&); | ||||||
|     int exec(String path, Vector<String> arguments, Vector<String> environment); |     int exec(String path, Vector<String> arguments, Vector<String> environment); | ||||||
|  |  | ||||||
|  | @ -144,7 +144,9 @@ typedef u32 socklen_t; | ||||||
|     __ENUMERATE_SYSCALL(module_unload)          \ |     __ENUMERATE_SYSCALL(module_unload)          \ | ||||||
|     __ENUMERATE_SYSCALL(detach_thread)          \ |     __ENUMERATE_SYSCALL(detach_thread)          \ | ||||||
|     __ENUMERATE_SYSCALL(set_thread_name)        \ |     __ENUMERATE_SYSCALL(set_thread_name)        \ | ||||||
|     __ENUMERATE_SYSCALL(get_thread_name) |     __ENUMERATE_SYSCALL(get_thread_name)        \ | ||||||
|  |     __ENUMERATE_SYSCALL(madvise)                \ | ||||||
|  |     __ENUMERATE_SYSCALL(purge) | ||||||
| 
 | 
 | ||||||
| namespace Syscall { | namespace Syscall { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -27,12 +27,16 @@ | ||||||
| #define MAP_ANONYMOUS 0x20 | #define MAP_ANONYMOUS 0x20 | ||||||
| #define MAP_ANON MAP_ANONYMOUS | #define MAP_ANON MAP_ANONYMOUS | ||||||
| #define MAP_STACK 0x40 | #define MAP_STACK 0x40 | ||||||
|  | #define MAP_PURGEABLE 0x80 | ||||||
| 
 | 
 | ||||||
| #define PROT_READ 0x1 | #define PROT_READ 0x1 | ||||||
| #define PROT_WRITE 0x2 | #define PROT_WRITE 0x2 | ||||||
| #define PROT_EXEC 0x4 | #define PROT_EXEC 0x4 | ||||||
| #define PROT_NONE 0x0 | #define PROT_NONE 0x0 | ||||||
| 
 | 
 | ||||||
|  | #define MADV_SET_VOLATILE 0x100 | ||||||
|  | #define MADV_SET_NONVOLATILE 0x200 | ||||||
|  | 
 | ||||||
| #define F_DUPFD 0 | #define F_DUPFD 0 | ||||||
| #define F_GETFD 1 | #define F_GETFD 1 | ||||||
| #define F_SETFD 2 | #define F_SETFD 2 | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| #include <Kernel/VM/PhysicalAddress.h> | #include <Kernel/VM/PhysicalAddress.h> | ||||||
| #include <Kernel/VM/VMObject.h> | #include <Kernel/VM/VMObject.h> | ||||||
| 
 | 
 | ||||||
| class AnonymousVMObject final : public VMObject { | class AnonymousVMObject : public VMObject { | ||||||
| public: | public: | ||||||
|     virtual ~AnonymousVMObject() override; |     virtual ~AnonymousVMObject() override; | ||||||
| 
 | 
 | ||||||
|  | @ -11,9 +11,11 @@ public: | ||||||
|     static NonnullRefPtr<AnonymousVMObject> create_for_physical_range(PhysicalAddress, size_t); |     static NonnullRefPtr<AnonymousVMObject> create_for_physical_range(PhysicalAddress, size_t); | ||||||
|     virtual NonnullRefPtr<VMObject> clone() override; |     virtual NonnullRefPtr<VMObject> clone() override; | ||||||
| 
 | 
 | ||||||
| private: | protected: | ||||||
|     explicit AnonymousVMObject(size_t); |     explicit AnonymousVMObject(size_t); | ||||||
|     explicit AnonymousVMObject(const AnonymousVMObject&); |     explicit AnonymousVMObject(const AnonymousVMObject&); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|     AnonymousVMObject(PhysicalAddress, size_t); |     AnonymousVMObject(PhysicalAddress, size_t); | ||||||
| 
 | 
 | ||||||
|     AnonymousVMObject& operator=(const AnonymousVMObject&) = delete; |     AnonymousVMObject& operator=(const AnonymousVMObject&) = delete; | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								Kernel/VM/PurgeableVMObject.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Kernel/VM/PurgeableVMObject.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | #include <Kernel/VM/PurgeableVMObject.h> | ||||||
|  | #include <Kernel/VM/PhysicalPage.h> | ||||||
|  | 
 | ||||||
|  | NonnullRefPtr<PurgeableVMObject> PurgeableVMObject::create_with_size(size_t size) | ||||||
|  | { | ||||||
|  |     return adopt(*new PurgeableVMObject(size)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PurgeableVMObject::PurgeableVMObject(size_t size) | ||||||
|  |     : AnonymousVMObject(size) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PurgeableVMObject::PurgeableVMObject(const PurgeableVMObject& other) | ||||||
|  |     : AnonymousVMObject(other) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PurgeableVMObject::~PurgeableVMObject() | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NonnullRefPtr<VMObject> PurgeableVMObject::clone() | ||||||
|  | { | ||||||
|  |     return adopt(*new PurgeableVMObject(*this)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int PurgeableVMObject::purge() | ||||||
|  | { | ||||||
|  |     LOCKER(m_paging_lock); | ||||||
|  |     if (!m_volatile) | ||||||
|  |         return 0; | ||||||
|  |     int purged_page_count = 0; | ||||||
|  |     for (size_t i = 0; i < m_physical_pages.size(); ++i) { | ||||||
|  |         if (m_physical_pages[i]) | ||||||
|  |             ++purged_page_count; | ||||||
|  |         m_physical_pages[i] = nullptr; | ||||||
|  |     } | ||||||
|  |     m_was_purged = true; | ||||||
|  |     return purged_page_count; | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								Kernel/VM/PurgeableVMObject.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Kernel/VM/PurgeableVMObject.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <Kernel/VM/AnonymousVMObject.h> | ||||||
|  | 
 | ||||||
|  | class PurgeableVMObject final : public AnonymousVMObject { | ||||||
|  | public: | ||||||
|  |     virtual ~PurgeableVMObject() override; | ||||||
|  | 
 | ||||||
|  |     static NonnullRefPtr<PurgeableVMObject> create_with_size(size_t); | ||||||
|  |     virtual NonnullRefPtr<VMObject> clone() override; | ||||||
|  | 
 | ||||||
|  |     int purge(); | ||||||
|  | 
 | ||||||
|  |     bool was_purged() const { return m_was_purged; } | ||||||
|  |     void set_was_purged(bool b) { m_was_purged = b; } | ||||||
|  | 
 | ||||||
|  |     bool is_volatile() const { return m_volatile; } | ||||||
|  |     void set_volatile(bool b) { m_volatile = b; } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     explicit PurgeableVMObject(size_t); | ||||||
|  |     explicit PurgeableVMObject(const PurgeableVMObject&); | ||||||
|  | 
 | ||||||
|  |     PurgeableVMObject& operator=(const PurgeableVMObject&) = delete; | ||||||
|  |     PurgeableVMObject& operator=(PurgeableVMObject&&) = delete; | ||||||
|  |     PurgeableVMObject(PurgeableVMObject&&) = delete; | ||||||
|  | 
 | ||||||
|  |     virtual bool is_purgeable() const override { return true; } | ||||||
|  | 
 | ||||||
|  |     bool m_was_purged { false }; | ||||||
|  |     bool m_volatile { false }; | ||||||
|  | }; | ||||||
|  | @ -299,10 +299,11 @@ PageFaultResponse Region::handle_zero_fault(size_t page_index_in_region) | ||||||
|     ASSERT_INTERRUPTS_DISABLED(); |     ASSERT_INTERRUPTS_DISABLED(); | ||||||
|     ASSERT(vmobject().is_anonymous()); |     ASSERT(vmobject().is_anonymous()); | ||||||
| 
 | 
 | ||||||
|     auto& vmobject_physical_page_entry = vmobject().physical_pages()[first_page_index() + page_index_in_region]; |     sti(); | ||||||
|  |     LOCKER(vmobject().m_paging_lock); | ||||||
|  |     cli(); | ||||||
| 
 | 
 | ||||||
|     // NOTE: We don't need to acquire the VMObject's lock.
 |     auto& vmobject_physical_page_entry = vmobject().physical_pages()[first_page_index() + page_index_in_region]; | ||||||
|     //       This function is already exclusive due to interrupts being blocked.
 |  | ||||||
| 
 | 
 | ||||||
|     if (!vmobject_physical_page_entry.is_null()) { |     if (!vmobject_physical_page_entry.is_null()) { | ||||||
| #ifdef PAGE_FAULT_DEBUG | #ifdef PAGE_FAULT_DEBUG | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ public: | ||||||
|     virtual NonnullRefPtr<VMObject> clone() = 0; |     virtual NonnullRefPtr<VMObject> clone() = 0; | ||||||
| 
 | 
 | ||||||
|     virtual bool is_anonymous() const { return false; } |     virtual bool is_anonymous() const { return false; } | ||||||
|  |     virtual bool is_purgeable() const { return false; } | ||||||
|     virtual bool is_inode() const { return false; } |     virtual bool is_inode() const { return false; } | ||||||
| 
 | 
 | ||||||
|     size_t page_count() const { return m_physical_pages.size(); } |     size_t page_count() const { return m_physical_pages.size(); } | ||||||
|  | @ -42,11 +43,10 @@ protected: | ||||||
|     void for_each_region(Callback); |     void for_each_region(Callback); | ||||||
| 
 | 
 | ||||||
|     FixedArray<RefPtr<PhysicalPage>> m_physical_pages; |     FixedArray<RefPtr<PhysicalPage>> m_physical_pages; | ||||||
|  |     Lock m_paging_lock { "VMObject" }; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     VMObject& operator=(const VMObject&) = delete; |     VMObject& operator=(const VMObject&) = delete; | ||||||
|     VMObject& operator=(VMObject&&) = delete; |     VMObject& operator=(VMObject&&) = delete; | ||||||
|     VMObject(VMObject&&) = delete; |     VMObject(VMObject&&) = delete; | ||||||
| 
 |  | ||||||
|     Lock m_paging_lock { "VMObject" }; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -56,4 +56,11 @@ int shm_unlink(const char* name) | ||||||
|     int rc = syscall(SC_shm_unlink, name); |     int rc = syscall(SC_shm_unlink, name); | ||||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); |     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int madvise(void* address, size_t size, int advice) | ||||||
|  | { | ||||||
|  |     int rc = syscall(SC_madvise, address, size, advice); | ||||||
|  |     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #define MAP_ANONYMOUS 0x20 | #define MAP_ANONYMOUS 0x20 | ||||||
| #define MAP_ANON MAP_ANONYMOUS | #define MAP_ANON MAP_ANONYMOUS | ||||||
| #define MAP_STACK 0x40 | #define MAP_STACK 0x40 | ||||||
|  | #define MAP_PURGEABLE 0x80 | ||||||
| 
 | 
 | ||||||
| #define PROT_READ 0x1 | #define PROT_READ 0x1 | ||||||
| #define PROT_WRITE 0x2 | #define PROT_WRITE 0x2 | ||||||
|  | @ -17,6 +18,9 @@ | ||||||
| 
 | 
 | ||||||
| #define MAP_FAILED ((void*)-1) | #define MAP_FAILED ((void*)-1) | ||||||
| 
 | 
 | ||||||
|  | #define MADV_SET_VOLATILE 0x100 | ||||||
|  | #define MADV_SET_NONVOLATILE 0x200 | ||||||
|  | 
 | ||||||
| __BEGIN_DECLS | __BEGIN_DECLS | ||||||
| 
 | 
 | ||||||
| void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t); | void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t); | ||||||
|  | @ -26,5 +30,6 @@ int mprotect(void*, size_t, int prot); | ||||||
| int set_mmap_name(void*, size_t, const char*); | int set_mmap_name(void*, size_t, const char*); | ||||||
| int shm_open(const char* name, int flags, mode_t); | int shm_open(const char* name, int flags, mode_t); | ||||||
| int shm_unlink(const char* name); | int shm_unlink(const char* name); | ||||||
|  | int madvise(void*, size_t, int advice); | ||||||
| 
 | 
 | ||||||
| __END_DECLS | __END_DECLS | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling