2011-03-28 Tor Perkins * fhandler_termios.cc (fhandler_termios::bg_check): Do not return EIO when a process group has no leader as this is allowed and does not imply an orphaned process group. Add a test for orphaned process groups. Index: cygwin/fhandler_termios.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_termios.cc,v retrieving revision 1.78 diff -u -p -r1.78 fhandler_termios.cc --- cygwin/fhandler_termios.cc 23 Oct 2010 18:07:08 -0000 1.78 +++ cygwin/fhandler_termios.cc 2 Apr 2011 23:20:49 -0000 @@ -111,6 +111,26 @@ fhandler_pty_master::tcgetpgrp () return tc->pgid; } +int +tty_min::is_orphaned_process_group (int pgid) +{ + /* An orphaned process group is a process group in which the parent + of every member is either itself a member of the group or is not + a member of the group's session. */ + winpids pids ((DWORD) PID_MAP_RW); + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + if (!p->exists () || p->pgid != pgid) + continue; + pinfo ppid (p->ppid); + if (ppid->pgid != pgid && + ppid->sid == myself->sid) + return 0; + } + return 1; +} + void tty_min::kill_pgrp (int sig) { @@ -157,36 +177,41 @@ fhandler_termios::bg_check (int sig) return bg_eof; } - /* If the process group is no more or if process is ignoring or blocks 'sig', - return with error */ - int pgid_gone = !pid_exists (myself->pgid); + /* Determine if process ignores or blocks 'sig' */ int sigs_ignored = ((void *) global_sigs[sig].sa_handler == (void *) SIG_IGN) || (_main_tls->sigmask & SIGTOMASK (sig)); - if (pgid_gone) - goto setEIO; - else if (!sigs_ignored) - /* nothing */; - else if (sig == SIGTTOU) - return bg_ok; /* Just allow the output */ - else - goto setEIO; /* This is an output error */ - - /* Don't raise a SIGTT* signal if we have already been interrupted - by another signal. */ - if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0) - { - siginfo_t si = {0}; - si.si_signo = sig; - si.si_code = SI_KERNEL; - kill_pgrp (myself->pgid, si); - } - return bg_signalled; - -setEIO: - set_errno (EIO); - return bg_error; + /* If the process is ignoring SIGTT*, then background IO is OK. If + the process is not ignoring SIGTT*, then the sig is to be sent to + all processes in the process group (unless the process group of the + process is orphaned, in which case we return EIO). */ + if ( sigs_ignored ) + { + return bg_ok; /* Just allow the IO */ + } + else + { + if ( tc->is_orphaned_process_group (myself->pgid) ) + { + termios_printf ("process group is orphaned"); + set_errno (EIO); /* This is an IO error */ + return bg_error; + } + else + { + /* Don't raise a SIGTT* signal if we have already been + interrupted by another signal. */ + if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0) + { + siginfo_t si = {0}; + si.si_signo = sig; + si.si_code = SI_KERNEL; + kill_pgrp (myself->pgid, si); + } + return bg_signalled; + } + } } #define set_input_done(x) input_done = input_done || (x) Index: cygwin/tty.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/tty.h,v retrieving revision 1.26 diff -u -p -r1.26 tty.h --- cygwin/tty.h 19 Apr 2010 19:52:43 -0000 1.26 +++ cygwin/tty.h 2 Apr 2011 23:20:49 -0000 @@ -76,6 +76,7 @@ public: int getsid () {return sid;} void setsid (pid_t tsid) {sid = tsid;} void kill_pgrp (int sig); + int is_orphaned_process_group (int pgid); HWND gethwnd () {return hwnd;} void sethwnd (HWND wnd) {hwnd = wnd;} };