Print this page
OS-4470 lxbrand unblocking signals in new threads must be atomic

@@ -89,12 +89,11 @@
         int             c_sig;          /* signal to send on thread exit */
         void            *c_stk;         /* %esp of new thread */
         void            *c_ptidp;
         struct lx_desc  *c_ldtinfo;     /* thread-specific segment */
         void            *c_ctidp;
-        ucontext_t      c_uc;           /* original register state */
-        sigset_t        c_sigmask;      /* signal mask */
+        ucontext_t      c_uc;           /* original register state/sigmask */
         lx_affmask_t    c_affmask;      /* CPU affinity mask */
         volatile int    *c_clone_res;   /* pid/error returned to cloner */
         int             c_ptrace_event; /* ptrace(2) event for child stop */
         void            *c_ntv_stk;     /* native stack for this thread */
         size_t          c_ntv_stk_sz;   /* native stack size */

@@ -237,28 +236,22 @@
          * thread-specific data structure with the stack list so that it may be
          * freed at thread exit or fork(2).
          */
         lx_install_stack(cs->c_ntv_stk, cs->c_ntv_stk_sz, lxtsd);
 
-        if (sigprocmask(SIG_SETMASK, &cs->c_sigmask, NULL) < 0) {
-                *(cs->c_clone_res) = -errno;
-
-                lx_err_fatal("Unable to release held signals for child "
-                    "thread: %s", strerror(errno));
-        }
-
         /*
          * Let the parent know that the clone has (effectively) been
          * completed.
          */
         *(cs->c_clone_res) = rval;
 
         /*
-         * We want to load the general registers from this context, and
-         * switch to the BRAND stack.
+         * We want to load the general registers from this context, restore the
+         * original signal mask, and switch to the BRAND stack.  The original
+         * signal mask was saved to the context by lx_clone().
          */
-        cs->c_uc.uc_flags = UC_CPU;
+        cs->c_uc.uc_flags = UC_CPU | UC_SIGMASK;
         cs->c_uc.uc_brand_data[0] = (void *)LX_UC_STACK_BRAND;
 
         /*
          * New threads will not link into the existing context chain.
          */

@@ -279,20 +272,13 @@
          * Fire the ptrace(2) event stop in the new thread:
          */
         lx_ptrace_stop_if_option(cs->c_ptrace_event, B_TRUE, 0, &cs->c_uc);
 
         /*
-         * Jump to the Linux process.  The system call must not return.
+         * Jump to the Linux process.  This call cannot return.
          */
-        if (syscall(SYS_brand, B_JUMP_TO_LINUX, &cs->c_uc) == -1) {
-                lx_err_fatal("B_JUMP_TO_LINUX failed: %s",
-                    strerror(errno));
-        }
-        abort();
-
-        /*NOTREACHED*/
-        return (NULL);
+        lx_jump_to_linux(&cs->c_uc);
 }
 
 /*
  * The way Linux handles stopping for FORK vs. CLONE does not map exactly to
  * which syscall was used. Instead, it has to do with which signal is set in

@@ -664,23 +650,22 @@
                     "thread: %s", strerror(errno));
         }
 
         clone_res = 0;
 
-        (void) sigfillset(&sigmask);
-
         /*
          * Block all signals because the thread we create won't be able to
          * properly handle them until it's fully set up.
          */
+        (void) sigfillset(&sigmask);
         if (sigprocmask(SIG_BLOCK, &sigmask, &osigmask) < 0) {
                 lx_debug("lx_clone sigprocmask() failed: %s", strerror(errno));
                 free(cs->c_lx_tsd);
                 free(cs);
                 return (-errno);
         }
-        cs->c_sigmask = osigmask;
+        cs->c_uc.uc_sigmask = osigmask;
 
         /*
          * Allocate the native stack for this new thread now, so that we
          * can return failure gracefully as ENOMEM.
          */