public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin/cygwin-3_3-branch] Cygwin: fhandler_fifo::raw_read: handle STATUS_PENDING
@ 2021-11-24 14:03 Ken Brown
  0 siblings, 0 replies; only message in thread
From: Ken Brown @ 2021-11-24 14:03 UTC (permalink / raw)
  To: cygwin-cvs

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

commit da32bafaac2d6d7f1fd49df97a828e20ac77b978
Author: Ken Brown <kbrown@cornell.edu>
Date:   Tue Nov 23 11:40:56 2021 -0500

    Cygwin: fhandler_fifo::raw_read: handle STATUS_PENDING
    
    NtReadFile can return STATUS_PENDING occasionally even in non-blocking
    mode.  Check for this and wait for NtReadFile to complete.  To avoid
    code repetition, do this in a static helper function nt_read.

Diff:
---
 winsup/cygwin/fhandler_fifo.cc | 70 ++++++++++++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 23 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 489ba528c..34bd835ae 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -1201,12 +1201,39 @@ fhandler_fifo::release_select_sem (const char *from)
     ReleaseSemaphore (select_sem, n_release, NULL);
 }
 
+/* Read from a non-blocking pipe and wait for completion. */
+static NTSTATUS
+nt_read (HANDLE h, HANDLE evt, PIO_STATUS_BLOCK pio, void *in_ptr, size_t& len)
+{
+  NTSTATUS status;
+
+  ResetEvent (evt);
+  status = NtReadFile (h, evt, NULL, NULL, pio, in_ptr, len, NULL, NULL);
+  if (status == STATUS_PENDING)
+    {
+      /* Very short-lived */
+      status = NtWaitForSingleObject (evt, FALSE, NULL);
+      if (NT_SUCCESS (status))
+	status = pio->Status;
+    }
+  return status;
+}
+
 void __reg3
 fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 {
+  HANDLE evt;
+
   if (!len)
     return;
 
+  if (!(evt = CreateEvent (NULL, false, false, NULL)))
+    {
+      __seterrno ();
+      len = (size_t) -1;
+      return;
+    }
+
   while (1)
     {
       int nconnected = 0;
@@ -1244,17 +1271,15 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 	  NTSTATUS status;
 	  IO_STATUS_BLOCK io;
 
-	  status = NtReadFile (fc_handler[j].h, NULL, NULL, NULL,
-			       &io, in_ptr, len, NULL, NULL);
+	  status = nt_read (fc_handler[j].h, evt, &io, in_ptr, len);
 	  switch (status)
 	    {
 	    case STATUS_SUCCESS:
 	    case STATUS_BUFFER_OVERFLOW:
-	      /* io.Information is supposedly valid in latter case. */
 	      if (io.Information > 0)
 		{
 		  len = io.Information;
-		  goto out;
+		  goto unlock_out;
 		}
 	      break;
 	    case STATUS_PIPE_EMPTY:
@@ -1265,7 +1290,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 	      fc_handler[j].set_state (fc_disconnected);
 	      break;
 	    default:
-	      debug_printf ("NtReadFile status %y", status);
+	      debug_printf ("nt_read status %y", status);
 	      fc_handler[j].set_state (fc_error);
 	      break;
 	    }
@@ -1278,8 +1303,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 	    NTSTATUS status;
 	    IO_STATUS_BLOCK io;
 
-	    status = NtReadFile (fc_handler[i].h, NULL, NULL, NULL,
-				 &io, in_ptr, len, NULL, NULL);
+	    status = nt_read (fc_handler[i].h, evt, &io, in_ptr, len);
 	    switch (status)
 	      {
 	      case STATUS_SUCCESS:
@@ -1290,7 +1314,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		    if (j < nhandlers)
 		      fc_handler[j].last_read = false;
 		    fc_handler[i].last_read = true;
-		    goto out;
+		    goto unlock_out;
 		  }
 		break;
 	      case STATUS_PIPE_EMPTY:
@@ -1301,7 +1325,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		fc_handler[i].set_state (fc_disconnected);
 		break;
 	      default:
-		debug_printf ("NtReadFile status %y", status);
+		debug_printf ("nt_read status %y", status);
 		fc_handler[i].set_state (fc_error);
 		break;
 	      }
@@ -1315,8 +1339,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 	    IO_STATUS_BLOCK io;
 
 	    nconnected++;
-	    status = NtReadFile (fc_handler[i].h, NULL, NULL, NULL,
-				 &io, in_ptr, len, NULL, NULL);
+	    status = nt_read (fc_handler[i].h, evt, &io, in_ptr, len);
 	    switch (status)
 	      {
 	      case STATUS_SUCCESS:
@@ -1327,7 +1350,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		    if (j < nhandlers)
 		      fc_handler[j].last_read = false;
 		    fc_handler[i].last_read = true;
-		    goto out;
+		    goto unlock_out;
 		  }
 		break;
 	      case STATUS_PIPE_EMPTY:
@@ -1337,25 +1360,25 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		nconnected--;
 		break;
 	      default:
-		debug_printf ("NtReadFile status %y", status);
+		debug_printf ("nt_read status %y", status);
 		fc_handler[i].set_state (fc_error);
 		nconnected--;
 		break;
 	      }
 	  }
-      fifo_client_unlock ();
       if (!nconnected && hit_eof ())
 	{
-	  reading_unlock ();
 	  len = 0;
-	  return;
+	  goto unlock_out;
 	}
+      fifo_client_unlock ();
 maybe_retry:
       reading_unlock ();
       if (is_nonblocking ())
 	{
 	  set_errno (EAGAIN);
-	  goto errout;
+	  len = (size_t) -1;
+	  goto out;
 	}
       else
 	{
@@ -1370,7 +1393,8 @@ maybe_retry:
 	      else
 		{
 		  set_errno (EINTR);
-		  goto errout;
+		  len = (size_t) -1;
+		  goto out;
 		}
 	    }
 	}
@@ -1378,17 +1402,17 @@ maybe_retry:
       if (isclosed ())
 	{
 	  set_errno (EBADF);
-	  goto errout;
+	  len = (size_t) -1;
+	  goto out;
 	}
     }
-errout:
-  len = (size_t) -1;
-  return;
-out:
+unlock_out:
   fifo_client_unlock ();
   reading_unlock ();
+out:
   if (select_sem)
     release_select_sem ("raw_read");
+  CloseHandle (evt);
 }
 
 int __reg2


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

only message in thread, other threads:[~2021-11-24 14:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-24 14:03 [newlib-cygwin/cygwin-3_3-branch] Cygwin: fhandler_fifo::raw_read: handle STATUS_PENDING 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).