summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler.h3
-rw-r--r--winsup/cygwin/fhandler_fifo.cc55
2 files changed, 50 insertions, 8 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index b5bfdd0b3..221c856e6 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1298,7 +1298,8 @@ struct fifo_client_handler
{
HANDLE h;
fifo_client_connect_state state;
- fifo_client_handler () : h (NULL), state (fc_unknown) {}
+ bool last_read; /* true if our last successful read was from this client. */
+ fifo_client_handler () : h (NULL), state (fc_unknown), last_read (false) {}
void close () { NtClose (h); }
fifo_client_connect_state set_state ();
};
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 3685cc0c2..afe21a468 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -404,6 +404,7 @@ fhandler_fifo::update_my_handlers ()
goto out;
}
fc.state = shared_fc_handler[i].state;
+ fc.last_read = shared_fc_handler[i].last_read;
}
out:
set_prev_owner (null_fr_id);
@@ -1200,15 +1201,56 @@ 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 ();
- /* Poll the connected clients for input. */
- int nconnected = 0;
+ /* 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
+ interleaving of writes from different clients. */
fifo_client_lock ();
+ /* First pass. */
+ int j;
+ for (j = 0; j < nhandlers; j++)
+ if (fc_handler[j].last_read)
+ break;
+ if (j < nhandlers && fc_handler[j].state >= fc_closing)
+ {
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+
+ status = NtReadFile (fc_handler[j].h, NULL, NULL, NULL,
+ &io, in_ptr, len, NULL, NULL);
+ switch (status)
+ {
+ case STATUS_SUCCESS:
+ case STATUS_BUFFER_OVERFLOW:
+ /* io.Information is supposedly valid in latter case. */
+ if (io.Information > 0)
+ {
+ len = io.Information;
+ fifo_client_unlock ();
+ reading_unlock ();
+ return;
+ }
+ break;
+ case STATUS_PIPE_EMPTY:
+ break;
+ case STATUS_PIPE_BROKEN:
+ fc_handler[j].state = fc_disconnected;
+ break;
+ default:
+ debug_printf ("NtReadFile status %y", status);
+ fc_handler[j].state = fc_error;
+ break;
+ }
+ fc_handler[j].last_read = false;
+ }
+
+ /* Second pass. */
+ int nconnected = 0;
for (int i = 0; i < nhandlers; i++)
if (fc_handler[i].state >= fc_closing)
{
NTSTATUS status;
IO_STATUS_BLOCK io;
- size_t nbytes = 0;
nconnected++;
status = NtReadFile (fc_handler[i].h, NULL, NULL, NULL,
@@ -1217,11 +1259,10 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
- /* io.Information is supposedly valid. */
- nbytes = io.Information;
- if (nbytes > 0)
+ if (io.Information > 0)
{
- len = nbytes;
+ len = io.Information;
+ fc_handler[i].last_read = true;
fifo_client_unlock ();
reading_unlock ();
return;