mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-28 03:27:46 +08:00
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.
This commit is contained in:
parent
5fa9a0e708
commit
1f34405fea
@ -341,6 +341,7 @@ DLL_OFILES:= \
|
||||
miscfuncs.o \
|
||||
mktemp.o \
|
||||
mmap.o \
|
||||
mmap_alloc.o \
|
||||
msg.o \
|
||||
msgcat.o \
|
||||
mount.o \
|
||||
|
@ -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)
|
||||
{
|
||||
|
79
winsup/cygwin/mmap_alloc.cc
Normal file
79
winsup/cygwin/mmap_alloc.cc
Normal file
@ -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
|
21
winsup/cygwin/mmap_alloc.h
Normal file
21
winsup/cygwin/mmap_alloc.h
Normal file
@ -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
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user