Index: fhandler.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler.cc,v retrieving revision 1.256 diff -u -p -u -p -r1.256 fhandler.cc --- fhandler.cc 13 Jul 2006 20:56:24 -0000 1.256 +++ fhandler.cc 17 Jul 2006 17:02:10 -0000 @@ -223,8 +223,10 @@ fhandler_base::raw_read (void *ptr, size HANDLE h = NULL; /* grumble */ int prio = 0; /* ditto */ + int try_noreserve = 1; DWORD len = ulen; +retry: ulen = (size_t) -1; if (read_state) { @@ -259,8 +261,14 @@ fhandler_base::raw_read (void *ptr, size bytes_read = 0; break; } - case ERROR_INVALID_FUNCTION: case ERROR_INVALID_PARAMETER: + if (try_noreserve) + { + try_noreserve = 0; + if (mmap_commit_noreserve_pages (ptr, len)) + goto retry; + } + case ERROR_INVALID_FUNCTION: case ERROR_INVALID_HANDLE: if (pc.isdir ()) { Index: mmap.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/mmap.cc,v retrieving revision 1.130 diff -u -p -u -p -r1.130 mmap.cc --- mmap.cc 13 Jul 2006 10:29:21 -0000 1.130 +++ mmap.cc 17 Jul 2006 17:02:11 -0000 @@ -899,6 +899,58 @@ map::del_list (unsigned i) } } +/* This function should be called by all Cygwin functions that want to + support passing noreserve mmap page addresses to Windows system calls. + It should be called only after a system call indicates that the + application buffer passed had an invalid virtual address to avoid + any performance impact in non-noreserve cases. + + Check if the address range is all within "noreserve" mmap regions. + If so, call VirtualAlloc to commit the pages and return 1 on success. + If VirtualAlloc fails, raise SIGBUS and return 0. Also return 0 if + the address range was not covered by a noreserve map. + + On success, the calling Cygwin function should retry the Windows system + call. */ +int +mmap_commit_noreserve_pages (void *addr, size_t len) +{ + list *map_list = mmapped_areas.get_list_by_fd (-1); + + if (map_list == NULL) + return 0; + + while (len > 0) + { + caddr_t u_addr; + DWORD u_len; + long record_idx = map_list->search_record ((caddr_t)addr, 1, + u_addr, u_len, -1); + if (record_idx < 0) + return 0; + + mmap_record *rec = map_list->get_record (record_idx); + if (!rec->noreserve ()) + return 0; + + size_t commit_len = u_len - ((char *)addr - u_addr); + if (commit_len > len) + commit_len = len; + + if (VirtualAlloc (addr, commit_len, MEM_COMMIT, rec->gen_protect ()) + == NULL) + { + raise(SIGBUS); + return 0; + } + + addr = (char *)addr + commit_len; + len -= commit_len; + } + + return 1; +} + /* This function is called from exception_handler when a segmentation violation has happened. We have two cases to check here. Index: winsup.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/winsup.h,v retrieving revision 1.189 diff -u -p -u -p -r1.189 winsup.h --- winsup.h 13 Jul 2006 08:33:34 -0000 1.189 +++ winsup.h 17 Jul 2006 17:02:11 -0000 @@ -300,6 +300,7 @@ size_t getsystempagesize (); /* mmap functions. */ void mmap_init (); int mmap_is_attached_or_noreserve_page (ULONG_PTR addr); +int mmap_commit_noreserve_pages (void *addr, size_t len); int winprio_to_nice (DWORD) __attribute__ ((regparm (1))); DWORD nice_to_winprio (int &) __attribute__ ((regparm (1)));