https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=1f34405feab107cc5d7b50a023c9407f71eeca62
commit 1f34405feab107cc5d7b50a023c9407f71eeca62 Author: Corinna Vinschen <cori...@vinschen.de> Date: Thu Aug 8 10:53:58 2019 +0200 Cygwin: shmat: use mmap allocator strategy on 64 bit This avoids collisions of shmat maps with Windows own datastructures when allocating top-down. This patch moves the mmap_allocator class definition into its own files and just uses it from mmap and shmat. Diff: --- winsup/cygwin/Makefile.in | 1 + winsup/cygwin/mmap.cc | 89 +-------------------------------------------- winsup/cygwin/mmap_alloc.cc | 79 ++++++++++++++++++++++++++++++++++++++++ winsup/cygwin/mmap_alloc.h | 21 +++++++++++ winsup/cygwin/shm.cc | 8 +++- 5 files changed, 109 insertions(+), 89 deletions(-) diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index b687d92..ca0633e 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -341,6 +341,7 @@ DLL_OFILES:= \ miscfuncs.o \ mktemp.o \ mmap.o \ + mmap_alloc.o \ msg.o \ msgcat.o \ mount.o \ diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index 7973737..d8ef037 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -20,6 +20,7 @@ details. */ #include "cygheap.h" #include "ntdll.h" #include <sys/queue.h> +#include "mmap_alloc.h" /* __PROT_ATTACH indicates an anonymous mapping which is supposed to be attached to a file mapping for pages beyond the file's EOF. The idea @@ -798,94 +799,6 @@ mmap_worker (mmap_list *map_list, fhandler_base *fh, caddr_t base, size_t len, return base; } -#ifdef __x86_64__ - -/* The memory region used for memory maps */ -#define MMAP_STORAGE_LOW 0x001000000000L /* Leave 32 Gigs for heap. */ -/* Up to Win 8 only supporting 44 bit address space, starting with Win 8.1 - 48 bit address space. */ -#define MMAP_STORAGE_HIGH wincap.mmap_storage_high () - -/* FIXME? Unfortunately the OS doesn't support a top down allocation with - a ceiling value. The ZeroBits mechanism only works for - NtMapViewOfSection and it only evaluates the high bit of ZeroBits - on 64 bit, so it's pretty much useless for our purposes. - - If the below simple mechanism to perform top-down allocations - turns out to be too dumb, we need something else. One idea is to - dived the space in (3835) 4 Gig chunks and simply store the - available free space per slot. Then we can go top down from slot - to slot and only try slots which are supposed to have enough space. - Bookkeeping would be very simple and fast. */ -class mmap_allocator -{ - caddr_t mmap_current_low; - -public: - mmap_allocator () : mmap_current_low ((caddr_t) MMAP_STORAGE_HIGH) {} - - PVOID alloc (PVOID in_addr, SIZE_T in_size, bool fixed) - { - MEMORY_BASIC_INFORMATION mbi; - - SIZE_T size = roundup2 (in_size, wincap.allocation_granularity ()); - /* First check for the given address. */ - if (in_addr) - { - /* If it points to a free area, big enough to fulfill the request, - return the address. */ - if (VirtualQuery (in_addr, &mbi, sizeof mbi) - && mbi.State == MEM_FREE - && mbi.RegionSize >= size) - return in_addr; - /* Otherwise, if MAP_FIXED was given, give up. */ - if (fixed) - return NULL; - /* Otherwise, fall through to the usual free space search mechanism. */ - } - /* Start with the last allocation start address - requested size. */ - caddr_t addr = mmap_current_low - size; - bool merry_go_round = false; - do - { - /* Did we hit the lower ceiling? If so, restart from the upper - ceiling, but note that we did it. */ - if (addr < (caddr_t) MMAP_STORAGE_LOW) - { - addr = (caddr_t) MMAP_STORAGE_HIGH - size; - merry_go_round = true; - } - /* Shouldn't fail, but better test. */ - if (!VirtualQuery ((PVOID) addr, &mbi, sizeof mbi)) - return NULL; - /* If the region is free... */ - if (mbi.State == MEM_FREE) - { - /* ...and the region is big enough to fulfill the request... */ - if (mbi.RegionSize >= size) - { - /* ...note the address as next start address for our simple - merry-go-round and return the address. */ - mmap_current_low = addr; - return (PVOID) addr; - } - /* Otherwise, subtract what's missing in size and try again. */ - addr -= size - mbi.RegionSize; - } - /* If the region isn't free, skip to address below AllocationBase - and try again. */ - else - addr = (caddr_t) mbi.AllocationBase - size; - } - /* Repeat until we had a full ride on the merry_go_round. */ - while (!merry_go_round || addr >= mmap_current_low); - return NULL; - } -}; - -static mmap_allocator mmap_alloc; /* Inherited by forked child. */ -#endif - extern "C" void * mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off) { diff --git a/winsup/cygwin/mmap_alloc.cc b/winsup/cygwin/mmap_alloc.cc new file mode 100644 index 0000000..b42bc16 --- /dev/null +++ b/winsup/cygwin/mmap_alloc.cc @@ -0,0 +1,79 @@ +#ifdef __x86_64__ + +#include "winsup.h" +#include "mmap_alloc.h" +#include <sys/param.h> + +/* FIXME? Unfortunately the OS doesn't support a top down allocation with + a ceiling value. The ZeroBits mechanism only works for + NtMapViewOfSection and it only evaluates the high bit of ZeroBits + on 64 bit, so it's pretty much useless for our purposes. + + If the below simple mechanism to perform top-down allocations + turns out to be too dumb, we need something else. One idea is to + dived the space in (3835) 4 Gig chunks and simply store the + available free space per slot. Then we can go top down from slot + to slot and only try slots which are supposed to have enough space. + Bookkeeping would be very simple and fast. */ +PVOID +mmap_allocator::alloc (PVOID in_addr, SIZE_T in_size, bool fixed) +{ + MEMORY_BASIC_INFORMATION mbi; + + SIZE_T size = roundup2 (in_size, wincap.allocation_granularity ()); + /* First check for the given address. */ + if (in_addr) + { + /* If it points to a free area, big enough to fulfill the request, + return the address. */ + if (VirtualQuery (in_addr, &mbi, sizeof mbi) + && mbi.State == MEM_FREE + && mbi.RegionSize >= size) + return in_addr; + /* Otherwise, if MAP_FIXED was given, give up. */ + if (fixed) + return NULL; + /* Otherwise, fall through to the usual free space search mechanism. */ + } + /* Start with the last allocation start address - requested size. */ + caddr_t addr = mmap_current_low - size; + bool merry_go_round = false; + do + { + /* Did we hit the lower ceiling? If so, restart from the upper + ceiling, but note that we did it. */ + if (addr < (caddr_t) MMAP_STORAGE_LOW) + { + addr = (caddr_t) MMAP_STORAGE_HIGH - size; + merry_go_round = true; + } + /* Shouldn't fail, but better test. */ + if (!VirtualQuery ((PVOID) addr, &mbi, sizeof mbi)) + return NULL; + /* If the region is free... */ + if (mbi.State == MEM_FREE) + { + /* ...and the region is big enough to fulfill the request... */ + if (mbi.RegionSize >= size) + { + /* ...note the address as next start address for our simple + merry-go-round and return the address. */ + mmap_current_low = addr; + return (PVOID) addr; + } + /* Otherwise, subtract what's missing in size and try again. */ + addr -= size - mbi.RegionSize; + } + /* If the region isn't free, skip to address below AllocationBase + and try again. */ + else + addr = (caddr_t) mbi.AllocationBase - size; + } + /* Repeat until we had a full ride on the merry_go_round. */ + while (!merry_go_round || addr >= mmap_current_low); + return NULL; +} + +mmap_allocator mmap_alloc; /* Inherited by forked child. */ + +#endif diff --git a/winsup/cygwin/mmap_alloc.h b/winsup/cygwin/mmap_alloc.h new file mode 100644 index 0000000..01c195d --- /dev/null +++ b/winsup/cygwin/mmap_alloc.h @@ -0,0 +1,21 @@ +#ifdef __x86_64__ + +/* The memory region used for memory maps */ +#define MMAP_STORAGE_LOW 0x001000000000L /* Leave 32 Gigs for heap. */ +/* Up to Win 8 only supporting 44 bit address space, starting with Win 8.1 + 48 bit address space. */ +#define MMAP_STORAGE_HIGH wincap.mmap_storage_high () + +class mmap_allocator +{ + caddr_t mmap_current_low; + +public: + mmap_allocator () : mmap_current_low ((caddr_t) MMAP_STORAGE_HIGH) {} + + PVOID alloc (PVOID in_addr, SIZE_T in_size, bool fixed); +}; + +extern mmap_allocator mmap_alloc; + +#endif diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index 805a24b..40d8dcb 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -17,6 +17,7 @@ details. */ #include "cygtls.h" #include "sync.h" #include "ntdll.h" +#include "mmap_alloc.h" /* __getpagesize is only available from libcygwin.a */ #undef SHMLBA @@ -220,8 +221,13 @@ shmat (int shmid, const void *shmaddr, int shmflg) return (void *) -1; } NTSTATUS status; - vm_object_t ptr = NULL; SIZE_T viewsize = ssh_entry->size; +#ifdef __x86_64__ + vm_object_t ptr = mmap_alloc.alloc (NULL, viewsize, false); +#else + vm_object_t ptr = NULL; +#endif + ULONG access = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_READWRITE; status = NtMapViewOfSection (ssh_entry->hdl, NtCurrentProcess (), &ptr, 0, ssh_entry->size, NULL, &viewsize, ViewShare,