[PATCH 10/12] Cygwin: FIFO: allow take_ownership to be interrupted

Ken Brown kbrown@cornell.edu
Thu Jul 16 16:19:13 GMT 2020


Use cygwait in take_ownership to allow interruption while waiting to
become owner.  Return the cygwait return value or a suitable value to
indicate an error.

raw_read now checks the return value and acts accordingly.
---
 winsup/cygwin/fhandler.h       |  2 +-
 winsup/cygwin/fhandler_fifo.cc | 54 ++++++++++++++++++++++++++++++----
 winsup/cygwin/select.cc        | 11 ++++++-
 3 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 221c856e6..0e0cfbd71 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1489,7 +1489,7 @@ public:
   void owner_lock () { shmem->owner_lock (); }
   void owner_unlock () { shmem->owner_unlock (); }
 
-  void take_ownership ();
+  DWORD take_ownership ();
   void reading_lock () { shmem->reading_lock (); }
   void reading_unlock () { shmem->reading_unlock (); }
 
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index fd1695f40..30486304f 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -1175,15 +1175,16 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
   return ret;
 }
 
-/* Called from raw_read and select.cc:peek_fifo. */
-void
+/* Called from raw_read and select.cc:peek_fifo.  Return WAIT_OBJECT_0
+   on success.  */
+DWORD
 fhandler_fifo::take_ownership ()
 {
   owner_lock ();
   if (get_owner () == me)
     {
       owner_unlock ();
-      return;
+      return WAIT_OBJECT_0;
     }
   set_pending_owner (me);
   /* Wake up my fifo_reader_thread. */
@@ -1192,8 +1193,19 @@ fhandler_fifo::take_ownership ()
     /* Wake up owner's fifo_reader_thread. */
     SetEvent (update_needed_evt);
   owner_unlock ();
-  /* The reader threads should now do the transfer.  */
-  WaitForSingleObject (owner_found_evt, INFINITE);
+  /* The reader threads should now do the transfer. */
+  DWORD waitret = cygwait (owner_found_evt, cw_cancel | cw_sig_eintr);
+  owner_lock ();
+  if (waitret == WAIT_OBJECT_0
+      && (get_owner () != me || get_pending_owner ()))
+    {
+      /* Something went wrong.  Return WAIT_TIMEOUT, which can't be
+	 returned by the above cygwait call. */
+      set_pending_owner (null_fr_id);
+      waitret = WAIT_TIMEOUT;
+    }
+  owner_unlock ();
+  return waitret;
 }
 
 void __reg3
@@ -1206,7 +1218,37 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
     {
       /* No one else can take ownership while we hold the reading_lock. */
       reading_lock ();
-      take_ownership ();
+      switch (take_ownership ())
+	{
+	case WAIT_OBJECT_0:
+	  break;
+	case WAIT_SIGNALED:
+	  if (_my_tls.call_signal_handler ())
+	    {
+	      reading_unlock ();
+	      continue;
+	    }
+	  else
+	    {
+	      set_errno (EINTR);
+	      reading_unlock ();
+	      goto errout;
+	    }
+	  break;
+	case WAIT_CANCELED:
+	  reading_unlock ();
+	  pthread::static_cancel_self ();
+	  break;
+	case WAIT_TIMEOUT:
+	  reading_unlock ();
+	  debug_printf ("take_ownership returned an unexpected result; retry");
+	  continue;
+	default:
+	  reading_unlock ();
+	  debug_printf ("unknown error while trying to take ownership, %E");
+	  goto errout;
+	}
+
       /* Poll the connected clients for input.  Make two passes.  On
 	 the first pass, just try to read from the client from which
 	 we last read successfully.  This should minimize
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 80d16f2a7..3f3f33fb5 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -867,7 +867,16 @@ peek_fifo (select_record *s, bool from_select)
 	}
 
       fh->reading_lock ();
-      fh->take_ownership ();
+      if (fh->take_ownership () != WAIT_OBJECT_0)
+	{
+	  select_printf ("%s, unable to take ownership", fh->get_name ());
+	  fh->reading_unlock ();
+	  gotone += s->read_ready = true;
+	  if (s->except_selected)
+	    gotone += s->except_ready = true;
+	  goto out;
+	}
+
       fh->fifo_client_lock ();
       int nconnected = 0;
       for (int i = 0; i < fh->get_nhandlers (); i++)
-- 
2.27.0



More information about the Cygwin-patches mailing list