allow read into untouched noreserve mappings

Brian Ford Brian.Ford@flightsafety.com
Mon Jul 17 17:25:00 GMT 2006


On Fri, 14 Jul 2006, Corinna Vinschen wrote:

> The idea is to have features working for most cases and then
> to get it working gradually better.

Well, in that spirit then, the attached patch allows read and varients to
use untouched noreserve mappings as buffers.  If this is accepted, I'll
consider doing something similar for recvmsg and recvfrom.  That should
cover the majority of cases, I believe.

2006-07-17  Brian Ford  <Brian.Ford@FlightSafety.com>

	* winsup.h (mmap_commit_noreserve_pages): New prototype.
	* mmap.cc (fhandler_base::raw_read): New function.
	* fhandler.cc (fhandler_base::raw_read): Call it for
	INVALID_PARAMETER errors, and retry on success to allow
	reads into untouched MAP_NORESERVE buffers.

-- 
Brian Ford
Lead Realtime Software Engineer
VITAL - Visual Simulation Systems
FlightSafety International
the best safety device in any aircraft is a well-trained crew...
.

-------------- next part --------------
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)));


More information about the Cygwin-patches mailing list