From 8d750bfb1bf0228b6e58e834f4842c7080398d13 Mon Sep 17 00:00:00 2001 From: davidxu Date: Mon, 29 Dec 2003 23:21:09 +0000 Subject: Implement sigaltstack() as per-threaded. Current only scope process thread is supported, for scope system process, kernel signal bits need to be changed. Reviewed by: deischen Tested on : i386 amd64 ia64 --- lib/libpthread/pthread.map | 2 + lib/libpthread/thread/Makefile.inc | 1 + lib/libpthread/thread/thr_create.c | 3 + lib/libpthread/thread/thr_sig.c | 147 ++++++++++++++++++++++++++------ lib/libpthread/thread/thr_sigaltstack.c | 104 ++++++++++++++++++++++ 5 files changed, 233 insertions(+), 24 deletions(-) create mode 100644 lib/libpthread/thread/thr_sigaltstack.c (limited to 'lib/libpthread') diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map index 04b308c..e3cc71d 100644 --- a/lib/libpthread/pthread.map +++ b/lib/libpthread/pthread.map @@ -154,6 +154,7 @@ global: _sem_unlink; _sem_wait; _sigaction; + _sigaltstack; _sigpending; _sigprocmask; _sigsuspend; @@ -308,6 +309,7 @@ global: sem_unlink; sem_wait; sigaction; + sigaltstack; sigpending; sigprocmask; sigsuspend; diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc index 0a9da84..fb11adb 100644 --- a/lib/libpthread/thread/Makefile.inc +++ b/lib/libpthread/thread/Makefile.inc @@ -89,6 +89,7 @@ SRCS+= \ thr_setschedparam.c \ thr_sig.c \ thr_sigaction.c \ + thr_sigaltstack.c \ thr_sigmask.c \ thr_sigpending.c \ thr_sigprocmask.c \ diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c index eef5806..b82f1809 100644 --- a/lib/libpthread/thread/thr_create.c +++ b/lib/libpthread/thread/thr_create.c @@ -252,6 +252,9 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, sigemptyset(&new_thread->sigpend); new_thread->check_pending = 0; new_thread->locklevel = 0; + new_thread->sigstk.ss_sp = 0; + new_thread->sigstk.ss_size = 0; + new_thread->sigstk.ss_flags = SS_DISABLE; if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { new_thread->state = PS_SUSPENDED; diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index 8759f20..a817371 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -399,16 +399,31 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) DBG_MSG("<<< _thr_sig_handler(%d)\n", sig); } +struct sighandle_info { + __siginfohandler_t *sigfunc; + int sa_flags; + int sig; + siginfo_t *info; + ucontext_t *ucp; +}; + +static void handle_signal(struct pthread *curthread, + struct sighandle_info *shi); +static void handle_signal_altstack(struct pthread *curthread, + struct sighandle_info *shi); + /* Must be called with signal lock and schedule lock held in order */ static void thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, ucontext_t *ucp) { - void (*sigfunc)(int, siginfo_t *, void *); + __siginfohandler_t *sigfunc; sigset_t sigmask; int sa_flags; + int onstack; struct sigaction act; struct kse *curkse; + struct sighandle_info shi; /* * Invoke the signal handler without going through the scheduler: @@ -444,31 +459,29 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, */ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); - _kse_critical_leave(&curthread->tcb->tcb_tmbx); + onstack = _thr_sigonstack(&sigfunc); + ucp->uc_stack = curthread->sigstk; + ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE) + ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0); ucp->uc_sigmask = sigmask; - if (((__sighandler_t *)sigfunc != SIG_DFL) && - ((__sighandler_t *)sigfunc != SIG_IGN)) { - if ((sa_flags & SA_SIGINFO) != 0 || info == NULL) - (*(sigfunc))(sig, info, ucp); - else { - ((ohandler)(*sigfunc))( - sig, info->si_code, (struct sigcontext *)ucp, - info->si_addr, (__sighandler_t *)sigfunc); - } + shi.sigfunc = sigfunc; + shi.sig = sig; + shi.sa_flags = sig; + shi.info = info; + shi.ucp = ucp; + /* + * XXX Not ready for scope system thread, kernel bits + * should involve in + */ + if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0 && + (curthread->sigstk.ss_flags & SS_DISABLE) == 0) { + /* Deliver signal on alternative stack */ + if (sa_flags & SA_ONSTACK && !onstack) + handle_signal_altstack(curthread, &shi); + else + handle_signal(curthread, &shi); } else { - if ((__sighandler_t *)sigfunc == SIG_DFL) { - if (sigprop(sig) & SA_KILL) { - if (_kse_isthreaded()) - kse_thr_interrupt(NULL, - KSE_INTR_SIGEXIT, sig); - else - kill(getpid(), sig); - } -#ifdef NOTYET - else if (sigprop(sig) & SA_STOP) - kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig); -#endif - } + handle_signal(curthread, &shi); } _kse_critical_enter(); @@ -488,6 +501,89 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread); } +static void +handle_signal(struct pthread *curthread, struct sighandle_info *shi) +{ + _kse_critical_leave(&curthread->tcb->tcb_tmbx); + + if (((__sighandler_t *)shi->sigfunc != SIG_DFL) && + ((__sighandler_t *)shi->sigfunc != SIG_IGN)) { + if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL) + (*(shi->sigfunc))(shi->sig, shi->info, shi->ucp); + else { + ((ohandler)(*shi->sigfunc))( + shi->sig, shi->info->si_code, + (struct sigcontext *)shi->ucp, + shi->info->si_addr, + (__sighandler_t *)shi->sigfunc); + } + } else { + if ((__sighandler_t *)shi->sigfunc == SIG_DFL) { + if (sigprop(shi->sig) & SA_KILL) { + if (_kse_isthreaded()) + kse_thr_interrupt(NULL, + KSE_INTR_SIGEXIT, shi->sig); + else + kill(getpid(), shi->sig); + } +#ifdef NOTYET + else if (sigprop(shi->sig) & SA_STOP) + kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, + shi->sig); +#endif + } + } +} + +static void +handle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc, + struct sighandle_info *shi) +{ + shi->ucp->uc_stack.ss_flags = SS_ONSTACK; + handle_signal(curthread, shi); + if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) + setcontext(ret_uc); + else { + /* Work around for ia64, THR_SETCONTEXT does not work */ + _kse_critical_enter(); + curthread->tcb->tcb_tmbx.tm_context = *ret_uc; + _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1); + /* THR_SETCONTEXT */ + } +} + +/* + * Jump to stack set by sigaltstack before invoking signal handler + */ +static void +handle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi) +{ + volatile int once; + ucontext_t uc1, *uc2; + + THR_ASSERT(_kse_in_critical(), "Not in critical"); + + once = 0; + THR_GETCONTEXT(&uc1); + if (once == 0) { + once = 1; + /* XXX + * We are still in critical region, it is safe to operate thread + * context + */ + uc2 = &curthread->tcb->tcb_tmbx.tm_context; + uc2->uc_stack = curthread->sigstk; + makecontext(uc2, (void (*)(void))handle_signal_wrapper, + 3, curthread, &uc1, shi); + if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) + setcontext(uc2); + else { + _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1); + /* THR_SETCONTEXT(uc2); */ + } + } +} + int _thr_getprocsig(int sig, siginfo_t *siginfo) { @@ -1144,12 +1240,14 @@ _thr_signal_init(void) PANIC("Cannot initialize signal handler"); } __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, NULL); + __sys_sigaltstack(NULL, &_thr_initial->sigstk); } void _thr_signal_deinit(void) { int i; + struct pthread *curthread = _get_curthread(); /* Enter a loop to get the existing signal status: */ for (i = 1; i <= _SIG_MAXSIG; i++) { @@ -1167,5 +1265,6 @@ _thr_signal_deinit(void) PANIC("Cannot set signal handler info"); } } + __sys_sigaltstack(&curthread->sigstk, NULL); } diff --git a/lib/libpthread/thread/thr_sigaltstack.c b/lib/libpthread/thread/thr_sigaltstack.c new file mode 100644 index 0000000..8a4a457 --- /dev/null +++ b/lib/libpthread/thread/thr_sigaltstack.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2003 David Xu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include "thr_private.h" + +__weak_reference(_sigaltstack, sigaltstack); + +int +_sigaltstack(stack_t *_ss, stack_t *_oss) +{ + struct pthread *curthread = _get_curthread(); + stack_t ss, oss; + int oonstack, errsave, ret; + kse_critical_t crit; + + if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { + crit = _kse_critical_enter(); + ret = __sys_sigaltstack(_ss, _oss); + errsave = errno; + /* Get a copy */ + if (ret == 0 && _ss != NULL) + curthread->sigstk = *_ss; + _kse_critical_leave(crit); + errno = errsave; + return (ret); + } + + if (_ss) + ss = *_ss; + if (_oss) + oss = *_oss; + + /* Should get and set stack in atomic way */ + crit = _kse_critical_enter(); + oonstack = _thr_sigonstack(&ss); + if (_oss != NULL) { + oss = curthread->sigstk; + oss.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE) + ? SS_DISABLE : ((oonstack) ? SS_ONSTACK : 0); + } + + if (_ss != NULL) { + if (oonstack) { + _kse_critical_leave(crit); + return (EPERM); + } + if ((ss.ss_flags & ~SS_DISABLE) != 0) { + _kse_critical_leave(crit); + return (EINVAL); + } + if (!(ss.ss_flags & SS_DISABLE)) { + if (ss.ss_size < MINSIGSTKSZ) { + _kse_critical_leave(crit); + return (ENOMEM); + } + curthread->sigstk = ss; + } else { + curthread->sigstk.ss_flags |= SS_DISABLE; + } + } + _kse_critical_leave(crit); + if (_oss != NULL) + *_oss = oss; + return (0); +} + +int +_thr_sigonstack(void *sp) +{ + struct pthread *curthread = _get_curthread(); + + return ((curthread->sigstk.ss_flags & SS_DISABLE) == 0 ? + (((size_t)sp - (size_t)curthread->sigstk.ss_sp) < curthread->sigstk.ss_size) + : 0); +} + -- cgit v1.1