From b3bd66961a8cbdf76428bf78f0e2df783219dd79 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Fri, 29 May 2020 15:27:13 +0200 Subject: [PATCH] libroot/kernel: Implement MADV_FREE madvise() extension. It allows an application to signal that it no longer needs the data in the given address range and the underlying pages can be discarded and reused elsewhere. This is finer grained than working with full areas or mappings at a time and enables unmapping sections of partially used mappings without giving up its address space. Compared with punching holes into a mapping by "mapping over" with PROT_NONE and MAP_NORESERVE, this has the obvious advantage of not producing a lot of unused extra areas and saves the corresponding resources. It is also a lot "lighter" of an operation than cutting existing areas. This introduces madvise() alongside the existing posix_madvise() to allow for OS specific extensions. The constants for both functions are aliased, the POSIX_MADV_* being a subset of the MADV_* ones without the non-POSIX extensions. Internally posix_madvise() simply calls madvise(). MADV_FREE is commonly supported in other OSes with various subtle semantic differences as to when pages are actually freed/cleared and how or whether the pages are counted against the memory use of a process. In the variant implemented here, pages are always immediately discarded and memory counting is not altered. This behaviour should be considered an implementation detail and may be altered later. The actual unmap and discard could for example be delayed until pages are needed elsewhere to reduce overhead in case of repeated discarding and remapping. Note that MADV_FREE doesn't really align with the rest of the madvise() API as it works like a command (i.e. discard these pages) and does not add an attribute to the pages in the given range (i.e. mark these pages for quick access from now on). As such, an MADV_FREE does not need to be undone by setting a different advice later on, unlike how the other flags work. This discrepancy may be the reason why it is not part of POSIX. Change-Id: Icc093379125a43e465dc4409d8f5ae0f64e107e0 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2844 Reviewed-by: waddlesplash --- headers/posix/sys/mman.h | 19 ++++++--- src/system/kernel/vm/vm.cpp | 41 ++++++++++++++++++- src/system/libroot/posix/sys/mman.cpp | 9 +++- src/system/libroot/stubbed/libroot_stubs.c | 1 + .../libroot/stubbed/libroot_stubs_legacy.c | 1 + 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/headers/posix/sys/mman.h b/headers/posix/sys/mman.h index 40c49c7b5d..8661ad6c9f 100644 --- a/headers/posix/sys/mman.h +++ b/headers/posix/sys/mman.h @@ -33,12 +33,20 @@ #define MS_SYNC 0x02 #define MS_INVALIDATE 0x04 +/* madvise() values */ +#define MADV_NORMAL 1 +#define MADV_SEQUENTIAL 2 +#define MADV_RANDOM 3 +#define MADV_WILLNEED 4 +#define MADV_DONTNEED 5 +#define MADV_FREE 6 + /* posix_madvise() values */ -#define POSIX_MADV_NORMAL 1 -#define POSIX_MADV_SEQUENTIAL 2 -#define POSIX_MADV_RANDOM 3 -#define POSIX_MADV_WILLNEED 4 -#define POSIX_MADV_DONTNEED 5 +#define POSIX_MADV_NORMAL MADV_NORMAL +#define POSIX_MADV_SEQUENTIAL MADV_SEQUENTIAL +#define POSIX_MADV_RANDOM MADV_RANDOM +#define POSIX_MADV_WILLNEED MADV_WILLNEED +#define POSIX_MADV_DONTNEED MADV_DONTNEED __BEGIN_DECLS @@ -50,6 +58,7 @@ int munmap(void* address, size_t length); int mprotect(void* address, size_t length, int protection); int msync(void* address, size_t length, int flags); +int madvise(void* address, size_t length, int advice); int posix_madvise(void* address, size_t length, int advice); int shm_open(const char* name, int openMode, mode_t permissions); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 5048a69cd5..cc6aff51fb 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -6782,9 +6782,46 @@ _user_sync_memory(void* _address, size_t size, uint32 flags) status_t -_user_memory_advice(void* address, size_t size, uint32 advice) +_user_memory_advice(void* _address, size_t size, uint32 advice) { - // TODO: Implement! + addr_t address = (addr_t)_address; + if ((address % B_PAGE_SIZE) != 0) + return B_BAD_VALUE; + + size = PAGE_ALIGN(size); + if (address + size < address || !IS_USER_ADDRESS(address) + || !IS_USER_ADDRESS(address + size)) { + // weird error code required by POSIX + return B_NO_MEMORY; + } + + switch (advice) { + case MADV_NORMAL: + case MADV_SEQUENTIAL: + case MADV_RANDOM: + case MADV_WILLNEED: + case MADV_DONTNEED: + // TODO: Implement! + break; + + case MADV_FREE: + { + AddressSpaceWriteLocker locker; + do { + status_t status = locker.SetTo(team_get_current_team_id()); + if (status != B_OK) + return status; + } while (wait_if_address_range_is_wired(locker.AddressSpace(), + address, size, &locker)); + + discard_address_range(locker.AddressSpace(), address, size, false); + break; + } + + default: + return B_BAD_VALUE; + } + return B_OK; } diff --git a/src/system/libroot/posix/sys/mman.cpp b/src/system/libroot/posix/sys/mman.cpp index 3944538ef9..bb00ab00ef 100644 --- a/src/system/libroot/posix/sys/mman.cpp +++ b/src/system/libroot/posix/sys/mman.cpp @@ -181,12 +181,19 @@ msync(void* address, size_t length, int flags) int -posix_madvise(void* address, size_t length, int advice) +madvise(void* address, size_t length, int advice) { RETURN_AND_SET_ERRNO(_kern_memory_advice(address, length, advice)); } +int +posix_madvise(void* address, size_t length, int advice) +{ + return madvise(address, length, advice); +} + + int shm_open(const char* name, int openMode, mode_t permissions) { diff --git a/src/system/libroot/stubbed/libroot_stubs.c b/src/system/libroot/stubbed/libroot_stubs.c index f65dfa9e00..73d0c7dfd2 100644 --- a/src/system/libroot/stubbed/libroot_stubs.c +++ b/src/system/libroot/stubbed/libroot_stubs.c @@ -2336,6 +2336,7 @@ void lroundf() {} void lroundl() {} void lsearch() {} void lseek() {} +void madvise() {} void malloc() {} void malloc_usable_size() {} void matherr() {} diff --git a/src/system/libroot/stubbed/libroot_stubs_legacy.c b/src/system/libroot/stubbed/libroot_stubs_legacy.c index fc050f3d18..2de2f3aa35 100644 --- a/src/system/libroot/stubbed/libroot_stubs_legacy.c +++ b/src/system/libroot/stubbed/libroot_stubs_legacy.c @@ -2257,6 +2257,7 @@ void lroundf() {} void lroundl() {} void lsearch() {} void lseek() {} +void madvise() {} void makeSuperblock__Q28BPrivate10superblockiPQ28BPrivate11processHeap() {} void malloc() {} void malloc__Q28BPrivate10threadHeapUl() {}