From 70e60d969c4006ddce3a4e16549d0271158ba8f4 Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Thu, 17 Jan 2019 16:55:20 -0500 Subject: [PATCH FIFO, draft 4/4] Cygwin: fhandler_fifo: add a spinlock Don't let listen_client_thread and raw_read access the pipe_instance list simultaneously. --- winsup/cygwin/fhandler.h | 3 +++ winsup/cygwin/fhandler_fifo.cc | 27 +++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 311cf0958..a557375f5 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1249,6 +1249,7 @@ class fhandler_fifo: public fhandler_base_overlapped HANDLE lct_termination_evt; pipe_instance inst[MAX_INSTANCES]; int ninstances, nconnected; + af_unix_spinlock_t _pipe_inst_lock; bool __reg2 wait (HANDLE); char __reg2 *fifo_name (char *, const char *); int disconnect_and_reconnect (int); @@ -1258,6 +1259,8 @@ class fhandler_fifo: public fhandler_base_overlapped public: fhandler_fifo (); DWORD listen_client_thread (); + void pipe_inst_lock () { _pipe_inst_lock.lock (); } + void pipe_inst_unlock () { _pipe_inst_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 5bc64408b..452978202 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -213,8 +213,12 @@ fhandler_fifo::listen_client_thread () { while (1) { + pipe_inst_lock (); if (nconnected == ninstances && create_pipe_instance () < 0) - return -1; + { + pipe_inst_unlock (); + return -1; + } /* Wait for a client to connect. */ HANDLE w[MAX_INSTANCES + 1]; @@ -224,6 +228,7 @@ fhandler_fifo::listen_client_thread () w[i] = inst[i].connected ? inst[i].dummy_evt : inst[i].fh->get_overlapped ()->hEvent; w[ninstances] = lct_termination_evt; + pipe_inst_unlock (); if (!arm (read_ready)) goto errout; wait_ret = WaitForMultipleObjects (ninstances + 1, w, false, INFINITE); @@ -234,8 +239,11 @@ fhandler_fifo::listen_client_thread () return 0; else { + pipe_inst_lock (); inst[i].connected = true; nconnected++; + pipe_inst_unlock (); + yield (); } } errout: @@ -497,6 +505,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len) if (!check_listen_client_thread ()) goto errout; + pipe_inst_lock (); for (int i = 0; i < ninstances; i++) if (inst[i].connected) { @@ -508,12 +517,22 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len) inst[i].fh->set_nonblocking (was_nonblocking); nread = (ssize_t) len; if (nread > 0) - return; + { + pipe_inst_unlock (); + return; + } else if (nread < 0 && errno != EAGAIN) - goto errout; + { + pipe_inst_unlock (); + goto errout; + } else if (nread == 0 && disconnect_and_reconnect (i) < 0) - goto errout; + { + pipe_inst_unlock (); + goto errout; + } } + pipe_inst_unlock (); if (is_nonblocking ()) { set_errno (EAGAIN); -- 2.17.0