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.
*/