Cygwin: FIFO: don't leave a pending listen request
On exit from the listen_client thread, make sure there's no pending FSCTL_PIPE_LISTEN request. Otherwise we might get a client connection after restarting the thread, and we won't have a handle for communicating with that client. Remove the retry loop in the case of STATUS_PIPE_LISTENING; that case shouldn't occur. Remove the now-unused fc_connecting value from fifo_client_connect_state.
This commit is contained in:
parent
816c6da53a
commit
c12053a793
|
@ -1240,7 +1240,6 @@ public:
|
||||||
enum fifo_client_connect_state
|
enum fifo_client_connect_state
|
||||||
{
|
{
|
||||||
fc_unknown,
|
fc_unknown,
|
||||||
fc_connecting,
|
|
||||||
fc_connected,
|
fc_connected,
|
||||||
fc_invalid
|
fc_invalid
|
||||||
};
|
};
|
||||||
|
|
|
@ -272,10 +272,7 @@ listen_client_func (LPVOID param)
|
||||||
return fh->listen_client_thread ();
|
return fh->listen_client_thread ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start a thread that listens for client connections. Whenever a new
|
/* Start a thread that listens for client connections. */
|
||||||
client connects, it creates a new pipe_instance if necessary.
|
|
||||||
(There may already be an available instance if a client has
|
|
||||||
disconnected.) */
|
|
||||||
bool
|
bool
|
||||||
fhandler_fifo::listen_client ()
|
fhandler_fifo::listen_client ()
|
||||||
{
|
{
|
||||||
|
@ -331,70 +328,80 @@ fhandler_fifo::listen_client_thread ()
|
||||||
|
|
||||||
/* Create a new client handler. */
|
/* Create a new client handler. */
|
||||||
if (add_client_handler () < 0)
|
if (add_client_handler () < 0)
|
||||||
goto out;
|
{
|
||||||
|
fifo_client_unlock ();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allow a writer to open. */
|
/* Allow a writer to open. */
|
||||||
if (!arm (read_ready))
|
if (!arm (read_ready))
|
||||||
{
|
{
|
||||||
|
fifo_client_unlock ();
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
fifo_client_unlock ();
|
|
||||||
|
|
||||||
/* Listen for a writer to connect to the new client handler. */
|
/* Listen for a writer to connect to the new client handler. */
|
||||||
fifo_client_handler& fc = fc_handler[nhandlers - 1];
|
fifo_client_handler& fc = fc_handler[nhandlers - 1];
|
||||||
do
|
NTSTATUS status;
|
||||||
{
|
IO_STATUS_BLOCK io;
|
||||||
NTSTATUS status;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
|
|
||||||
status = NtFsControlFile (fc.fh->get_handle (), fc.connect_evt,
|
status = NtFsControlFile (fc.fh->get_handle (), fc.connect_evt,
|
||||||
NULL, NULL, &io, FSCTL_PIPE_LISTEN,
|
NULL, NULL, &io, FSCTL_PIPE_LISTEN,
|
||||||
NULL, 0, NULL, 0);
|
NULL, 0, NULL, 0);
|
||||||
if (status == STATUS_PENDING)
|
fifo_client_unlock ();
|
||||||
|
if (status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
HANDLE w[2] = { fc.connect_evt, lct_termination_evt };
|
||||||
|
DWORD waitret = WaitForMultipleObjects (2, w, false, INFINITE);
|
||||||
|
switch (waitret)
|
||||||
{
|
{
|
||||||
HANDLE w[2] = { fc.connect_evt, lct_termination_evt };
|
case WAIT_OBJECT_0:
|
||||||
DWORD waitret = WaitForMultipleObjects (2, w, false, INFINITE);
|
status = io.Status;
|
||||||
switch (waitret)
|
|
||||||
{
|
|
||||||
case WAIT_OBJECT_0:
|
|
||||||
status = io.Status;
|
|
||||||
break;
|
|
||||||
case WAIT_OBJECT_0 + 1:
|
|
||||||
ret = 0;
|
|
||||||
status = STATUS_THREAD_IS_TERMINATING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
__seterrno ();
|
|
||||||
debug_printf ("WaitForMultipleObjects failed, %E");
|
|
||||||
status = STATUS_THREAD_IS_TERMINATING;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case STATUS_SUCCESS:
|
|
||||||
case STATUS_PIPE_CONNECTED:
|
|
||||||
record_connection (fc);
|
|
||||||
break;
|
break;
|
||||||
case STATUS_PIPE_LISTENING:
|
case WAIT_OBJECT_0 + 1:
|
||||||
/* Retry. */
|
ret = 0;
|
||||||
fc.state = fc_connecting;
|
status = STATUS_THREAD_IS_TERMINATING;
|
||||||
ResetEvent (fc.connect_evt);
|
|
||||||
break;
|
break;
|
||||||
case STATUS_THREAD_IS_TERMINATING:
|
|
||||||
fifo_client_lock ();
|
|
||||||
delete_client_handler (nhandlers - 1);
|
|
||||||
fifo_client_unlock ();
|
|
||||||
goto out;
|
|
||||||
default:
|
default:
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno ();
|
||||||
fifo_client_lock ();
|
debug_printf ("WaitForMultipleObjects failed, %E");
|
||||||
delete_client_handler (nhandlers - 1);
|
status = STATUS_THREAD_IS_TERMINATING;
|
||||||
fifo_client_unlock ();
|
break;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
} while (fc.state == fc_connecting);
|
}
|
||||||
|
HANDLE ph = NULL;
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case STATUS_SUCCESS:
|
||||||
|
case STATUS_PIPE_CONNECTED:
|
||||||
|
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
|
||||||
|
&& (NT_SUCCESS (io.Status) || io.Status == STATUS_PIPE_CONNECTED))
|
||||||
|
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. */
|
||||||
|
if (ph)
|
||||||
|
CloseHandle (ph);
|
||||||
|
goto out;
|
||||||
|
default:
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
fc.state = fc_invalid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
/* Check for thread termination in case WaitForMultipleObjects
|
/* Check for thread termination in case WaitForMultipleObjects
|
||||||
didn't get called above. */
|
didn't get called above. */
|
||||||
if (IsEventSignalled (lct_termination_evt))
|
if (IsEventSignalled (lct_termination_evt))
|
||||||
|
|
Loading…
Reference in New Issue