diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 1cd7d2b11..f8c1b52a4 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1359,6 +1359,10 @@ class fhandler_fifo: public fhandler_base HANDLE write_ready; /* A writer is open; OK for a reader to open. */ HANDLE writer_opening; /* A writer is opening; no EOF. */ + /* Handles to named events needed by all readers of a given FIFO. */ + HANDLE owner_needed_evt; /* The owner is closing. */ + HANDLE owner_found_evt; /* A new owner has taken over. */ + /* Handles to non-shared events needed for fifo_reader_threads. */ HANDLE cancel_evt; /* Signal thread to terminate. */ HANDLE thr_sync_evt; /* The thread has terminated. */ @@ -1405,6 +1409,16 @@ class fhandler_fifo: public fhandler_base fifo_reader_id_t get_prev_owner () const { return shmem->get_prev_owner (); } void set_prev_owner (fifo_reader_id_t fr_id) { shmem->set_prev_owner (fr_id); } + void owner_needed () + { + ResetEvent (owner_found_evt); + SetEvent (owner_needed_evt); + } + void owner_found () + { + ResetEvent (owner_needed_evt); + SetEvent (owner_found_evt); + } int get_shared_nhandlers () { return shmem->get_shared_nhandlers (); } void set_shared_nhandlers (int n) { shmem->set_shared_nhandlers (n); } diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc index 5ae7b1f9c..793adfae8 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -74,6 +74,7 @@ static NO_COPY fifo_reader_id_t null_fr_id = { .winpid = 0, .fh = NULL }; fhandler_fifo::fhandler_fifo (): fhandler_base (), read_ready (NULL), write_ready (NULL), writer_opening (NULL), + owner_needed_evt (NULL), owner_found_evt (NULL), cancel_evt (NULL), thr_sync_evt (NULL), _maybe_eof (false), fc_handler (NULL), shandlers (0), nhandlers (0), reader (false), writer (false), duplexer (false), @@ -464,14 +465,23 @@ fhandler_fifo::fifo_reader_thread_func () set_owner (me); if (update_my_handlers () < 0) api_fatal ("Can't update my handlers, %E"); + owner_found (); owner_unlock (); continue; } else if (cur_owner != me) { owner_unlock (); - WaitForSingleObject (cancel_evt, INFINITE); - goto canceled; + HANDLE w[2] = { owner_needed_evt, cancel_evt }; + switch (WaitForMultipleObjects (2, w, false, INFINITE)) + { + case WAIT_OBJECT_0: + continue; + case WAIT_OBJECT_0 + 1: + goto canceled; + default: + api_fatal ("WFMO failed, %E"); + } } else { @@ -797,8 +807,23 @@ fhandler_fifo::open (int flags, mode_t) if (create_shared_fc_handler () < 0) goto err_close_shmem; inc_nreaders (); + npbuf[0] = 'n'; + if (!(owner_needed_evt = CreateEvent (sa_buf, true, false, npbuf))) + { + debug_printf ("CreateEvent for %s failed, %E", npbuf); + __seterrno (); + goto err_dec_nreaders; + } + npbuf[0] = 'f'; + if (!(owner_found_evt = CreateEvent (sa_buf, true, false, npbuf))) + { + debug_printf ("CreateEvent for %s failed, %E", npbuf); + __seterrno (); + goto err_close_owner_needed_evt; + } + /* Make cancel and sync inheritable for exec. */ if (!(cancel_evt = create_event (true))) - goto err_dec_nreaders; + goto err_close_owner_found_evt; if (!(thr_sync_evt = create_event (true))) goto err_close_cancel_evt; me.winpid = GetCurrentProcessId (); @@ -918,6 +943,10 @@ err_close_reader: return 0; err_close_cancel_evt: NtClose (cancel_evt); +err_close_owner_found_evt: + NtClose (owner_found_evt); +err_close_owner_needed_evt: + NtClose (owner_needed_evt); err_dec_nreaders: if (dec_nreaders () == 0) ResetEvent (read_ready); @@ -1255,13 +1284,49 @@ fhandler_fifo::close () { if (reader) { - if (dec_nreaders () == 0) - ResetEvent (read_ready); + /* If we're the owner, try to find a new owner. */ + bool find_new_owner = false; + cancel_reader_thread (); owner_lock (); if (get_owner () == me) - set_owner (null_fr_id); + { + find_new_owner = true; + set_owner (null_fr_id); + set_prev_owner (me); + owner_needed (); + } owner_unlock (); + if (dec_nreaders () == 0) + ResetEvent (read_ready); + else if (find_new_owner && !IsEventSignalled (owner_found_evt)) + { + bool found = false; + do + if (dec_nreaders () >= 0) + { + /* There's still another reader open. */ + if (WaitForSingleObject (owner_found_evt, 1) == WAIT_OBJECT_0) + found = true; + else + { + owner_lock (); + if (get_owner ()) /* We missed owner_found_evt? */ + found = true; + else + owner_needed (); + owner_unlock (); + } + } + while (inc_nreaders () > 0 && !found); + } + close_all_handlers (); + if (fc_handler) + free (fc_handler); + if (owner_needed_evt) + NtClose (owner_needed_evt); + if (owner_found_evt) + NtClose (owner_found_evt); if (cancel_evt) NtClose (cancel_evt); if (thr_sync_evt) @@ -1281,10 +1346,10 @@ fhandler_fifo::close () NtClose (write_ready); if (writer_opening) NtClose (writer_opening); - close_all_handlers (); - if (fc_handler) - free (fc_handler); - return fhandler_base::close (); + if (nohandle ()) + return 0; + else + return fhandler_base::close (); } /* If we have a write handle (i.e., we're a duplexer or a writer), @@ -1364,8 +1429,22 @@ fhandler_fifo::dup (fhandler_base *child, int flags) } if (fhf->reopen_shared_fc_handler () < 0) goto err_close_shared_fc_hdl; + if (!DuplicateHandle (GetCurrentProcess (), owner_needed_evt, + GetCurrentProcess (), &fhf->owner_needed_evt, + 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + goto err_close_shared_fc_handler; + } + if (!DuplicateHandle (GetCurrentProcess (), owner_found_evt, + GetCurrentProcess (), &fhf->owner_found_evt, + 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + goto err_close_owner_needed_evt; + } if (!(fhf->cancel_evt = create_event (true))) - goto err_close_shared_fc_handler; + goto err_close_owner_found_evt; if (!(fhf->thr_sync_evt = create_event (true))) goto err_close_cancel_evt; inc_nreaders (); @@ -1375,6 +1454,10 @@ fhandler_fifo::dup (fhandler_base *child, int flags) return 0; err_close_cancel_evt: NtClose (fhf->cancel_evt); +err_close_owner_found_evt: + NtClose (fhf->owner_found_evt); +err_close_owner_needed_evt: + NtClose (fhf->owner_needed_evt); err_close_shared_fc_handler: NtUnmapViewOfSection (GetCurrentProcess (), fhf->shared_fc_handler); err_close_shared_fc_hdl: @@ -1411,6 +1494,8 @@ fhandler_fifo::fixup_after_fork (HANDLE parent) fork_fixup (parent, shared_fc_hdl, "shared_fc_hdl"); if (reopen_shared_fc_handler () < 0) api_fatal ("Can't reopen shared fc_handler memory during fork, %E"); + fork_fixup (parent, owner_needed_evt, "owner_needed_evt"); + fork_fixup (parent, owner_found_evt, "owner_found_evt"); if (close_on_exec ()) /* Prevent a later attempt to close the non-inherited pipe-instance handles copied from the parent. */ @@ -1491,6 +1576,8 @@ fhandler_fifo::set_close_on_exec (bool val) set_no_inheritance (writer_opening, val); if (reader) { + set_no_inheritance (owner_needed_evt, val); + set_no_inheritance (owner_found_evt, val); set_no_inheritance (cancel_evt, val); set_no_inheritance (thr_sync_evt, val); fifo_client_lock ();