aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin
diff options
context:
space:
mode:
authorTakashi Yano <takashi.yano@nifty.ne.jp>2024-09-06 14:19:44 +0900
committerTakashi Yano <takashi.yano@nifty.ne.jp>2024-09-17 22:01:45 +0900
commitc7fe29f5cb85242ae2607945762f7e0b9af02513 (patch)
tree5dc6ed8d8c829f0b6a7cd991f9a6796f6f4d1222 /winsup/cygwin
parent784ce7aff8c92b6b729e8bf5564e582360c24d8c (diff)
downloadnewlib-cygwin-3_5-branch.zip
newlib-cygwin-3_5-branch.tar.gz
newlib-cygwin-3_5-branch.tar.bz2
Cygwin: pipe: Restore blocking mode of read pipe on close()/raw_read()github/cygwin-3_5-branchcygwin-3_5-branch
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 by referring the variable is_blocking_read_pipe as well. is_blocking_read_pipe is a member of fhandler_pipe class and is set by set_pipe_non_blocking(), so if other process sets the pipe mode to blocking mode, the current process cannot know the pipe is blocking mode. Therefore, is_blocking_read_pipe is also set on the signal __SIGNONCYGCHLD, which is sent to the process group when non-cygwin app is started. 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>, Ken Brown <kbrown@cornell.edu> Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/fhandler/pipe.cc41
-rw-r--r--winsup/cygwin/local_includes/fhandler.h3
-rw-r--r--winsup/cygwin/sigproc.cc9
3 files changed, 45 insertions, 8 deletions
diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc
index 9973468..3b78cc1 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 10bc9c7..0000044 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 99fa3c3..a758bc8 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)