aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler.h13
-rw-r--r--winsup/cygwin/fhandler_fifo.cc237
2 files changed, 141 insertions, 109 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 65aab4d..bd44da5 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1324,10 +1324,17 @@ struct fifo_reader_id_t
class fifo_shmem_t
{
LONG _nreaders;
+ fifo_reader_id_t _owner;
+ af_unix_spinlock_t _owner_lock;
public:
int inc_nreaders () { return (int) InterlockedIncrement (&_nreaders); }
int dec_nreaders () { return (int) InterlockedDecrement (&_nreaders); }
+
+ fifo_reader_id_t get_owner () const { return _owner; }
+ void set_owner (fifo_reader_id_t fr_id) { _owner = fr_id; }
+ void owner_lock () { _owner_lock.lock (); }
+ void owner_unlock () { _owner_lock.unlock (); }
};
class fhandler_fifo: public fhandler_base
@@ -1356,7 +1363,7 @@ class fhandler_fifo: public fhandler_base
bool __reg2 wait (HANDLE);
static NTSTATUS npfs_handle (HANDLE &);
- HANDLE create_pipe_instance (bool);
+ HANDLE create_pipe_instance ();
NTSTATUS open_pipe (HANDLE&);
NTSTATUS wait_open_pipe (HANDLE&);
int add_client_handler ();
@@ -1384,6 +1391,10 @@ public:
void fifo_client_unlock () { _fifo_client_lock.unlock (); }
fifo_reader_id_t get_me () const { return me; }
+ fifo_reader_id_t get_owner () const { return shmem->get_owner (); }
+ void set_owner (fifo_reader_id_t fr_id) { shmem->set_owner (fr_id); }
+ void owner_lock () { shmem->owner_lock (); }
+ void owner_unlock () { shmem->owner_unlock (); }
int open (int, mode_t);
off_t lseek (off_t offset, int whence);
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 5676a2c..0b9b337 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -164,7 +164,7 @@ fhandler_fifo::npfs_handle (HANDLE &nph)
blocking mode so that we can easily wait for a connection. After
it is connected, it is put in nonblocking mode. */
HANDLE
-fhandler_fifo::create_pipe_instance (bool first)
+fhandler_fifo::create_pipe_instance ()
{
NTSTATUS status;
HANDLE npfsh;
@@ -187,14 +187,12 @@ fhandler_fifo::create_pipe_instance (bool first)
access = GENERIC_READ | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE;
sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
- hattr = openflags & O_CLOEXEC ? 0 : OBJ_INHERIT;
- if (first)
- hattr |= OBJ_CASE_INSENSITIVE;
+ hattr = (openflags & O_CLOEXEC ? 0 : OBJ_INHERIT) | OBJ_CASE_INSENSITIVE;
InitializeObjectAttributes (&attr, get_pipe_name (),
hattr, npfsh, NULL);
timeout.QuadPart = -500000;
status = NtCreateNamedPipeFile (&ph, access, &attr, &io, sharing,
- first ? FILE_CREATE : FILE_OPEN, 0,
+ FILE_OPEN_IF, 0,
FILE_PIPE_MESSAGE_TYPE
| FILE_PIPE_REJECT_REMOTE_CLIENTS,
FILE_PIPE_MESSAGE_MODE,
@@ -292,14 +290,13 @@ fhandler_fifo::add_client_handler ()
int ret = -1;
fifo_client_handler fc;
HANDLE ph = NULL;
- bool first = (nhandlers == 0);
if (nhandlers == MAX_CLIENTS)
{
set_errno (EMFILE);
goto out;
}
- ph = create_pipe_instance (first);
+ ph = create_pipe_instance ();
if (!ph)
goto out;
else
@@ -349,92 +346,120 @@ fhandler_fifo::fifo_reader_thread_func ()
while (1)
{
- /* Cleanup the fc_handler list. */
- fifo_client_lock ();
- int i = 0;
- while (i < nhandlers)
+ fifo_reader_id_t cur_owner;
+
+ owner_lock ();
+ cur_owner = get_owner ();
+ if (!cur_owner)
{
- if (fc_handler[i].state < fc_connected)
- delete_client_handler (i);
- else
- i++;
+ set_owner (me);
+ owner_unlock ();
+ continue;
+ }
+ else if (cur_owner != me)
+ {
+ owner_unlock ();
+ WaitForSingleObject (cancel_evt, INFINITE);
+ goto canceled;
}
+ else
+ {
+ /* I'm the owner */
+ fifo_client_lock ();
- /* Create a new client handler. */
- if (add_client_handler () < 0)
- api_fatal ("Can't add a client handler, %E");
+ /* Cleanup the fc_handler list. */
+ fifo_client_lock ();
+ int i = 0;
+ while (i < nhandlers)
+ {
+ if (fc_handler[i].state < fc_connected)
+ delete_client_handler (i);
+ else
+ i++;
+ }
- /* Listen for a writer to connect to the new client handler. */
- fifo_client_handler& fc = fc_handler[nhandlers - 1];
- fifo_client_unlock ();
- NTSTATUS status;
- IO_STATUS_BLOCK io;
- bool cancel = false;
+ /* Create a new client handler. */
+ if (add_client_handler () < 0)
+ api_fatal ("Can't add a client handler, %E");
- status = NtFsControlFile (fc.h, conn_evt, NULL, NULL, &io,
- FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
- if (status == STATUS_PENDING)
- {
- HANDLE w[2] = { conn_evt, cancel_evt };
- switch (WaitForMultipleObjects (2, w, false, INFINITE))
+ /* Listen for a writer to connect to the new client handler. */
+ fifo_client_handler& fc = fc_handler[nhandlers - 1];
+ fifo_client_unlock ();
+ owner_unlock ();
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ bool cancel = false;
+
+ status = NtFsControlFile (fc.h, conn_evt, NULL, NULL, &io,
+ FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
+ if (status == STATUS_PENDING)
{
- case WAIT_OBJECT_0:
- status = io.Status;
+ HANDLE w[2] = { conn_evt, cancel_evt };
+ switch (WaitForMultipleObjects (2, w, false, INFINITE))
+ {
+ case WAIT_OBJECT_0:
+ status = io.Status;
+ debug_printf ("NtFsControlFile STATUS_PENDING, then %y",
+ status);
+ break;
+ case WAIT_OBJECT_0 + 1:
+ status = STATUS_THREAD_IS_TERMINATING;
+ cancel = true;
+ break;
+ default:
+ api_fatal ("WFMO failed, %E");
+ }
+ }
+ else
+ debug_printf ("NtFsControlFile status %y, no STATUS_PENDING",
+ status);
+ HANDLE ph = NULL;
+ NTSTATUS status1;
+
+ fifo_client_lock ();
+ switch (status)
+ {
+ case STATUS_SUCCESS:
+ case STATUS_PIPE_CONNECTED:
+ record_connection (fc);
break;
- case WAIT_OBJECT_0 + 1:
- status = STATUS_THREAD_IS_TERMINATING;
- cancel = true;
+ case STATUS_PIPE_CLOSING:
+ record_connection (fc, fc_closing);
+ break;
+ case STATUS_THREAD_IS_TERMINATING:
+ /* Try to connect a bogus client. Otherwise fc is still
+ listening, and the next connection might not get recorded. */
+ status1 = open_pipe (ph);
+ WaitForSingleObject (conn_evt, INFINITE);
+ if (NT_SUCCESS (status1))
+ /* Bogus cilent connected. */
+ delete_client_handler (nhandlers - 1);
+ else
+ /* Did a real client connect? */
+ switch (io.Status)
+ {
+ case STATUS_SUCCESS:
+ case STATUS_PIPE_CONNECTED:
+ record_connection (fc);
+ break;
+ case STATUS_PIPE_CLOSING:
+ 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:
- api_fatal ("WFMO failed, %E");
+ break;
}
+ fifo_client_unlock ();
+ if (ph)
+ NtClose (ph);
+ if (cancel)
+ goto canceled;
}
- HANDLE ph = NULL;
- NTSTATUS status1;
-
- fifo_client_lock ();
- switch (status)
- {
- case STATUS_SUCCESS:
- case STATUS_PIPE_CONNECTED:
- record_connection (fc);
- break;
- case STATUS_PIPE_CLOSING:
- record_connection (fc, fc_closing);
- break;
- case STATUS_THREAD_IS_TERMINATING:
- /* Try to connect a bogus client. Otherwise fc is still
- listening, and the next connection might not get recorded. */
- status1 = open_pipe (ph);
- WaitForSingleObject (conn_evt, INFINITE);
- if (NT_SUCCESS (status1))
- /* Bogus cilent connected. */
- delete_client_handler (nhandlers - 1);
- else
- /* Did a real client connect? */
- switch (io.Status)
- {
- case STATUS_SUCCESS:
- case STATUS_PIPE_CONNECTED:
- record_connection (fc);
- break;
- case STATUS_PIPE_CLOSING:
- 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:
- break;
- }
- fifo_client_unlock ();
- if (ph)
- NtClose (ph);
- if (cancel)
- goto canceled;
}
canceled:
if (conn_evt)
@@ -580,6 +605,15 @@ fhandler_fifo::open (int flags, mode_t)
me.winpid = GetCurrentProcessId ();
me.fh = this;
new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
+ /* Wait until there's an owner. */
+ owner_lock ();
+ while (!get_owner ())
+ {
+ owner_unlock ();
+ yield ();
+ owner_lock ();
+ }
+ owner_unlock ();
/* If we're a duplexer, we need a handle for writing. */
if (duplexer)
@@ -1014,6 +1048,10 @@ fhandler_fifo::close ()
if (dec_nreaders () == 0)
ResetEvent (read_ready);
cancel_reader_thread ();
+ owner_lock ();
+ if (get_owner () == me)
+ set_owner (null_fr_id);
+ owner_unlock ();
if (cancel_evt)
NtClose (cancel_evt);
if (thr_sync_evt)
@@ -1056,7 +1094,6 @@ fhandler_fifo::fcntl (int cmd, intptr_t arg)
int
fhandler_fifo::dup (fhandler_base *child, int flags)
{
- int i = 0;
fhandler_fifo *fhf = NULL;
if (get_flags () & O_PATH)
@@ -1092,6 +1129,9 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
/* Make sure the child starts unlocked. */
fhf->fifo_client_unlock ();
+ /* Clear fc_handler list; the child never starts as owner. */
+ fhf->nhandlers = 0;
+
if (!DuplicateHandle (GetCurrentProcess (), shmem_handle,
GetCurrentProcess (), &fhf->shmem_handle,
0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
@@ -1101,25 +1141,8 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
}
if (fhf->reopen_shmem () < 0)
goto err_close_shmem_handle;
- fifo_client_lock ();
- for (i = 0; i < nhandlers; i++)
- {
- if (!DuplicateHandle (GetCurrentProcess (), fc_handler[i].h,
- GetCurrentProcess (), &fhf->fc_handler[i].h,
- 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
- {
- __seterrno ();
- break;
- }
- }
- if (i < nhandlers)
- {
- fifo_client_unlock ();
- goto err_close_handlers;
- }
- fifo_client_unlock ();
if (!(fhf->cancel_evt = create_event ()))
- goto err_close_handlers;
+ goto err_close_shmem;
if (!(fhf->thr_sync_evt = create_event ()))
goto err_close_cancel_evt;
inc_nreaders ();
@@ -1129,9 +1152,7 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
return 0;
err_close_cancel_evt:
NtClose (fhf->cancel_evt);
-err_close_handlers:
- for (int j = 0; j < i; j++)
- fhf->fc_handler[j].close ();
+err_close_shmem:
NtUnmapViewOfSection (GetCurrentProcess (), fhf->shmem);
err_close_shmem_handle:
NtClose (fhf->shmem_handle);
@@ -1160,10 +1181,10 @@ fhandler_fifo::fixup_after_fork (HANDLE parent)
fork_fixup (parent, shmem_handle, "shmem_handle");
if (reopen_shmem () < 0)
api_fatal ("Can't reopen shared memory during fork, %E");
- fifo_client_lock ();
- for (int i = 0; i < nhandlers; i++)
- fork_fixup (parent, fc_handler[i].h, "fc_handler[].h");
- fifo_client_unlock ();
+ if (close_on_exec ())
+ /* Prevent a later attempt to close the non-inherited
+ pipe-instance handles copied from the parent. */
+ nhandlers = 0;
if (!(cancel_evt = create_event ()))
api_fatal ("Can't create reader thread cancel event during fork, %E");
if (!(thr_sync_evt = create_event ()))