public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: FIFO: fix signal handling in raw_read and raw_write
@ 2019-06-23 17:09 Ken Brown
  0 siblings, 0 replies; only message in thread
From: Ken Brown @ 2019-06-23 17:09 UTC (permalink / raw)
  To: cygwin-cvs

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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-06-23 17:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-23 17:09 [newlib-cygwin] Cygwin: FIFO: fix signal handling in raw_read and raw_write Ken Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).