Cygwin: FIFO: simplify the listen_client_thread code

Always return 0; no one is doing anything with the return value
anyway.

Remove the return value from stop_listen_client.

Make the connection event auto-reset, so that we don't have to reset
it later.

Simplify the process of connecting a bogus client when thread
termination is signaled.

Make some failures fatal.

Remove the unnecessary extra check for thread termination near the end
of listen_client_thread.
This commit is contained in:
Ken Brown 2020-04-29 18:53:05 -04:00
parent 32dbc3d215
commit 9b2afd78ce
2 changed files with 47 additions and 74 deletions

View File

@ -1319,7 +1319,7 @@ class fhandler_fifo: public fhandler_base
int add_client_handler (); int add_client_handler ();
void delete_client_handler (int); void delete_client_handler (int);
bool listen_client (); bool listen_client ();
int stop_listen_client (); void stop_listen_client ();
int check_listen_client_thread (); int check_listen_client_thread ();
void record_connection (fifo_client_handler&, void record_connection (fifo_client_handler&,
fifo_client_connect_state = fc_connected); fifo_client_connect_state = fc_connected);
@ -1345,7 +1345,7 @@ public:
ssize_t __reg3 raw_write (const void *ptr, size_t ulen); ssize_t __reg3 raw_write (const void *ptr, size_t ulen);
bool arm (HANDLE h); bool arm (HANDLE h);
bool need_fixup_before () const { return reader; } bool need_fixup_before () const { return reader; }
int fixup_before_fork_exec (DWORD) { return stop_listen_client (); } int fixup_before_fork_exec (DWORD) { stop_listen_client (); return 0; }
void init_fixup_before (); void init_fixup_before ();
void fixup_after_fork (HANDLE); void fixup_after_fork (HANDLE);
void fixup_after_exec (); void fixup_after_exec ();

View File

