This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
[PATCH] Cygwin: shmat: use mmap allocator strategy on 64 bit
- From: corinna-cygwin at cygwin dot com
- To: cygwin-patches at cygwin dot com
- Cc: Ken Brown <kbrown at cornell dot edu>, Michael Haubenwallner <michael dot haubenwallner at ssi-schaefer dot com>
- Date: Thu, 8 Aug 2019 10:55:27 +0200
- Subject: [PATCH] Cygwin: shmat: use mmap allocator strategy on 64 bit
From: Corinna Vinschen <corinna-cygwin@cygwin.com>
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.
---
winsup/cygwin/Makefile.in | 1 +
winsup/cygwin/mmap.cc | 89 +------------------------------------
winsup/cygwin/mmap_alloc.cc | 80 +++++++++++++++++++++++++++++++++
winsup/cygwin/mmap_alloc.h | 21 +++++++++
winsup/cygwin/shm.cc | 8 +++-
5 files changed, 110 insertions(+), 89 deletions(-)
create mode 100644 winsup/cygwin/mmap_alloc.cc
create mode 100644 winsup/cygwin/mmap_alloc.h
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index b687d922db2e..ca0633eb8c1f 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 797373742d29..d8ef037f092e 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 000000000000..5e084b61a7bc
--- /dev/null
+++ b/winsup/cygwin/mmap_alloc.cc
@@ -0,0 +1,80 @@
+#ifdef __x86_64__
+
+#include "winsup.h"
+#include "mmap_alloc.h"
+#include <sys/param.h>
+
+mmap_allocator mmap_alloc; /* Inherited by forked child. */
+
+/* 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;
+}
+
+#endif
+
diff --git a/winsup/cygwin/mmap_alloc.h b/winsup/cygwin/mmap_alloc.h
new file mode 100644
index 000000000000..01c195d525f0
--- /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 805a24b807f7..40d8dcb10a30 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,
--
2.20.1