Cygwin: FIFO: add a spinlock

Don't let listen_client_thread and raw_read access the client list
simultaneously.
This commit is contained in:
Ken Brown 2019-03-22 19:30:38 +00:00 committed by Corinna Vinschen
parent 48d4cce3be
commit c75e077f99
2 changed files with 28 additions and 9 deletions

View File

@ -1267,6 +1267,7 @@ class fhandler_fifo: public fhandler_base
WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
fifo_client_handler client[MAX_CLIENTS];
int nclients, nconnected;
af_unix_spinlock_t _fifo_client_lock;
bool __reg2 wait (HANDLE);
NTSTATUS npfs_handle (HANDLE &);
HANDLE create_pipe_instance (bool);
@ -1278,6 +1279,8 @@ public:
fhandler_fifo ();
PUNICODE_STRING get_pipe_name ();
DWORD listen_client_thread ();
void fifo_client_lock () { _fifo_client_lock.lock (); }
void fifo_client_unlock () { _fifo_client_lock.unlock (); }
int open (int, mode_t);
off_t lseek (off_t offset, int whence);
int close ();

View File

@ -349,13 +349,17 @@ fhandler_fifo::listen_client_thread ()
int i;
DWORD wait_ret;
fifo_client_lock ();
found = false;
for (i = 0; i < nclients; i++)
switch (client[i].state)
{
case fc_invalid:
if (disconnect_and_reconnect (i) < 0)
goto errout;
{
fifo_client_unlock ();
goto errout;
}
/* Fall through. */
case fc_connected:
w[i] = client[i].dummy_evt;
@ -369,13 +373,15 @@ fhandler_fifo::listen_client_thread ()
break;
}
w[nclients] = lct_termination_evt;
int res = 0;
if (!found)
{
if (add_client () < 0)
goto errout;
else
continue;
}
res = add_client ();
fifo_client_unlock ();
if (res < 0)
goto errout;
else if (!found)
continue;
if (!arm (read_ready))
{
__seterrno ();
@ -391,9 +397,11 @@ fhandler_fifo::listen_client_thread ()
return 0;
else
{
fifo_client_lock ();
client[i].state = fc_connected;
nconnected++;
set_pipe_non_blocking (client[i].fh->get_handle (), true);
fifo_client_unlock ();
yield ();
}
}
@ -664,6 +672,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
}
/* Poll the connected clients for input. */
fifo_client_lock ();
for (int i = 0; i < nclients; i++)
if (client[i].state == fc_connected)
{
@ -671,15 +680,22 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
client[i].fh->fhandler_base::raw_read (in_ptr, len);
ssize_t nread = (ssize_t) len;
if (nread > 0)
return;
{
fifo_client_unlock ();
return;
}
else if (nread < 0 && GetLastError () != ERROR_NO_DATA)
goto errout;
{
fifo_client_unlock ();
goto errout;
}
else if (nread == 0) /* Client has disconnected. */
{
client[i].state = fc_invalid;
nconnected--;
}
}
fifo_client_unlock ();
if (is_nonblocking ())
{
set_errno (EAGAIN);