From 1115b9a9eadf27b4db1cdf6f84957d18638faecf Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Thu, 9 Feb 2012 19:56:48 +0400 Subject: [PATCH] Allow to get memory via Win32 VirtualAlloc (USE_WINALLOC) on Cygwin * README.macros (USE_WINALLOC): Document. * include/private/gcconfig.h (USE_WINALLOC): Add comment. * include/private/gcconfig.h (USE_MMAP): Explicitly undefine if USE_WINALLOC. * os_dep.c (GC_wince_get_mem): Move definition up to simplify ifdef. * os_dep.c (GC_win32_get_mem): Test USE_WINALLOC instead of CYGWIN32; test GLOBAL_ALLOC_TEST value only if MSWIN32. --- doc/README.macros | 3 + include/private/gcconfig.h | 5 ++ os_dep.c | 128 +++++++++++++++++++------------------ 3 files changed, 73 insertions(+), 63 deletions(-) diff --git a/doc/README.macros b/doc/README.macros index e04037dc..195969cb 100644 --- a/doc/README.macros +++ b/doc/README.macros @@ -279,6 +279,9 @@ USE_MUNMAP Causes memory to be returned to the OS under the right Works under some Unix, Linux and Windows versions. Requires USE_MMAP except for Windows. +USE_WINALLOC (Cygwin only) Use Win32 VirtualAlloc (instead of sbrk or mmap) + to get new memory. Useful if memory unmapping (USE_MUNMAP) is enabled. + MUNMAP_THRESHOLD= Set the desired memory blocks unmapping threshold (the number of sequential garbage collections for which a candidate block for unmapping should remain free). diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index ae820ca2..9bb29e3b 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -2440,9 +2440,14 @@ #endif #if (defined(MSWIN32) || defined(MSWINCE)) && !defined(USE_WINALLOC) + /* USE_WINALLOC is only an option for Cygwin. */ # define USE_WINALLOC #endif +#ifdef USE_WINALLOC +# undef USE_MMAP +#endif + #if defined(GC_DISABLE_INCREMENTAL) || defined(MANUAL_VDB) # undef GWW_VDB # undef MPROTECT_VDB diff --git a/os_dep.c b/os_dep.c index 14cb2ebf..d27f4657 100644 --- a/os_dep.c +++ b/os_dep.c @@ -2193,7 +2193,62 @@ void * os2_alloc(size_t bytes) # endif /* OS2 */ -#if defined(MSWIN32) || defined(CYGWIN32) +#ifdef MSWINCE + ptr_t GC_wince_get_mem(word bytes) + { + ptr_t result = 0; /* initialized to prevent warning. */ + word i; + + /* Round up allocation size to multiple of page size */ + bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1); + + /* Try to find reserved, uncommitted pages */ + for (i = 0; i < GC_n_heap_bases; i++) { + if (((word)(-(signed_word)GC_heap_lengths[i]) + & (GC_sysinfo.dwAllocationGranularity-1)) + >= bytes) { + result = GC_heap_bases[i] + GC_heap_lengths[i]; + break; + } + } + + if (i == GC_n_heap_bases) { + /* Reserve more pages */ + word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1) + & ~(GC_sysinfo.dwAllocationGranularity-1); + /* If we ever support MPROTECT_VDB here, we will probably need to */ + /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */ + /* never spans regions. It seems to be OK for a VirtualFree */ + /* argument to span regions, so we should be OK for now. */ + result = (ptr_t) VirtualAlloc(NULL, res_bytes, + MEM_RESERVE | MEM_TOP_DOWN, + GC_pages_executable ? PAGE_EXECUTE_READWRITE : + PAGE_READWRITE); + if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result"); + /* If I read the documentation correctly, this can */ + /* only happen if HBLKSIZE > 64k or not a power of 2. */ + if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections"); + if (result == NULL) return NULL; + GC_heap_bases[GC_n_heap_bases] = result; + GC_heap_lengths[GC_n_heap_bases] = 0; + GC_n_heap_bases++; + } + + /* Commit pages */ + result = (ptr_t) VirtualAlloc(result, bytes, MEM_COMMIT, + GC_pages_executable ? PAGE_EXECUTE_READWRITE : + PAGE_READWRITE); +# undef IGNORE_PAGES_EXECUTABLE + + if (result != NULL) { + if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result"); + GC_heap_lengths[i] += bytes; + } + + return(result); + } + +#elif defined(USE_WINALLOC) || defined(CYGWIN32) # ifdef USE_GLOBAL_ALLOC # define GLOBAL_ALLOC_TEST 1 @@ -2214,16 +2269,19 @@ void * os2_alloc(size_t bytes) { ptr_t result; -# ifdef CYGWIN32 +# ifndef USE_WINALLOC result = GC_unix_get_mem(bytes); # else - if (GLOBAL_ALLOC_TEST) { +# ifdef MSWIN32 + if (GLOBAL_ALLOC_TEST) { /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE. */ /* There are also unconfirmed rumors of other */ /* problems, so we dodge the issue. */ result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE); result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1)); - } else { + } else +# endif + /* else */ { /* VirtualProtect only works on regions returned by a */ /* single VirtualAlloc call. Thus we allocate one */ /* extra page, which will prevent merging of blocks */ @@ -2257,7 +2315,7 @@ void * os2_alloc(size_t bytes) PAGE_READWRITE); # undef IGNORE_PAGES_EXECUTABLE } -# endif /* !CYGWIN32 */ +# endif /* USE_WINALLOC */ if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result"); /* If I read the documentation correctly, this can */ /* only happen if HBLKSIZE > 64k or not a power of 2. */ @@ -2282,7 +2340,7 @@ void * os2_alloc(size_t bytes) } } } -#endif /* MSWIN32 || CYGWIN32 */ +#endif /* USE_WINALLOC || CYGWIN32 */ #ifdef AMIGA # define GC_AMIGA_AM @@ -2290,63 +2348,6 @@ void * os2_alloc(size_t bytes) # undef GC_AMIGA_AM #endif - -#ifdef MSWINCE - ptr_t GC_wince_get_mem(word bytes) - { - ptr_t result = 0; /* initialized to prevent warning. */ - word i; - - /* Round up allocation size to multiple of page size */ - bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1); - - /* Try to find reserved, uncommitted pages */ - for (i = 0; i < GC_n_heap_bases; i++) { - if (((word)(-(signed_word)GC_heap_lengths[i]) - & (GC_sysinfo.dwAllocationGranularity-1)) - >= bytes) { - result = GC_heap_bases[i] + GC_heap_lengths[i]; - break; - } - } - - if (i == GC_n_heap_bases) { - /* Reserve more pages */ - word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1) - & ~(GC_sysinfo.dwAllocationGranularity-1); - /* If we ever support MPROTECT_VDB here, we will probably need to */ - /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */ - /* never spans regions. It seems to be OK for a VirtualFree */ - /* argument to span regions, so we should be OK for now. */ - result = (ptr_t) VirtualAlloc(NULL, res_bytes, - MEM_RESERVE | MEM_TOP_DOWN, - GC_pages_executable ? PAGE_EXECUTE_READWRITE : - PAGE_READWRITE); - if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result"); - /* If I read the documentation correctly, this can */ - /* only happen if HBLKSIZE > 64k or not a power of 2. */ - if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections"); - if (result == NULL) return NULL; - GC_heap_bases[GC_n_heap_bases] = result; - GC_heap_lengths[GC_n_heap_bases] = 0; - GC_n_heap_bases++; - } - - /* Commit pages */ - result = (ptr_t) VirtualAlloc(result, bytes, MEM_COMMIT, - GC_pages_executable ? PAGE_EXECUTE_READWRITE : - PAGE_READWRITE); -# undef IGNORE_PAGES_EXECUTABLE - - if (result != NULL) { - if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result"); - GC_heap_lengths[i] += bytes; - } - - return(result); - } -#endif - #ifdef USE_MUNMAP /* For now, this only works on Win32/WinCE and some Unix-like */ @@ -2511,6 +2512,7 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, while (len != 0) { MEMORY_BASIC_INFORMATION mem_info; GC_word free_len; + if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info)) != sizeof(mem_info)) ABORT("Weird VirtualQuery result"); -- 2.40.0