[newlib-cygwin] Cygwin: FIFO: improve termination of the listen_client thread
Ken Brown
kbrown@sourceware.org
Sun Jun 23 17:09:00 GMT 2019
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=5bd5e3dc6c576224bbff65014af66d1fbe879751
commit 5bd5e3dc6c576224bbff65014af66d1fbe879751
Author: Ken Brown <kbrown@cornell.edu>
Date: Fri Jun 21 18:49:11 2019 -0400
Cygwin: FIFO: improve termination of the listen_client thread
Add a method fifo_client_handler::pipe_state that queries Windows for
the state of a pipe instance. Use this to help terminate the
listen_client thread cleanly.
If the last client handler is useless, delete it instead of declaring
it invalid.
Diff:
---
winsup/cygwin/fhandler.h | 9 +++++++
winsup/cygwin/fhandler_fifo.cc | 61 +++++++++++++++++++++++++++++++-----------
2 files changed, 55 insertions(+), 15 deletions(-)
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 156baed..293a3e0 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1244,6 +1244,11 @@ enum fifo_client_connect_state
fc_invalid
};
+enum
+{
+ FILE_PIPE_INPUT_AVAILABLE_STATE = 5
+};
+
struct fifo_client_handler
{
fhandler_base *fh;
@@ -1251,6 +1256,10 @@ struct fifo_client_handler
HANDLE connect_evt;
fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL) {}
int close ();
+/* 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. */
+ int pipe_state ();
};
class fhandler_fifo: public fhandler_base
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 8afa397..b96c4d5 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -377,6 +377,7 @@ fhandler_fifo::listen_client_thread ()
}
}
HANDLE ph = NULL;
+ int ps = -1;
fifo_client_lock ();
switch (status)
{
@@ -385,29 +386,38 @@ fhandler_fifo::listen_client_thread ()
record_connection (fc);
break;
case STATUS_THREAD_IS_TERMINATING:
- /* Try to cancel the pending listen. Otherwise the first
- writer to connect after the thread is restarted will be
- invisible.
-
- FIXME: Is there a direct way to do this? We do it by
- opening and closing a write handle to the client side. */
- open_pipe (ph);
- /* We don't care about the return value of open_pipe. Even
- if the latter failed, a writer might have connected. */
- if (WaitForSingleObject (fc.connect_evt, 0) == WAIT_OBJECT_0
+ /* Force NtFsControlFile to complete. Otherwise the next
+ writer to connect might not be recorded in the client
+ handler list. */
+ status = open_pipe (ph);
+ if (NT_SUCCESS (status)
&& (NT_SUCCESS (io.Status) || io.Status == STATUS_PIPE_CONNECTED))
- record_connection (fc);
+ {
+ debug_printf ("successfully connected bogus client");
+ if (delete_client_handler (nhandlers - 1) < 0)
+ ret = -1;
+ }
+ else if ((ps = fc.pipe_state ()) == FILE_PIPE_CONNECTED_STATE
+ || ps == FILE_PIPE_INPUT_AVAILABLE_STATE)
+ {
+ /* A connection was made under our nose. */
+ debug_printf ("recording connection before terminating");
+ record_connection (fc);
+ }
else
- fc.state = fc_invalid;
- /* By closing ph we ensure that if fc connected to ph, fc
- will be declared invalid on the next read attempt. */
+ {
+ debug_printf ("failed to terminate NtFsControlFile cleanly");
+ delete_client_handler (nhandlers - 1);
+ ret = -1;
+ }
if (ph)
CloseHandle (ph);
fifo_client_unlock ();
goto out;
default:
+ debug_printf ("NtFsControlFile status %y", status);
__seterrno_from_nt_status (status);
- fc.state = fc_invalid;
+ delete_client_handler (nhandlers - 1);
fifo_client_unlock ();
goto out;
}
@@ -899,6 +909,27 @@ fifo_client_handler::close ()
}
int
+fifo_client_handler::pipe_state ()
+{
+ IO_STATUS_BLOCK io;
+ FILE_PIPE_LOCAL_INFORMATION fpli;
+ NTSTATUS status;
+
+ status = NtQueryInformationFile (fh->get_handle (), &io, &fpli,
+ sizeof (fpli), FilePipeLocalInformation);
+ if (!NT_SUCCESS (status))
+ {
+ debug_printf ("NtQueryInformationFile status %y", status);
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ else if (fpli.ReadDataAvailable > 0)
+ return FILE_PIPE_INPUT_AVAILABLE_STATE;
+ else
+ return fpli.NamedPipeState;
+}
+
+int
fhandler_fifo::stop_listen_client ()
{
int ret = 0;
More information about the Cygwin-cvs
mailing list