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