[newlib-cygwin] Cygwin: FIFO: fix signal handling in raw_read and raw_write

Ken Brown kbrown@sourceware.org
Sun Jun 23 17:09:00 GMT 2019


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=724c18ff7e05545555689854571ea27ed73e8f0b

commit 724c18ff7e05545555689854571ea27ed73e8f0b
Author: Ken Brown <kbrown@cornell.edu>
Date:   Sat Jun 8 11:05:39 2019 -0400

    Cygwin: FIFO: fix signal handling in raw_read and raw_write
    
    cygwait wasn't being called correctly.
    
    Also do some minor cleanup in raw_read and raw_write.

Diff:
---
 winsup/cygwin/fhandler_fifo.cc | 85 +++++++++++++++++++++++++++---------------
 1 file changed, 54 insertions(+), 31 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index c9ff0a3..f63787f 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -640,11 +640,15 @@ ssize_t __reg3
 fhandler_fifo::raw_write (const void *ptr, size_t len)
 {
   ssize_t ret = -1;
-  size_t nbytes = 0, chunk;
+  size_t nbytes = 0;
+  ULONG chunk;
   NTSTATUS status = STATUS_SUCCESS;
   IO_STATUS_BLOCK io;
   HANDLE evt = NULL;
 
+  if (!len)
+    return 0;
+
   if (len <= max_atomic_write)
     chunk = len;
   else if (is_nonblocking ())
@@ -654,7 +658,10 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
 
   /* Create a wait event if the FIFO is in blocking mode. */
   if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
-    return -1;
+    {
+      __seterrno ();
+      return -1;
+    }
 
   /* Write in chunks, accumulating a total.  If there's an error, just
      return the accumulated total unless the first write fails, in
@@ -663,33 +670,35 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
     {
       ULONG_PTR nbytes_now = 0;
       size_t left = len - nbytes;
-      size_t len1;
+      ULONG len1;
+      DWORD waitret = WAIT_OBJECT_0;
+
       if (left > chunk)
 	len1 = chunk;
       else
-	len1 = left;
+	len1 = (ULONG) left;
       nbytes_now = 0;
       status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
 			    (PVOID) ptr, len1, NULL, NULL);
       if (evt && status == STATUS_PENDING)
 	{
-	  DWORD waitret = cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr);
-	  switch (waitret)
-	    {
-	    case WAIT_OBJECT_0:
-	      status = io.Status;
-	      break;
-	    case WAIT_SIGNALED:
-	      status = STATUS_THREAD_SIGNALED;
-	      break;
-	    case WAIT_CANCELED:
-	      status = STATUS_THREAD_CANCELED;
-	      break;
-	    default:
-	      break;
-	    }
+	  waitret = cygwait (evt);
+	  if (waitret == WAIT_OBJECT_0)
+	    status = io.Status;
 	}
-      if (NT_SUCCESS (status))
+      if (waitret == WAIT_CANCELED)
+	status = STATUS_THREAD_CANCELED;
+      else if (waitret == WAIT_SIGNALED)
+	status = STATUS_THREAD_SIGNALED;
+      else if (isclosed ())  /* A signal handler might have closed the fd. */
+	{
+	  if (waitret == WAIT_OBJECT_0)
+	    set_errno (EBADF);
+	  else
+	    __seterrno ();
+	  len = (size_t) -1;
+	}
+      else if (NT_SUCCESS (status))
 	{
 	  nbytes_now = io.Information;
 	  /* NtWriteFile returns success with # of bytes written == 0
@@ -714,7 +723,7 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
     }
   if (evt)
     CloseHandle (evt);
-  if (status == STATUS_THREAD_SIGNALED && !_my_tls.call_signal_handler ())
+  if (status == STATUS_THREAD_SIGNALED && ret < 0)
     set_errno (EINTR);
   else if (status == STATUS_THREAD_CANCELED)
     pthread::static_cancel_self ();
@@ -784,6 +793,9 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
   if (res < 0 || (res == 0 && !listen_client ()))
     goto errout;
 
+  if (!len)
+    return;
+
   while (1)
     {
       if (hit_eof ())
@@ -827,21 +839,32 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 	}
       else
 	{
-	  /* Allow interruption.  Copied from
-	     fhandler_socket_unix::open_reparse_point. */
-	  pthread_testcancel ();
-	  if (cygwait (NULL, cw_nowait, cw_sig_eintr) == WAIT_SIGNALED
-	      && !_my_tls.call_signal_handler ())
+	  /* Allow interruption. */
+	  DWORD waitret = cygwait (NULL, cw_nowait, cw_cancel | cw_sig_eintr);
+	  if (waitret == WAIT_CANCELED)
+	    pthread::static_cancel_self ();
+	  else if (waitret == WAIT_SIGNALED)
 	    {
-	      set_errno (EINTR);
-	      goto errout;
+	      if (_my_tls.call_signal_handler ())
+		continue;
+	      else
+		{
+		  set_errno (EINTR);
+		  goto errout;
+		}
 	    }
-	  /* Don't hog the CPU. */
-	  Sleep (1);
 	}
+      /* We might have been closed by a signal handler or another thread. */
+      if (isclosed ())
+	{
+	  set_errno (EBADF);
+	  goto errout;
+	}
+      /* Don't hog the CPU. */
+      Sleep (1);
     }
 errout:
-  len = -1;
+  len = (size_t) -1;
 }
 
 int __reg2



More information about the Cygwin-cvs mailing list