summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler.h19
-rw-r--r--winsup/cygwin/fhandler_fifo.cc84
-rw-r--r--winsup/cygwin/select.cc44
3 files changed, 98 insertions, 49 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 4d691a0fc..3bc04cf13 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1296,19 +1296,26 @@ struct fifo_client_handler
/* Returns FILE_PIPE_DISCONNECTED_STATE, FILE_PIPE_LISTENING_STATE,
FILE_PIPE_CONNECTED_STATE, FILE_PIPE_CLOSING_STATE,
FILE_PIPE_INPUT_AVAILABLE_STATE, or -1 on error. */
+ fifo_client_connect_state &get_state () { return state; }
int pipe_state ();
};
class fhandler_fifo: public fhandler_base
{
- HANDLE read_ready;
- HANDLE write_ready;
+ /* Handles to named events shared by all fhandlers for a given FIFO. */
+ HANDLE read_ready; /* A reader is open; OK for a writer to open. */
+ HANDLE write_ready; /* A writer is open; OK for a reader to open. */
+ HANDLE writer_opening; /* A writer is opening; no EOF. */
+
+ /* Non-shared handles needed for the listen_client_thread. */
HANDLE listen_client_thr;
HANDLE lct_termination_evt;
+
UNICODE_STRING pipe_name;
WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
+ bool _maybe_eof;
fifo_client_handler fc_handler[MAX_CLIENTS];
- int nhandlers, nconnected;
+ int nhandlers;
af_unix_spinlock_t _fifo_client_lock;
bool reader, writer, duplexer;
size_t max_atomic_write;
@@ -1326,10 +1333,10 @@ class fhandler_fifo: public fhandler_base
public:
fhandler_fifo ();
bool hit_eof ();
+ bool maybe_eof () const { return _maybe_eof; }
+ void maybe_eof (bool val) { _maybe_eof = val; }
int get_nhandlers () const { return nhandlers; }
- HANDLE get_fc_handle (int i) const { return fc_handler[i].h; }
- bool is_connected (int i) const
- { return fc_handler[i].state == fc_connected; }
+ fifo_client_handler get_fc_handler (int i) const { return fc_handler[i]; }
PUNICODE_STRING get_pipe_name ();
DWORD listen_client_thread ();
void fifo_client_lock () { _fifo_client_lock.lock (); }
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 4904a535d..21faf4ec2 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -66,9 +66,10 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
|| _s == STATUS_PIPE_BUSY; })
fhandler_fifo::fhandler_fifo ():
- fhandler_base (), read_ready (NULL), write_ready (NULL),
- listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
- nconnected (0), reader (false), writer (false), duplexer (false),
+ fhandler_base (),
+ read_ready (NULL), write_ready (NULL), writer_opening (NULL),
+ listen_client_thr (NULL), lct_termination_evt (NULL), _maybe_eof (false), nhandlers (0),
+ reader (false), writer (false), duplexer (false),
max_atomic_write (DEFAULT_PIPEBUFSIZE)
{
pipe_name_buf[0] = L'\0';
@@ -295,7 +296,8 @@ fhandler_fifo::record_connection (fifo_client_handler& fc,
{
SetEvent (write_ready);
fc.state = s;
- nconnected++;
+ maybe_eof (false);
+ ResetEvent (writer_opening);
set_pipe_non_blocking (fc.h, true);
}
@@ -465,6 +467,13 @@ fhandler_fifo::open (int flags, mode_t)
res = error_set_errno;
goto out;
}
+ npbuf[0] = 'o';
+ if (!(writer_opening = CreateEvent (sa_buf, true, false, npbuf)))
+ {
+ debug_printf ("CreateEvent for %s failed, %E", npbuf);
+ res = error_set_errno;
+ goto out;
+ }
/* If we're a duplexer, create the pipe and the first client handler. */
if (duplexer)
@@ -518,10 +527,12 @@ fhandler_fifo::open (int flags, mode_t)
listen_client thread is running. Then signal write_ready. */
if (writer)
{
+ SetEvent (writer_opening);
while (1)
{
if (!wait (read_ready))
{
+ ResetEvent (writer_opening);
res = error_errno_set;
goto out;
}
@@ -540,6 +551,7 @@ fhandler_fifo::open (int flags, mode_t)
debug_printf ("create of writer failed");
__seterrno_from_nt_status (status);
res = error_errno_set;
+ ResetEvent (writer_opening);
goto out;
}
}
@@ -559,6 +571,11 @@ out:
NtClose (write_ready);
write_ready = NULL;
}
+ if (writer_opening)
+ {
+ NtClose (writer_opening);
+ writer_opening = NULL;
+ }
if (get_handle ())
NtClose (get_handle ());
if (listen_client_thr)
@@ -717,28 +734,23 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
return ret;
}
-/* A FIFO open for reading is at EOF if no process has it open for
- writing. We test this by checking nconnected. But we must take
- account of the possible delay from the time of connection to the
- time the connection is recorded by the listen_client thread. */
+/* A reader is at EOF if the pipe is empty and no writers are open.
+ hit_eof is called by raw_read and select.cc:peek_fifo if it appears
+ that we are at EOF after polling the fc_handlers. We recheck this
+ in case a writer opened while we were polling. */
bool
fhandler_fifo::hit_eof ()
{
- bool eof;
- bool retry = true;
-
-repeat:
+ bool ret = maybe_eof () && !IsEventSignalled (writer_opening);
+ if (ret)
+ {
+ yield ();
+ /* Wait for the reader thread to finish recording any connection. */
fifo_client_lock ();
- eof = (nconnected == 0);
fifo_client_unlock ();
- if (eof && retry)
- {
- retry = false;
- /* Give the listen_client thread time to catch up. */
- Sleep (1);
- goto repeat;
- }
- return eof;
+ ret = maybe_eof ();
+ }
+ return ret;
}
/* Is the lct running? */
@@ -783,13 +795,8 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
while (1)
{
- if (hit_eof ())
- {
- len = 0;
- return;
- }
-
/* Poll the connected clients for input. */
+ int nconnected = 0;
fifo_client_lock ();
for (int i = 0; i < nhandlers; i++)
if (fc_handler[i].state >= fc_connected)
@@ -798,7 +805,8 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
IO_STATUS_BLOCK io;
size_t nbytes = 0;
- status = NtReadFile (get_fc_handle (i), NULL, NULL, NULL,
+ nconnected++;
+ status = NtReadFile (fc_handler[i].h, NULL, NULL, NULL,
&io, in_ptr, len, NULL, NULL);
switch (status)
{
@@ -826,7 +834,13 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
break;
}
}
+ maybe_eof (!nconnected && !IsEventSignalled (writer_opening));
fifo_client_unlock ();
+ if (maybe_eof () && hit_eof ())
+ {
+ len = 0;
+ return;
+ }
if (is_nonblocking ())
{
set_errno (EAGAIN);
@@ -928,6 +942,8 @@ fhandler_fifo::close ()
NtClose (read_ready);
if (write_ready)
NtClose (write_ready);
+ if (writer_opening)
+ NtClose (writer_opening);
fifo_client_lock ();
for (int i = 0; i < nhandlers; i++)
fc_handler[i].close ();
@@ -979,6 +995,13 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
__seterrno ();
goto err_close_read_ready;
}
+ if (!DuplicateHandle (GetCurrentProcess (), writer_opening,
+ GetCurrentProcess (), &fhf->writer_opening,
+ 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
+ {
+ __seterrno ();
+ goto err_close_write_ready;
+ }
if (reader)
{
/* Make sure the child starts unlocked. */
@@ -1009,6 +1032,9 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
err_close_handlers:
for (int j = 0; j < i; j++)
fhf->fc_handler[j].close ();
+/* err_close_writer_opening: */
+ NtClose (fhf->writer_opening);
+err_close_write_ready:
NtClose (fhf->write_ready);
err_close_read_ready:
NtClose (fhf->read_ready);
@@ -1028,6 +1054,7 @@ fhandler_fifo::fixup_after_fork (HANDLE parent)
fhandler_base::fixup_after_fork (parent);
fork_fixup (parent, read_ready, "read_ready");
fork_fixup (parent, write_ready, "write_ready");
+ fork_fixup (parent, writer_opening, "writer_opening");
if (reader)
{
/* Make sure the child starts unlocked. */
@@ -1062,6 +1089,7 @@ fhandler_fifo::set_close_on_exec (bool val)
fhandler_base::set_close_on_exec (val);
set_no_inheritance (read_ready, val);
set_no_inheritance (write_ready, val);
+ set_no_inheritance (writer_opening, val);
fifo_client_lock ();
for (int i = 0; i < nhandlers; i++)
set_no_inheritance (fc_handler[i].h, val);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index b5d19cf31..9323c423f 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -866,31 +866,45 @@ peek_fifo (select_record *s, bool from_select)
goto out;
}
- if (fh->hit_eof ())
- {
- select_printf ("read: %s, saw EOF", fh->get_name ());
- 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++)
- if (fh->is_connected (i))
+ if (fh->get_fc_handler (i).get_state () >= fc_connected)
{
- int n = pipe_data_available (s->fd, fh, fh->get_fc_handle (i),
- false);
- if (n > 0)
+ nconnected++;
+ switch (fh->get_fc_handler (i).pipe_state ())
{
- select_printf ("read: %s, ready for read: avail %d, client %d",
- fh->get_name (), n, i);
+ case FILE_PIPE_CONNECTED_STATE:
+ fh->get_fc_handler (i).get_state () = fc_connected;
+ break;
+ case FILE_PIPE_DISCONNECTED_STATE:
+ fh->get_fc_handler (i).get_state () = fc_disconnected;
+ nconnected--;
+ break;
+ case FILE_PIPE_CLOSING_STATE:
+ fh->get_fc_handler (i).get_state () = fc_closing;
+ break;
+ case FILE_PIPE_INPUT_AVAILABLE_STATE:
+ fh->get_fc_handler (i).get_state () = fc_input_avail;
+ select_printf ("read: %s, ready for read", fh->get_name ());
fh->fifo_client_unlock ();
gotone += s->read_ready = true;
goto out;
+ default:
+ fh->get_fc_handler (i).get_state () = fc_error;
+ nconnected--;
+ break;
}
}
+ fh->maybe_eof (!nconnected);
fh->fifo_client_unlock ();
+ if (fh->maybe_eof () && fh->hit_eof ())
+ {
+ select_printf ("read: %s, saw EOF", fh->get_name ());
+ gotone += s->read_ready = true;
+ if (s->except_selected)
+ gotone += s->except_ready = true;
+ }
}
out:
if (s->write_selected)