the sigmask was already a member of the child_info, so this just needed an arg to allow overriding the value copied from cygheap. The signal handlers are referenced by two pointers, global_sigs which is used by the signal routines, and cygheap->sigs which is only used during process launch and startup. Temporarily replace cygheap->sigs with a copy that has the requested signals reset to default while spawning the child.
Signed-off-by: Jeremy Drake <cyg...@jdrake.com> --- winsup/cygwin/local_includes/child_info.h | 3 +- winsup/cygwin/spawn.cc | 57 ++++++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/winsup/cygwin/local_includes/child_info.h b/winsup/cygwin/local_includes/child_info.h index ad7c8fc29a..63f398fa1d 100644 --- a/winsup/cygwin/local_includes/child_info.h +++ b/winsup/cygwin/local_includes/child_info.h @@ -141,9 +141,10 @@ struct spawn_worker_args int mode; int stdfds[3]; int cwdfd; + sigset_t *sigmask; spawn_worker_args (int mode) - : mode (mode), stdfds {-1, -1, -1}, cwdfd (AT_FDCWD) + : mode (mode), stdfds {-1, -1, -1}, cwdfd (AT_FDCWD), sigmask (NULL) { } }; diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index b8b623af7f..cd99644d60 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -589,6 +589,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, __stdin = args.stdfds[0]; __stdout = args.stdfds[1]; __stderr = args.stdfds[2]; + if (args.sigmask) + sigmask = *args.sigmask; record_children (); si.lpReserved2 = (LPBYTE) this; @@ -1454,6 +1456,8 @@ do_posix_spawn (pid_t *pid, const char *path, const posix_spawnattr_t *sa, char * const argv[], char * const envp[], int use_env_path) { + spawn_worker_args args (_P_NOWAIT); + struct sigaction *sigs = NULL; syscall_printf ("posix_spawn%s (%p, %s, %p, %p, %p, %p)", use_env_path ? "p" : "", pid, path, fa, sa, argv, envp); @@ -1461,15 +1465,26 @@ do_posix_spawn (pid_t *pid, const char *path, POSIX_SPAWN_RESETIDS POSIX_SPAWN_SETPGROUP POSIX_SPAWN_SETSCHEDPARAM - POSIX_SPAWN_SETSCHEDULER - POSIX_SPAWN_SETSIGDEF - POSIX_SPAWN_SETSIGMASK */ - if (sa && (*sa)->sa_flags) - goto fallback; + POSIX_SPAWN_SETSCHEDULER */ + if (sa) + { + if ((*sa)->sa_flags & ~(POSIX_SPAWN_SETSIGMASK|POSIX_SPAWN_SETSIGDEF)) + goto fallback; + + if ((*sa)->sa_flags & POSIX_SPAWN_SETSIGMASK) + args.sigmask = &(*sa)->sa_sigmask; + + if ((*sa)->sa_flags & POSIX_SPAWN_SETSIGDEF) + { + sigs = (struct sigaction *) cmalloc (HEAP_SIGS, + _NSIG * sizeof (struct sigaction)); + if (!sigs) + return ENOMEM; + } + } { path_conv buf; - spawn_worker_args args (_P_NOWAIT); /* lock the process to temporarily manipulate file descriptors for the spawn operation */ lock_process now; @@ -1623,12 +1638,40 @@ do_posix_spawn (pid_t *pid, const char *path, } } + if (sigs) + { + memcpy (sigs, cygheap->sigs, _NSIG * sizeof (struct sigaction)); + for (int i = 1; i < _NSIG; i++) + { + if ((*sa)->sa_sigdefault & SIGTOMASK (i)) + { + sigs[i].sa_mask = 0; + sigs[i].sa_handler = SIG_DFL; + sigs[i].sa_flags &= ~SA_SIGINFO; + } + } + + /* the active signal handler info is kept in global_sigs and + cygheap->sigs is only used for inheritance to child processes, so we + can swap out cygheap->sigs without worrying about messing up the + current process's state. Use an InterlockedExchange just to be + safe. */ + sigs = (struct sigaction *) InterlockedExchangePointer ( + (PVOID *) &cygheap->sigs, sigs); + } + chpid = ch_spawn.worker ( use_env_path ? (find_exec (path, buf, "PATH", FE_NNF, NULL, args.cwdfd) ?: "") : path, argv, envp ?: environ, args); + /* put cygheap->sigs back how we found it (should be the same as + global_sigs */ + if (sigs) + sigs = (struct sigaction *) InterlockedExchangePointer ( + (PVOID *) &cygheap->sigs, sigs); + if (chpid < 0) { ret = get_errno (); @@ -1641,6 +1684,8 @@ do_posix_spawn (pid_t *pid, const char *path, closes: int save_errno = get_errno (); + if (sigs) + cfree (sigs); if (args.cwdfd >= 0) close (args.cwdfd); for (size_t i = 0; i < 3; i++) -- 2.49.0.windows.1