On Mon, 11 Mar 2024 20:42:37 +0900 Takashi Yano wrote: > On Mon, 11 Mar 2024 11:47:32 +0100 > Corinna Vinschen wrote: > > Hi Takashi, > > > > On Mar 10 19:31, Takashi Yano wrote: > > > @@ -590,6 +591,10 @@ child_info_spawn::worker (const char *prog_arg, > > > const char *const *argv, > > > { > > > fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; > > > pipe->set_pipe_non_blocking (false); > > > + pipew_duped = (fhandler_pipe *) > > > + ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_pipe)); > > > + pipew_duped = new (pipew_duped) fhandler_pipe; > > > + pipe->dup (pipew_duped, 0); > > > if (pipe->request_close_query_hdl ()) > > > need_send_sig = true; > > > } > > > > The code setting up pipes and the dummy_tty is sufficiently complex, > > so that I wonder if it shouldn't have > > > > - its own methods and > > - comments to describe why this stuff is necessary. > > > > What about adding two methods, kind of like (the names are only > > suggestion, albeit bad ones): > > > > child_info_spawn::noncygwin_child_pre_fork() > > > > to keep the above stuff together (plus comments) and > > > > child_info_spawn::noncygwin_child_post_fork() > > > > for the below code? > > > > > @@ -597,6 +602,10 @@ child_info_spawn::worker (const char *prog_arg, > > > const char *const *argv, > > > { > > > fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; > > > pipe->set_pipe_non_blocking (false); > > > + piper_duped = (fhandler_pipe *) > > > + ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_pipe)); > > > + piper_duped = new (piper_duped) fhandler_pipe; > > > + pipe->dup (piper_duped, 0); > > > } > > > > > > if (need_send_sig) > > > @@ -905,6 +914,19 @@ child_info_spawn::worker (const char *prog_arg, > > > const char *const *argv, > > > term_spawn_worker.cleanup (); > > > term_spawn_worker.close_handle_set (); > > > } > > > + if (pipew_duped) > > > + { > > > + bool is_nonblocking = pipew_duped->is_nonblocking (); > > > + pipew_duped->set_pipe_non_blocking (is_nonblocking); > > > > Is that really right? You're asking pipew_duped for its > > nonblocking flag and then set pipew_duped to the same value...? > > > > > + pipew_duped->close (); > > > + cfree (pipew_duped); > > > + } > > Thanks for the reviewing and advice. I'll work for v2 patch. Please wait a > while.
I have reconsider what is essential. Then, just setting read pipe to non-blocking mode for cygwin apps is enough when it starts. Please review v2 patch attached. -- Takashi Yano <takashi.y...@nifty.ne.jp>
From 43ab2d456f3ef91a1cf8718ee178ac91e4b41679 Mon Sep 17 00:00:00 2001 From: Takashi Yano <takashi.y...@nifty.ne.jp> Date: Mon, 11 Mar 2024 22:08:00 +0900 Subject: [PATCH v2] Cygwin: pipe: Make sure to set read pipe non-blocking for cygwin apps. If pipe reader is a non-cygwin app first, and cygwin process reads the same pipe after that, the pipe has been set to bclocking mode for the cygwin app. However, the commit 9e4d308cd592 assumes the pipe for cygwin process always is non-blocking mode. With this patch, the pipe mode is reset to non-blocking when cygwin app is started. Addresses: https://cygwin.com/pipermail/cygwin/2024-March/255644.html Fixes: 9e4d308cd592 ("Cygwin: pipe: Adopt FILE_SYNCHRONOUS_IO_NONALERT flag for read pipe.") Reported-by: wh <wh9...@protonmail.com> Reviewed-by: Corinna Vinschen <cori...@vinschen.de> Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp> --- winsup/cygwin/fhandler/pipe.cc | 54 +++++++++++++++++++++++++ winsup/cygwin/local_includes/fhandler.h | 2 + winsup/cygwin/spawn.cc | 35 +--------------- 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 29d3b41d9..b29726dcb 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -18,6 +18,7 @@ details. */ #include "pinfo.h" #include "shared_info.h" #include "tls_pbuf.h" +#include "sigproc.h" #include <assert.h> /* This is only to be used for writing. When reading, @@ -1288,3 +1289,56 @@ close_proc: } return NULL; } + +void +fhandler_pipe::spawn_worker (bool iscygwin, int fileno_stdin, + int fileno_stdout, int fileno_stderr) +{ + bool need_send_noncygchld_sig = false; + + /* Set read pipe itself always non-blocking for cygwin process. blocking/ + non-blocking is simulated in the raw_read(). As for write pipe, follow + the is_nonblocking(). */ + int fd; + cygheap_fdenum cfd (false); + while ((fd = cfd.next ()) >= 0) + if (cfd->get_dev () == FH_PIPEW + && (fd == fileno_stdout || fd == fileno_stderr)) + { + fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; + bool mode = iscygwin ? pipe->is_nonblocking () : false; + pipe->set_pipe_non_blocking (mode); + + /* Setup for query_ndl stuff. Read the comment below. */ + if (!iscygwin && pipe->request_close_query_hdl ()) + need_send_noncygchld_sig = true; + } + else if (cfd->get_dev () == FH_PIPER && fd == fileno_stdin) + { + fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; + pipe->set_pipe_non_blocking (iscygwin); + } + + /* If multiple writers including non-cygwin app exist, the non-cygwin + app cannot detect pipe closure on the read side when the pipe is + created by system account or the the pipe creator is running as + service. This is because query_hdl which is held in write side + also is a read end of the pipe, so the pipe is still alive for + the non-cygwin app even after the reader is closed. + + To avoid this problem, let all processes in the same process + group close query_hdl using internal signal __SIGNONCYGCHLD when + non-cygwin app is started. */ + if (need_send_noncygchld_sig) + { + tty_min dummy_tty; + dummy_tty.ntty = (fh_devices) myself->ctty; + dummy_tty.pgid = myself->pgid; + tty_min *t = cygwin_shared->tty.get_cttyp (); + if (!t) /* If tty is not allocated, use dummy_tty instead. */ + t = &dummy_tty; + /* Emit __SIGNONCYGCHLD to let all processes in the + process group close query_hdl. */ + t->kill_pgrp (__SIGNONCYGCHLD); + } +} diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 8729eb276..dca473efb 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -1295,6 +1295,8 @@ public: } return false; } + static void spawn_worker (bool iscygwin, int fileno_stdin, + int fileno_stdout, int fileno_stderr); }; #define CYGWIN_FIFO_PIPE_NAME_LEN 47 diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 71d75bbf4..64749b572 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -579,39 +579,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, int fileno_stdout = in__stdout < 0 ? 1 : in__stdout; int fileno_stderr = 2; - if (!iscygwin ()) - { - bool need_send_sig = false; - int fd; - cygheap_fdenum cfd (false); - while ((fd = cfd.next ()) >= 0) - if (cfd->get_dev () == FH_PIPEW - && (fd == fileno_stdout || fd == fileno_stderr)) - { - fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; - pipe->set_pipe_non_blocking (false); - if (pipe->request_close_query_hdl ()) - need_send_sig = true; - } - else if (cfd->get_dev () == FH_PIPER && fd == fileno_stdin) - { - fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; - pipe->set_pipe_non_blocking (false); - } - - if (need_send_sig) - { - tty_min dummy_tty; - dummy_tty.ntty = (fh_devices) myself->ctty; - dummy_tty.pgid = myself->pgid; - tty_min *t = cygwin_shared->tty.get_cttyp (); - if (!t) /* If tty is not allocated, use dummy_tty instead. */ - t = &dummy_tty; - /* Emit __SIGNONCYGCHLD to let all processes in the - process group close query_hdl. */ - t->kill_pgrp (__SIGNONCYGCHLD); - } - } + fhandler_pipe::spawn_worker (iscygwin (), fileno_stdin, + fileno_stdout, fileno_stderr); bool no_pcon = mode != _P_OVERLAY && mode != _P_WAIT; term_spawn_worker.setup (iscygwin (), handle (fileno_stdin, false), -- 2.43.0