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;