[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