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

commit 724c18ff7e05545555689854571ea27ed73e8f0b
Author: Ken Brown <kbr...@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

Reply via email to