diff options
author | Ken Brown <kbrown@cornell.edu> | 2019-06-21 18:49:11 -0400 |
---|---|---|
committer | Ken Brown <kbrown@cornell.edu> | 2019-06-23 10:16:33 -0400 |
commit | 5bd5e3dc6c576224bbff65014af66d1fbe879751 (patch) | |
tree | bf30b755b1be1cc025937eaf936efbe31bd84309 | |
parent | d1b36ea949e275c803787523b0b04657895638fc (diff) | |
download | cygnal-5bd5e3dc6c576224bbff65014af66d1fbe879751.tar.gz cygnal-5bd5e3dc6c576224bbff65014af66d1fbe879751.tar.bz2 cygnal-5bd5e3dc6c576224bbff65014af66d1fbe879751.zip |
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.
-rw-r--r-- | winsup/cygwin/fhandler.h | 9 | ||||
-rw-r--r-- | 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 156baed9c..293a3e06e 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 8afa39747..b96c4d5e2 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; |