[PATCH] Cygwin: shmat: use mmap allocator strategy on 64 bit

corinna-cygwin@cygwin.com corinna-cygwin@cygwin.com
Thu Aug 8 08:55:00 GMT 2019


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



More information about the Cygwin-patches mailing list