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]; WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
fifo_client_handler client[MAX_CLIENTS]; fifo_client_handler client[MAX_CLIENTS];
int nclients, nconnected; int nclients, nconnected;
af_unix_spinlock_t _fifo_client_lock;
bool __reg2 wait (HANDLE); bool __reg2 wait (HANDLE);
NTSTATUS npfs_handle (HANDLE &); NTSTATUS npfs_handle (HANDLE &);
HANDLE create_pipe_instance (bool); HANDLE create_pipe_instance (bool);
@ -1278,6 +1279,8 @@ public:
fhandler_fifo (); fhandler_fifo ();
PUNICODE_STRING get_pipe_name (); PUNICODE_STRING get_pipe_name ();
DWORD listen_client_thread (); 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); int open (int, mode_t);
off_t lseek (off_t offset, int whence); off_t lseek (off_t offset, int whence);
int close (); int close ();

View File

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