Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-07-19 15:17:04 +0400
committerCorinna Vinschen <corinna@vinschen.de>2006-07-19 15:17:04 +0400
commit62b9fc5940c2bc20035e648cb97dd23fa9a7b5d9 (patch)
treef16817140dec33083f028d40937451930bb85aeb
parentc2d7650c68ad01823f8b7f5febec5708fc2ac0d6 (diff)
* Correctly merge HEAD into cv-branch.
-rw-r--r--winsup/cygwin/mmap.cc90
1 files changed, 55 insertions, 35 deletions
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc
index 97966515e..1c1afba57 100644
--- a/winsup/cygwin/mmap.cc
+++ b/winsup/cygwin/mmap.cc
@@ -900,44 +900,64 @@ map::del_list (unsigned i)
}
/* This function is called from exception_handler when a segmentation
- violation has happened. We have two cases to check here.
+ violation has occurred. It should also be called from all Cygwin
+ functions that want to support passing noreserve mmap page addresses
+ to Windows system calls. In that case, 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.
- First, is it an address within "attached" mmap pages (indicated by
- the __PROT_ATTACH protection, see there)? In this case the function
- returns 1 and the exception_handler raises SIGBUS, as demanded by the
- memory protection extension described in SUSv3 (see the mmap man
- page).
-
- Second, check if the address is within "noreserve" mmap pages
- (indicated by MAP_NORESERVE flag). If so, the function calls
- VirtualAlloc to commit the page and returns 2. The exception handler
- then just returns with 0 and the affected application retries the
- failing memory access. If VirtualAlloc fails, the function returns
- 1, so that the exception handler raises a SIGBUS, as described in the
- MAP_NORESERVE man pages for Linux and Solaris.
-
- In any other case 0 is returned and a normal SIGSEGV is raised. */
-int
-mmap_is_attached_or_noreserve_page (ULONG_PTR addr)
+ Check if the address range is all within noreserve mmap regions. If so,
+ call VirtualAlloc to commit the pages and return MMAP_NORESERVE_COMMITED
+ on success. If the page has __PROT_ATTACH (SUSv3 memory protection
+ extension), or if VirutalAlloc fails, return MMAP_RAISE_SIGBUS.
+ Otherwise, return MMAP_NONE if the address range is not covered by an
+ attached or noreserve map.
+
+ On MAP_NORESERVE_COMMITED, the exeception handler should return 0 to
+ allow the application to retry the memory access, or the calling Cygwin
+ function should retry the Windows system call. */
+mmap_region_status
+mmap_is_attached_or_noreserve (void *addr, size_t len)
{
- list *map_list;
- long record_idx;
- caddr_t u_addr;
- DWORD u_len;
- DWORD pagesize = getsystempagesize ();
+ list *map_list = mmapped_areas.get_list_by_fd (-1);
- addr = rounddown (addr, pagesize);
- if (!(map_list = mmapped_areas.get_list_by_fd (-1)))
- return 0;
- if ((record_idx = map_list->search_record ((caddr_t)addr, pagesize,
- u_addr, u_len, -1)) < 0)
- return 0;
- if (map_list->get_record (record_idx)->attached ())
- return 1;
- if (!map_list->get_record (record_idx)->noreserve ())
- return 0;
- DWORD new_prot = map_list->get_record (record_idx)->gen_protect ();
- return VirtualAlloc ((void *)addr, pagesize, MEM_COMMIT, new_prot) ? 2 : 1;
+ size_t pagesize = getpagesize ();
+ caddr_t start_addr = (caddr_t) rounddown ((uintptr_t) addr, pagesize);
+ len += ((caddr_t) addr - start_addr);
+ len = roundup2 (len, pagesize);
+
+ if (map_list == NULL)
+ return MMAP_NONE;
+
+ while (len > 0)
+ {
+ caddr_t u_addr;
+ DWORD u_len;
+ long record_idx = map_list->search_record (start_addr, len,
+ u_addr, u_len, -1);
+ if (record_idx < 0)
+ return MMAP_NONE;
+
+ mmap_record *rec = map_list->get_record (record_idx);
+ if (rec->attached ())
+ return MMAP_RAISE_SIGBUS;
+ if (!rec->noreserve ())
+ return MMAP_NONE;
+
+ size_t commit_len = u_len - (start_addr - u_addr);
+ if (commit_len > len)
+ commit_len = len;
+
+ if (!VirtualAlloc (start_addr, commit_len, MEM_COMMIT,
+ rec->gen_protect ()))
+ return MMAP_RAISE_SIGBUS;
+
+ start_addr += commit_len;
+ len -= commit_len;
+ }
+
+ return MMAP_NORESERVE_COMMITED;
}
static caddr_t