Print this page
OS-4470 lxbrand unblocking signals in new threads must be atomic
Reviewed by: Robert Mustacchi <rm@joyent.com>
OS-3561 lxbrand emulation library should execute on alternate stack
OS-3558 lxbrand add support for full in-kernel syscall handling
OS-3545 lx_syscall_regs should not walk stack
OS-3868 many LTP testcases now hang
OS-3901 lxbrand lx_recvmsg fails to translate control messages when 64-bit
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
OS-2844 lx brand should support 64-bit user-land

*** 20,29 **** --- 20,30 ---- */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2015 Joyent, Inc. */ #include "lint.h" #include <sys/feature_tests.h> /*
*** 282,292 **** --- 283,311 ---- continue; if (error) thr_panic("take_deferred_signal(): __sigresend() failed"); } + /* + * sigacthandler() attempts to clean up dangling uc_link pointers in + * signal handling contexts when libc believes us to have escaped + * a signal handler incorrectly in the past. + * + * Branded processes have a legitimate use for a chain including contexts + * other than those used for signal handling when tracking emulation + * requests from the kernel. We allow them to disable this cleanup + * behaviour. + */ + static int escaped_context_cleanup = 1; + void + set_escaped_context_cleanup(int on) + { + escaped_context_cleanup = on; + } + + void sigacthandler(int sig, siginfo_t *sip, void *uvp) { ucontext_t *ucp = uvp; ulwp_t *self = curthread;
*** 304,314 **** * thinking that it is still in the signal context. We repair this * possible damage by setting ucp->uc_link to NULL if we know that * we are actually executing at main level (self->ul_siglink == NULL). * See the code for setjmp()/longjmp() for more details. */ ! if (self->ul_siglink == NULL) ucp->uc_link = NULL; /* * If we are not in a critical region and are * not deferring signals, take the signal now. --- 323,333 ---- * thinking that it is still in the signal context. We repair this * possible damage by setting ucp->uc_link to NULL if we know that * we are actually executing at main level (self->ul_siglink == NULL). * See the code for setjmp()/longjmp() for more details. */ ! if (escaped_context_cleanup && self->ul_siglink == NULL) ucp->uc_link = NULL; /* * If we are not in a critical region and are * not deferring signals, take the signal now.
*** 456,478 **** lrw_unlock(&udp->siguaction[sig].sig_lock); return (rv); } /* ! * This is a private interface for the linux brand interface. */ void setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *), ! void (**osigacthandler)(int, siginfo_t *, void *)) { ulwp_t *self = curthread; uberdata_t *udp = self->ul_uberdata; if (osigacthandler != NULL) *osigacthandler = udp->sigacthandler; udp->sigacthandler = nsigacthandler; } /* * Tell the kernel to block all signals. * Use the schedctl interface, or failing that, use __lwp_sigmask(). --- 475,501 ---- lrw_unlock(&udp->siguaction[sig].sig_lock); return (rv); } /* ! * This is a private interface for the lx brand. */ void setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *), ! void (**osigacthandler)(int, siginfo_t *, void *), ! int (*brsetctxt)(const ucontext_t *)) { ulwp_t *self = curthread; uberdata_t *udp = self->ul_uberdata; if (osigacthandler != NULL) *osigacthandler = udp->sigacthandler; udp->sigacthandler = nsigacthandler; + + if (brsetctxt != NULL) + udp->setctxt = brsetctxt; } /* * Tell the kernel to block all signals. * Use the schedctl interface, or failing that, use __lwp_sigmask().
*** 515,529 **** --- 538,580 ---- set_setcontext_enforcement(int on) { setcontext_enforcement = on; } + /* + * The LX brand emulation library implements an operation that is analogous to + * setcontext(), but takes a different path in to the kernel. So that it can + * correctly restore a signal mask, we expose just the signal mask handling + * part of the regular setcontext() routine as a private interface. + */ + void + setcontext_sigmask(ucontext_t *ucp) + { + ulwp_t *self = curthread; + + if (ucp->uc_flags & UC_SIGMASK) { + block_all_signals(self); + delete_reserved_signals(&ucp->uc_sigmask); + self->ul_sigmask = ucp->uc_sigmask; + if (self->ul_cursig) { + /* + * We have a deferred signal present. + * The signal mask will be set when the + * signal is taken in take_deferred_signal(). + */ + ASSERT(self->ul_critical + self->ul_sigdefer != 0); + ucp->uc_flags &= ~UC_SIGMASK; + } + } + } + #pragma weak _setcontext = setcontext int setcontext(const ucontext_t *ucp) { ulwp_t *self = curthread; + uberdata_t *udp = self->ul_uberdata; int ret; ucontext_t uc; /* * Returning from the main context (uc_link == NULL) causes
*** 534,557 **** (void) memcpy(&uc, ucp, sizeof (uc)); /* * Restore previous signal mask and context link. */ ! if (uc.uc_flags & UC_SIGMASK) { ! block_all_signals(self); ! delete_reserved_signals(&uc.uc_sigmask); ! self->ul_sigmask = uc.uc_sigmask; ! if (self->ul_cursig) { ! /* ! * We have a deferred signal present. ! * The signal mask will be set when the ! * signal is taken in take_deferred_signal(). ! */ ! ASSERT(self->ul_critical + self->ul_sigdefer != 0); ! uc.uc_flags &= ~UC_SIGMASK; ! } ! } self->ul_siglink = uc.uc_link; /* * We don't know where this context structure has been. * Preserve the curthread pointer, at least. --- 585,595 ---- (void) memcpy(&uc, ucp, sizeof (uc)); /* * Restore previous signal mask and context link. */ ! setcontext_sigmask(&uc); self->ul_siglink = uc.uc_link; /* * We don't know where this context structure has been. * Preserve the curthread pointer, at least.
*** 576,586 **** * or ___lwp_cond_wait() that it returns right away * (giving us a spurious wakeup but not a deadlock). */ set_parking_flag(self, 0); self->ul_sp = 0; ! ret = __setcontext(&uc); /* * It is OK for setcontext() to return if the user has not specified * UC_CPU. */ --- 614,624 ---- * or ___lwp_cond_wait() that it returns right away * (giving us a spurious wakeup but not a deadlock). */ set_parking_flag(self, 0); self->ul_sp = 0; ! ret = udp->setctxt(&uc); /* * It is OK for setcontext() to return if the user has not specified * UC_CPU. */