From c75e077f9953e3ecc6ba371d7ef95e14883a68ba Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Fri, 22 Mar 2019 19:30:38 +0000 Subject: [PATCH] Cygwin: FIFO: add a spinlock Don't let listen_client_thread and raw_read access the client list simultaneously. --- winsup/cygwin/fhandler.h | 3 +++ winsup/cygwin/fhandler_fifo.cc | 34 +++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index e7c4af6a1..997dc0b6d 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -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 (); diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc index e91e88050..b0016ee90 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -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);