public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
From: Ken Brown <kbrown@sourceware.org>
To: cygwin-cvs@sourceware.org
Subject: [newlib-cygwin] Cygwin: fhandler_fifo::raw_read: handle STATUS_PENDING
Date: Wed, 24 Nov 2021 14:03:40 +0000 (GMT)	[thread overview]
Message-ID: <20211124140340.BA5A4385781E@sourceware.org> (raw)

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

commit 4f47e64b11ed8d47c62fa89e9b971f44b7e9ab75
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


                 reply	other threads:[~2021-11-24 14:03 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211124140340.BA5A4385781E@sourceware.org \
    --to=kbrown@sourceware.org \
    --cc=cygwin-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).