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

Reply via email to