diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 05b16258be..8daae8d192 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 /* This is only to be used for writing. When reading, @@ -587,6 +588,17 @@ fhandler_pipe::fixup_after_fork (HANDLE parent) ReleaseMutex (hdl_cnt_mtx); } +void +fhandler_pipe::fixup_after_exec () +{ + /* Set read pipe itself always non-blocking for cygwin process. + Blocking/non-blocking is simulated in raw_read(). For write + pipe, follow is_nonblocking(). */ + bool mode = get_device () == FH_PIPEW ? is_nonblocking () : true; + set_pipe_non_blocking (mode); + fhandler_base::fixup_after_exec (); +} + int fhandler_pipe::dup (fhandler_base *child, int flags) { @@ -1370,3 +1382,54 @@ fhandler_pipe::get_query_hdl_per_system (WCHAR *name, HeapFree (GetProcessHeap (), 0, shi); return NULL; } + +void +fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout, + int fileno_stderr) +{ + bool need_send_noncygchld_sig = false; + + /* spawn_worker() is called from spawn.cc only when non-cygwin app + is started. Set pipe mode blocking for the non-cygwin process. */ + 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); + + /* Setup for query_ndl stuff. Read the comment below. */ + if (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 (false); + } + + /* 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 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 649a431844..15b19f7643 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -1212,6 +1212,7 @@ class fhandler_pipe: public fhandler_pipe_fifo int open (int flags, mode_t mode = 0); bool open_setup (int flags); void fixup_after_fork (HANDLE); + void fixup_after_exec (); int dup (fhandler_base *child, int); void set_close_on_exec (bool val); int close (); @@ -1273,6 +1274,8 @@ class fhandler_pipe: public fhandler_pipe_fifo } return false; } + static void spawn_worker (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 383f5e56fe..acdef49375 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -607,38 +607,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, 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 (fileno_stdin, fileno_stdout, + fileno_stderr); bool no_pcon = mode != _P_OVERLAY && mode != _P_WAIT; term_spawn_worker.setup (iscygwin (), handle (fileno_stdin, false),