From beeae61f97145d795c4479b0d46cd3b75d6256c4 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Thu, 9 Sep 2021 11:53:11 +0900
Subject: [PATCH] Cygwin: fifo: Utilize select_sem for fifo as well as pipe.

---
 winsup/cygwin/fhandler_fifo.cc | 37 +++++++++++++++++++++++++++++++++-
 winsup/cygwin/select.cc        | 10 +++++++--
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 6709fb974..c40573783 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -1047,6 +1047,12 @@ writer_shmem:
   ResetEvent (writer_opening);
   nwriters_unlock ();
 success:
+  if (!select_sem)
+    {
+      char name[MAX_PATH];
+      __small_sprintf(name, "semaphore-%W", get_pipe_name ()->Buffer);
+      select_sem = CreateSemaphore (&sec_none, 0, INT32_MAX, name);
+    }
   return 1;
 err_close_reader:
   saved_errno = get_errno ();
@@ -1235,6 +1241,10 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		  len = io.Information;
 		  fifo_client_unlock ();
 		  reading_unlock ();
+		  if (select_sem)
+		    ReleaseSemaphore (select_sem,
+				      get_obj_handle_count (select_sem),
+				      NULL);
 		  return;
 		}
 	      break;
@@ -1273,6 +1283,10 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		    fc_handler[i].last_read = true;
 		    fifo_client_unlock ();
 		    reading_unlock ();
+		    if (select_sem)
+		      ReleaseSemaphore (select_sem,
+					get_obj_handle_count (select_sem),
+					NULL);
 		    return;
 		  }
 		break;
@@ -1312,6 +1326,10 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 		    fc_handler[i].last_read = true;
 		    fifo_client_unlock ();
 		    reading_unlock ();
+		    if (select_sem)
+		      ReleaseSemaphore (select_sem,
+					get_obj_handle_count (select_sem),
+					NULL);
 		    return;
 		  }
 		break;
@@ -1345,7 +1363,7 @@ maybe_retry:
       else
 	{
 	  /* Allow interruption and don't hog the CPU. */
-	  DWORD waitret = cygwait (NULL, 1, cw_cancel | cw_sig_eintr);
+	  DWORD waitret = cygwait (select_sem, 1, cw_cancel | cw_sig_eintr);
 	  if (waitret == WAIT_CANCELED)
 	    pthread::static_cancel_self ();
 	  else if (waitret == WAIT_SIGNALED)
@@ -1569,6 +1587,11 @@ fhandler_fifo::close ()
     NtClose (write_ready);
   if (writer_opening)
     NtClose (writer_opening);
+  if (select_sem)
+    {
+      ReleaseSemaphore (select_sem, get_obj_handle_count (select_sem), NULL);
+      NtClose (select_sem);
+    }
   if (nohandle ())
     return 0;
   else
@@ -1683,7 +1706,17 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
     }
   if (writer)
     inc_nwriters ();
+  if (select_sem &&
+      !DuplicateHandle (GetCurrentProcess (), select_sem,
+			GetCurrentProcess (), &fhf->select_sem,
+			0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
+    {
+      __seterrno ();
+      goto err_close_thr_sync_evt;
+    }
   return 0;
+err_close_thr_sync_evt:
+  NtClose (fhf->thr_sync_evt);
 err_close_cancel_evt:
   NtClose (fhf->cancel_evt);
 err_close_update_needed_evt:
@@ -1743,6 +1776,8 @@ fhandler_fifo::fixup_after_fork (HANDLE parent)
       me.winpid = GetCurrentProcessId ();
       new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
     }
+  if (select_sem)
+    fork_fixup (parent, select_sem, "select_sem");
   if (writer)
     inc_nwriters ();
 }
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index e9e71b269..5e583434c 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -963,7 +963,13 @@ start_thread_fifo (select_record *me, select_stuff *stuff)
     {
       pi->start = &stuff->start;
       pi->stop_thread = false;
-      pi->bye = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+      pi->bye = me->fh->get_select_sem ();
+      if (pi->bye)
+	DuplicateHandle (GetCurrentProcess (), pi->bye,
+			 GetCurrentProcess (), &pi->bye,
+			 0, 0, DUPLICATE_SAME_ACCESS);
+      else
+	pi->bye = CreateSemaphore (&sec_none_nih, 0, INT32_MAX, NULL);
       pi->thread = new cygthread (thread_fifo, pi, "fifosel");
       me->h = *pi->thread;
       if (!me->h)
@@ -981,7 +987,7 @@ fifo_cleanup (select_record *, select_stuff *stuff)
   if (pi->thread)
     {
       pi->stop_thread = true;
-      SetEvent (pi->bye);
+      ReleaseSemaphore (pi->bye, get_obj_handle_count (pi->bye), NULL);
       pi->thread->detach ();
       CloseHandle (pi->bye);
     }
-- 
2.33.0

