[PATCH v2] Cygwin: pipe: Restore blocking mode of read pipe on close()

Takashi Yano takashi.yano@nifty.ne.jp
Fri Sep 6 08:08:40 GMT 2024


If a cygwin app is executed from a non-cygwin app and the cygwin
app exits, the read pipe remains in the non-blocking mode because
of the commit fc691d0246b9. Due to this behaviour, the non-cygwin
app cannot read the pipe correctly after that. Similarly, if a
non-cygwin app is executed from a cygwin app and the non-cygwin
app exits, the read pipe remains in the blocking mode. With this
patch, the blocking mode of the read pipe is stored into a variable
was_blocking_read_pipe on set_pipe_non_blocking() when the cygwin
app starts and restored on close(). In addition, the pipe mode is
set to non-blocking mode in raw_read() if the mode is blocking
mode as well.

Addresses: https://github.com/git-for-windows/git/issues/5115
Fixes: fc691d0246b9 ("Cygwin: pipe: Make sure to set read pipe non-blocking for cygwin apps.");
Reported-by: isaacag, Johannes Schindelin <Johannes.Schindelin@gmx.de>
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
---
 winsup/cygwin/fhandler/pipe.cc          | 41 +++++++++++++++++++++++++
 winsup/cygwin/local_includes/fhandler.h |  3 ++
 winsup/cygwin/sigproc.cc                |  9 +-----
 3 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc
index 997346877..3b78cc183 100644
--- a/winsup/cygwin/fhandler/pipe.cc
+++ b/winsup/cygwin/fhandler/pipe.cc
@@ -54,6 +54,16 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking)
   NTSTATUS status;
   IO_STATUS_BLOCK io;
   FILE_PIPE_INFORMATION fpi;
+  bool was_blocking_read_pipe_new = was_blocking_read_pipe;
+
+  if (get_device () == FH_PIPER && nonblocking && !was_blocking_read_pipe)
+    {
+      status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi,
+				       FilePipeInformation);
+      if (NT_SUCCESS (status))
+	was_blocking_read_pipe_new =
+	  (fpi.CompletionMode == FILE_PIPE_QUEUE_OPERATION);
+    }
 
   fpi.ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
   fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION
@@ -62,6 +72,11 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking)
 				 FilePipeInformation);
   if (!NT_SUCCESS (status))
     debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status);
+  else
+    {
+      was_blocking_read_pipe = was_blocking_read_pipe_new;
+      is_blocking_read_pipe = !nonblocking;
+    }
 }
 
 int
@@ -95,6 +110,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id)
        even with FILE_SYNCHRONOUS_IO_NONALERT. */
     set_pipe_non_blocking (get_device () == FH_PIPER ?
 			   true : is_nonblocking ());
+  was_blocking_read_pipe = false;
+
   return 1;
 }
 
@@ -289,6 +306,9 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
   if (!len)
     return;
 
+  if (is_blocking_read_pipe)
+    set_pipe_non_blocking (true);
+
   DWORD timeout = is_nonblocking () ? 0 : INFINITE;
   DWORD waitret = cygwait (read_mtx, timeout);
   switch (waitret)
@@ -721,6 +741,8 @@ fhandler_pipe::close ()
     CloseHandle (query_hdl);
   if (query_hdl_close_req_evt)
     CloseHandle (query_hdl_close_req_evt);
+  if (was_blocking_read_pipe)
+    set_pipe_non_blocking (false);
   int ret = fhandler_base::close ();
   ReleaseMutex (hdl_cnt_mtx);
   CloseHandle (hdl_cnt_mtx);
@@ -1373,6 +1395,7 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout,
       {
 	fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
 	pipe->set_pipe_non_blocking (false);
+	need_send_noncygchld_sig = true;
       }
 
   /* If multiple writers including non-cygwin app exist, the non-cygwin
@@ -1398,3 +1421,21 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout,
       t->kill_pgrp (__SIGNONCYGCHLD);
     }
 }
+
+void
+fhandler_pipe::sigproc_worker (void)
+{
+  cygheap_fdenum cfd (false);
+  while (cfd.next () >= 0)
+    if (cfd->get_dev () == FH_PIPEW)
+      {
+	fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
+	if (pipe->need_close_query_hdl ())
+	  pipe->close_query_handle ();
+      }
+    else if (cfd->get_dev () == FH_PIPER)
+      {
+	fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
+	pipe->is_blocking_read_pipe = true;
+      }
+}
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index 10bc9c7ec..000004479 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -1197,6 +1197,8 @@ class fhandler_pipe: public fhandler_pipe_fifo
 private:
   HANDLE read_mtx;
   pid_t popen_pid;
+  bool was_blocking_read_pipe;
+  bool is_blocking_read_pipe;
   HANDLE query_hdl;
   HANDLE hdl_cnt_mtx;
   HANDLE query_hdl_proc;
@@ -1287,6 +1289,7 @@ public:
     }
   static void spawn_worker (int fileno_stdin, int fileno_stdout,
 			    int fileno_stderr);
+  static void sigproc_worker (void);
 };
 
 #define CYGWIN_FIFO_PIPE_NAME_LEN     47
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 99fa3c342..a758bc8f2 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -1475,14 +1475,7 @@ wait_sig (VOID *)
 	    }
 	  break;
 	case __SIGNONCYGCHLD:
-	  cygheap_fdenum cfd (false);
-	  while (cfd.next () >= 0)
-	    if (cfd->get_dev () == FH_PIPEW)
-	      {
-		fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
-		if (pipe->need_close_query_hdl ())
-		  pipe->close_query_handle ();
-	      }
+	  fhandler_pipe::sigproc_worker ();
 	  break;
 	}
       if (clearwait && !have_execed)
-- 
2.45.1



More information about the Cygwin-patches mailing list