@ -324,11 +324,10 @@ fhandler_fifo::record_connection (fifo_client_handler& fc,
DWORD DWORD
fhandler_fifo::listen_client_thread () fhandler_fifo::listen_client_thread ()
{ {
DWORD ret = -1; HANDLE conn_evt;
HANDLE evt;
if (!(evt = create_event ())) if (!(conn_evt = CreateEvent (NULL, false, false, NULL)))
goto out; api_fatal ("Can't create connection event, %E");
while (1) while (1)
{ {
@ -346,7 +345,7 @@ 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; api_fatal ("Can't add a client handler, %E");
/* Allow a writer to open. */ /* Allow a writer to open. */
if (!arm (read_ready)) if (!arm (read_ready))
@ -359,12 +358,13 @@ fhandler_fifo::listen_client_thread ()
fifo_client_handler& fc = fc_handler[nhandlers - 1]; fifo_client_handler& fc = fc_handler[nhandlers - 1];
NTSTATUS status; NTSTATUS status;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
bool cancel = false;
status = NtFsControlFile (fc.h, evt, NULL, NULL, &io, status = NtFsControlFile (fc.h, conn_evt, NULL, NULL, &io,
FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0); FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
if (status == STATUS_PENDING) if (status == STATUS_PENDING)
{ {
HANDLE w[2] = { evt, lct_termination_evt }; HANDLE w[2] = { conn_evt, lct_termination_evt };
DWORD waitret = WaitForMultipleObjects (2, w, false, INFINITE); DWORD waitret = WaitForMultipleObjects (2, w, false, INFINITE);
switch (waitret) switch (waitret)
{ {
@ -372,83 +372,65 @@ fhandler_fifo::listen_client_thread ()
status = io.Status; status = io.Status;
break; break;
case WAIT_OBJECT_0 + 1: case WAIT_OBJECT_0 + 1:
ret = 0;
status = STATUS_THREAD_IS_TERMINATING; status = STATUS_THREAD_IS_TERMINATING;
cancel = true;
break; break;
default: default:
__seterrno (); api_fatal ("WFMO failed, %E");
debug_printf ("WaitForMultipleObjects failed, %E");
status = STATUS_THREAD_IS_TERMINATING;
break;
} }
} }
HANDLE ph = NULL; HANDLE ph = NULL;
int ps = -1; NTSTATUS status1;
fifo_client_lock (); fifo_client_lock ();
switch (status) switch (status)
{ {
case STATUS_SUCCESS: case STATUS_SUCCESS:
case STATUS_PIPE_CONNECTED: case STATUS_PIPE_CONNECTED:
record_connection (fc); record_connection (fc);
ResetEvent (evt);
break; break;
case STATUS_PIPE_CLOSING: case STATUS_PIPE_CLOSING:
record_connection (fc, fc_closing); record_connection (fc, fc_closing);
ResetEvent (evt);
break; break;
case STATUS_THREAD_IS_TERMINATING: case STATUS_THREAD_IS_TERMINATING:
/* Force NtFsControlFile to complete. Otherwise the next /* Try to connect a bogus client. Otherwise fc is still
writer to connect might not be recorded in the client listening, and the next connection might not get recorded. */
handler list. */ status1 = open_pipe (ph);
status = open_pipe (ph); WaitForSingleObject (conn_evt, INFINITE);
if (NT_SUCCESS (status) if (NT_SUCCESS (status1))
&& (NT_SUCCESS (io.Status) || io.Status == STATUS_PIPE_CONNECTED)) /* Bogus cilent connected. */
{ delete_client_handler (nhandlers - 1);
debug_printf ("successfully connected bogus client");
delete_client_handler (nhandlers - 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
{ /* Did a real client connect? */
debug_printf ("failed to terminate NtFsControlFile cleanly"); switch (io.Status)
delete_client_handler (nhandlers - 1); {
ret = -1; case STATUS_SUCCESS:
} case STATUS_PIPE_CONNECTED:
if (ph) record_connection (fc);
NtClose (ph); break;
fifo_client_unlock (); case STATUS_PIPE_CLOSING:
goto out; record_connection (fc, fc_closing);
break;
default:
debug_printf ("NtFsControlFile status %y after failing to connect bogus client or real client", io.Status);
fc.state = fc_unknown;
break;
}
break;
default: default:
debug_printf ("NtFsControlFile status %y", status); break;
__seterrno_from_nt_status (status);
delete_client_handler (nhandlers - 1);
fifo_client_unlock ();
goto out;
} }
fifo_client_unlock (); fifo_client_unlock ();
/* Check for thread termination in case WaitForMultipleObjects if (ph)
didn't get called above. */ NtClose (ph);
if (IsEventSignalled (lct_termination_evt)) if (cancel)
{ goto out;
ret = 0;
goto out;
}
} }
out: out:
if (evt) if (conn_evt)
NtClose (evt); NtClose (conn_evt);
ResetEvent (read_ready); ResetEvent (read_ready);
if (ret < 0) return 0;
debug_printf ("exiting with error, %E");
else
debug_printf ("exiting without error");
return ret;
} }
int int
@ -945,10 +927,9 @@ fifo_client_handler::pipe_state ()
return fpli.NamedPipeState; return fpli.NamedPipeState;
} }
int void
fhandler_fifo::stop_listen_client () fhandler_fifo::stop_listen_client ()
{ {
int ret = 0;
HANDLE thr, evt; HANDLE thr, evt;
thr = InterlockedExchangePointer (&listen_client_thr, NULL); thr = InterlockedExchangePointer (&listen_client_thr, NULL);
@ -957,19 +938,11 @@ fhandler_fifo::stop_listen_client ()
if (lct_termination_evt) if (lct_termination_evt)
SetEvent (lct_termination_evt); SetEvent (lct_termination_evt);
WaitForSingleObject (thr, INFINITE); WaitForSingleObject (thr, INFINITE);
DWORD err;
GetExitCodeThread (thr, &err);
if (err)
{
ret = -1;
debug_printf ("listen_client_thread exited with error");
}
NtClose (thr); NtClose (thr);
} }
evt = InterlockedExchangePointer (&lct_termination_evt, NULL); evt = InterlockedExchangePointer (&lct_termination_evt, NULL);
if (evt) if (evt)
NtClose (evt); NtClose (evt);
return ret;
} }
int int
@ -978,7 +951,7 @@ fhandler_fifo::close ()
/* Avoid deadlock with lct in case this is called from a signal /* Avoid deadlock with lct in case this is called from a signal
handler or another thread. */ handler or another thread. */
fifo_client_unlock (); fifo_client_unlock ();
int ret = stop_listen_client (); stop_listen_client ();
if (read_ready) if (read_ready)
NtClose (read_ready); NtClose (read_ready);
if (write_ready) if (write_ready)
@ -987,7 +960,7 @@ fhandler_fifo::close ()
for (int i = 0; i < nhandlers; i++) for (int i = 0; i < nhandlers; i++)
fc_handler[i].close (); fc_handler[i].close ();
fifo_client_unlock (); fifo_client_unlock ();
return fhandler_base::close () || ret; return fhandler_base::close ();
} }
/* If we have a write handle (i.e., we're a duplexer or a writer), /* If we have a write handle (i.e., we're a duplexer or a writer),