Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin AT sources DOT redhat DOT com From: "Zack Weinberg" Date: Tue, 9 Jan 2001 22:01:49 -0800 To: cygwin AT sources DOT redhat DOT com Subject: would appreciate help with anon-mmap replacement Message-ID: <20010109220149.J2032@wolery.stanford.edu> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.3.12i I'm trying to fix GCC's present problems with cygwin's mmap implementation. GCC uses mmap to obtain anonymous memory, and expects Unix-compatible semantics in detail - these are (as far as I can tell) unimplementable under Windows due to the way the underlying system calls work. This was partially addressed in cygwin 1.1.7; it doesn't crash anymore, it just leaks memory continuously. A solution inside cygwin would be a lot of work and wouldn't help people with older versions of the library. Therefore, I'm focusing on a solution inside GCC's support library, using VirtualAlloc() directly. I have attempted to write the appropriate routines and a test program which demonstrates what GCC needs. When this test program is run on a modern Unix system it exits successfully. When run under cygwin it goes into an infinite loop chewing CPU. cygwin strace reports this over and over again (with different leading numbers): 1034 1296856 [main] test 310 handle_exceptions: In cygwin_except_handler exc 0xC0000005 at 0x4013AB sp 0x246FE7C 614 1297470 [main] test 310 handle_exceptions: In cygwin_except_handler sig = 11 at 0x4013AB 608 1298078 [main] test 310 handle_exceptions: In cygwin_except_handler calling 0x4010E0 728 1298806 [main] test 310 sig_send: pid 310, signal 11, its_me 1 608 1299414 [main] test 310 sig_send: Waiting for thiscomplete 0xC 915 1300329 [sig] test 310 wait_sig: looping 738 1301067 [sig] test 310 wait_sig: awake 651 1301718 [sig] test 310 wait_sig: sig 11 blocked 655 1302373 [main] test 310 sig_send: returning 0 from sending signal 11 I'd appreciate any help anyone can offer. I do not have access to a cygwin machine, and my knowledge of the Windows API is limited to the online docs at msdn.microsoft.com, so it's likely I've made an obvious mistake. [I had someone run the test for me.] Note that the test program won't work on a Unix box that doesn't have MAP_ANON(YMOUS), which is rather a lot of them. The real thing will of course know about /dev/zero; I left that out for simplicity. Thanks. zw #ifdef _WIN32 #include #define MAP_FAILED 0 #else #include #include #include #include #ifndef MAP_ANON # ifdef MAP_ANONYMOUS # define MAP_ANON MAP_ANONYMOUS # else # error "Won't work without MAP_ANON(YMOUS)." # endif #endif #ifndef MAP_FAILED # define MAP_FAILED -1 #endif #endif /* _WIN32 */ #include #include #include #undef perror_exit #define perror_exit(str, val) \ do { perror(str); exit(val); } while (0) /* Anonymous mmap replacement for cygwin environment. This attempts to produce the semantics needed by GCC by careful use of low-level Win32 routines. The fundamental difficulty is that Unix style anonymous mmap() both "reserves" and "commits" memory; it does so with page granularity; and munmap() both "decommits" and "releases" exactly what you ask it to, irrespective of what chunks were inside or overlapped that region. Cygwin's existing mmap implementation uses MapViewOfFile and UnmapViewOfFile with a -1 HANDLE. These can only be used in exact pairs (i.e. you have to release exactly the chunk of memory you originally allocated). The same is true of VirtualAlloc and VirtualFree "reserving" and "releasing" memory, with the additional gotcha of 64K (segment?) granularity. VA/VF "committing" and "decommitting" memory appear to be as close to Unix semantics as you can get. So we "reserve" a huge block of memory at the beginning, then trust that future VA(0, size, MEM_COMMIT ...) calls will use that region without further prompting. We further trust that the reserved region gets discarded automatically when the process terminates. */ static void anonmap_init () { #ifdef _WIN32 /* Reserve one gigabyte of address space. This should be satisfiable by all existing versions of Windows. */ char *arena = (char *) VirtualAlloc (0, 1024 * 1024 * 1024, MEM_RESERVE, 0); if (arena == NULL) perror_exit ("reserve", 127); #endif } static char * anonmap (size, loc) size_t size; char *loc; { #ifdef _WIN32 return (char *) VirtualAlloc (loc, size, MEM_COMMIT, PAGE_READWRITE); #else return (char *) mmap (loc, size, PROT_READ|PROT_WRITE, (loc ? MAP_FIXED : 0)|MAP_PRIVATE|MAP_ANON, -1, 0); #endif } static void anonfree (loc, size) char *loc; size_t size; { #ifdef _WIN32 VirtualFree (loc, size, MEM_DECOMMIT); #else munmap (loc, size); #endif } static jmp_buf r; static size_t pg; static void sigsegv (unused) int unused; { longjmp (r, 1); } /* 1. If we map a 2-page region and unmap its second page, the first page must remain. */ void test_1 () { char *x = anonmap (pg * 2, 0); if (x == (char *)MAP_FAILED) perror_exit ("test 1 mmap", 1); signal (SIGSEGV, sigsegv); if (setjmp (r)) perror_exit ("test 1 fault", 2); x[0] = 1; x[pg] = 1; anonfree (x + pg, pg); x[0] = 2; if (setjmp (r)) { anonfree (x, pg); return; } x[pg] = 1; perror_exit ("test 1 no fault", 3); } /* 2. If we map a 2-page region and unmap its first page, the second page must remain. */ void test_2 () { char *x = anonmap (pg * 2, 0); if (x == (char *)MAP_FAILED) perror_exit ("test 2 mmap", 4); signal (SIGSEGV, sigsegv); if (setjmp (r)) perror_exit ("test 2 fault", 5); x[0] = 1; x[pg] = 1; anonfree (x, pg); x[pg] = 2; if (setjmp (r)) { anonfree (x + pg, pg); return; } x[0] = 1; perror_exit ("test 2 no fault", 6); } /* 3. If we map two consecutive 1-page regions and unmap them both with one munmap, both must go away. */ void test_3 () { char *x, *y; x = anonmap (pg, 0); if (x == (char *)MAP_FAILED) perror_exit ("test 3 mmap 1", 7); y = anonmap (pg, x+pg); if (y == (char *)MAP_FAILED || x + pg != y) perror_exit ("test 3 mmap 2", 7); signal (SIGSEGV, sigsegv); if (setjmp (r)) perror_exit ("test 3 fault", 8); x[0] = 1; x[pg] = 1; anonfree (x, pg * 2); if (setjmp (r) == 0) { x[0] = 1; perror_exit ("test 3 no fault 1", 9); } signal (SIGSEGV, sigsegv); if (setjmp (r) == 0) { x[pg] = 1; perror_exit ("test 3 no fault 2", 10); } } int main () { pg = getpagesize (); anonmap_init (); test_1(); test_2(); test_3(); exit(0); } -- Want to unsubscribe from this list? Check out: http://cygwin.com/ml/#unsubscribe-simple