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

*** 89,100 **** 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 */ 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 */ --- 89,99 ---- 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/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,264 **** * 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. */ ! cs->c_uc.uc_flags = UC_CPU; cs->c_uc.uc_brand_data[0] = (void *)LX_UC_STACK_BRAND; /* * New threads will not link into the existing context chain. */ --- 236,257 ---- * 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); /* * 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, 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 | 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,298 **** * 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. */ ! 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); } /* * 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 --- 272,284 ---- * 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. This call cannot return. */ ! 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,686 **** "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. */ 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; /* * Allocate the native stack for this new thread now, so that we * can return failure gracefully as ENOMEM. */ --- 650,671 ---- "thread: %s", strerror(errno)); } clone_res = 0; /* * 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_uc.uc_sigmask = osigmask; /* * Allocate the native stack for this new thread now, so that we * can return failure gracefully as ENOMEM. */