]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: select: don't report read ready on a FIFO never opened for writing
authorKen Brown <kbrown@cornell.edu>
Fri, 23 Sep 2022 14:24:04 +0000 (10:24 -0400)
committerKen Brown <kbrown@cornell.edu>
Wed, 19 Oct 2022 12:17:50 +0000 (08:17 -0400)
According to POSIX and the Linux man page, select(2) is supposed to
report read ready if a file is at EOF.  In the case of a FIFO, this
means that the pipe is empty and there are no writers.  But there
seems to be an undocumented exception, observed on Linux and other
platforms:  If no writer has ever been opened, then select(2) does not
report read ready.  This can happen if a reader is opened with
O_NONBLOCK before any writers have opened.

This commit makes Cygwin consistent with those other platforms by
introducing a special EOF test, fhandler_fifo::select_hit_eof, which
returns false if there's never been a writer opened.

To implement this we use a new variable '_writer_opened' in the FIFO's
shared memory, which is set to 1 the first time a writer opens.  New
methods writer_opened() and set_writer_opened() are used to test and
set this variable.

Addresses: https://cygwin.com/pipermail/cygwin/2022-September/252223.html

winsup/cygwin/fhandler/fifo.cc
winsup/cygwin/local_includes/fhandler.h
winsup/cygwin/release/3.3.4
winsup/cygwin/select.cc

index 1d3e42908143440a083d8017434c587752a1b264..efea508ae51ca3db456490e594e2f6463c4fba3e 100644 (file)
@@ -1043,6 +1043,7 @@ writer_shmem:
   set_pipe_non_blocking (get_handle (), flags & O_NONBLOCK);
   nwriters_lock ();
   inc_nwriters ();
+  set_writer_opened ();
   SetEvent (write_ready);
   ResetEvent (writer_opening);
   nwriters_unlock ();
index aad7f4c371bda7b5bdfa547ee4446462fba56d70..b012c6e8fb37494ce756e13e0a8299f4a3b7a3d5 100644 (file)
@@ -1327,6 +1327,8 @@ struct fifo_reader_id_t
 class fifo_shmem_t
 {
   LONG _nreaders, _nwriters;
+  /* Set to 1 the first time a writer opens. */
+  LONG _writer_opened;
   fifo_reader_id_t _owner, _prev_owner, _pending_owner;
   af_unix_spinlock_t _owner_lock, _reading_lock, _nreaders_lock, _nwriters_lock;
 
@@ -1343,6 +1345,9 @@ public:
   int inc_nwriters () { return (int) InterlockedIncrement (&_nwriters); }
   int dec_nwriters () { return (int) InterlockedDecrement (&_nwriters); }
 
+  bool writer_opened () const { return (bool) _writer_opened; }
+  void set_writer_opened () { InterlockedExchange (&_writer_opened, 1); }
+
   fifo_reader_id_t get_owner () const { return _owner; }
   void set_owner (fifo_reader_id_t fr_id) { _owner = fr_id; }
   fifo_reader_id_t get_prev_owner () const { return _prev_owner; }
@@ -1425,6 +1430,8 @@ class fhandler_fifo: public fhandler_pipe_fifo
   int nwriters () const { return shmem->nwriters (); }
   int inc_nwriters () { return shmem->inc_nwriters (); }
   int dec_nwriters () { return shmem->dec_nwriters (); }
+  bool writer_opened () const { return shmem->writer_opened (); }
+  void set_writer_opened () { shmem->set_writer_opened (); }
   void nreaders_lock () { shmem->nreaders_lock (); }
   void nreaders_unlock () { shmem->nreaders_unlock (); }
   void nwriters_lock () { shmem->nwriters_lock (); }
@@ -1480,6 +1487,8 @@ public:
   /* Called if we appear to be at EOF after polling fc_handlers. */
   bool hit_eof () const
   { return !nwriters () && !IsEventSignalled (writer_opening); }
+  /* Special EOF test needed by select.cc:peek_fifo(). */
+  bool select_hit_eof () const { return hit_eof () && writer_opened (); }
   int get_nhandlers () const { return nhandlers; }
   fifo_client_handler &get_fc_handler (int i) { return fc_handler[i]; }
   PUNICODE_STRING get_pipe_name ();
index bc74e69146a7bb1228be5be56fbaf1132e425548..616f73ff0df6b40792e3c9153fbaa29ab68e179e 100644 (file)
@@ -37,3 +37,6 @@ Bug Fixes
 - Fix a permission problem when writing DOS attributes on Samba.
   Addresses: https://cygwin.com/pipermail/cygwin/2022-January/250629.html
 
+- For Linux compatibility, select(2) no longer reports read ready on a
+  FIFO that has never been opened for writing.
+  Addresses: https://cygwin.com/pipermail/cygwin/2022-September/252223.html
index 76ab91bbb803b2a993a748add70df9b94332c6a2..2fd7b72b6c0f9c4e1123b02e214c78145d3bbe5f 100644 (file)
@@ -950,7 +950,17 @@ peek_fifo (select_record *s, bool from_select)
            }
        }
       fh->fifo_client_unlock ();
-      if (!nconnected && fh->hit_eof ())
+      /* According to POSIX and the Linux man page, we're supposed to
+        report read ready if the FIFO is at EOF, i.e., if the pipe is
+        empty and there are no writers.  But there seems to be an
+        undocumented exception, observed on Linux and other platforms
+        (https://cygwin.com/pipermail/cygwin/2022-September/252223.html):
+        If no writer has ever been opened, then we do not report read
+        ready.  This can happen if a reader is opened with O_NONBLOCK
+        before any writers have opened.  To be consistent with other
+        platforms, we use a special EOF test that returns false if
+        there's never been a writer opened. */
+      if (!nconnected && fh->select_hit_eof ())
        {
          select_printf ("read: %s, saw EOF", fh->get_name ());
          gotone += s->read_ready = true;
This page took 0.040609 seconds and 5 git commands to generate.