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.
This commit is contained in:
parent
d1b36ea949
commit
5bd5e3dc6c
|
@ -1244,6 +1244,11 @@ enum fifo_client_connect_state
|
||||||
fc_invalid
|
fc_invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FILE_PIPE_INPUT_AVAILABLE_STATE = 5
|
||||||
|
};
|
||||||
|
|
||||||
struct fifo_client_handler
|
struct fifo_client_handler
|
||||||
{
|
{
|
||||||
fhandler_base *fh;
|
fhandler_base *fh;
|
||||||
|
@ -1251,6 +1256,10 @@ struct fifo_client_handler
|
||||||
HANDLE connect_evt;
|
HANDLE connect_evt;
|
||||||
fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL) {}
|
fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL) {}
|
||||||
int close ();
|
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
|
class fhandler_fifo: public fhandler_base
|
||||||
|
|
|
@ -377,6 +377,7 @@ fhandler_fifo::listen_client_thread ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HANDLE ph = NULL;
|
HANDLE ph = NULL;
|
||||||
|
int ps = -1;
|
||||||
fifo_client_lock ();
|
fifo_client_lock ();
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
|
@ -385,29 +386,38 @@ fhandler_fifo::listen_client_thread ()
|
||||||
record_connection (fc);
|
record_connection (fc);
|
||||||
break;
|
break;
|
||||||
case STATUS_THREAD_IS_TERMINATING:
|
case STATUS_THREAD_IS_TERMINATING:
|
||||||
/* Try to cancel the pending listen. Otherwise the first
|
/* Force NtFsControlFile to complete. Otherwise the next
|
||||||
writer to connect after the thread is restarted will be
|
writer to connect might not be recorded in the client
|
||||||
invisible.
|
handler list. */
|
||||||
|
status = open_pipe (ph);
|
||||||
FIXME: Is there a direct way to do this? We do it by
|
if (NT_SUCCESS (status)
|
||||||
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
|
|
||||||
&& (NT_SUCCESS (io.Status) || io.Status == STATUS_PIPE_CONNECTED))
|
&& (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
|
else
|
||||||
fc.state = fc_invalid;
|
{
|
||||||
/* By closing ph we ensure that if fc connected to ph, fc
|
debug_printf ("failed to terminate NtFsControlFile cleanly");
|
||||||
will be declared invalid on the next read attempt. */
|
delete_client_handler (nhandlers - 1);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
if (ph)
|
if (ph)
|
||||||
CloseHandle (ph);
|
CloseHandle (ph);
|
||||||
fifo_client_unlock ();
|
fifo_client_unlock ();
|
||||||
goto out;
|
goto out;
|
||||||
default:
|
default:
|
||||||
|
debug_printf ("NtFsControlFile status %y", status);
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
fc.state = fc_invalid;
|
delete_client_handler (nhandlers - 1);
|
||||||
fifo_client_unlock ();
|
fifo_client_unlock ();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -898,6 +908,27 @@ fifo_client_handler::close ()
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
int
|
||||||
fhandler_fifo::stop_listen_client ()
|
fhandler_fifo::stop_listen_client ()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue