diff options
author | davidxu <davidxu@FreeBSD.org> | 2003-12-29 23:21:09 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2003-12-29 23:21:09 +0000 |
commit | 8d750bfb1bf0228b6e58e834f4842c7080398d13 (patch) | |
tree | e2ab7b024b94d440af7be0888fe6e9a4498d59b5 /lib/libpthread/thread/thr_sig.c | |
parent | 2d0145273e128a3db5439ade8d7f54ab879fffef (diff) | |
download | FreeBSD-src-8d750bfb1bf0228b6e58e834f4842c7080398d13.zip FreeBSD-src-8d750bfb1bf0228b6e58e834f4842c7080398d13.tar.gz |
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
Diffstat (limited to 'lib/libpthread/thread/thr_sig.c')
-rw-r--r-- | lib/libpthread/thread/thr_sig.c | 147 |
1 files changed, 123 insertions, 24 deletions
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); } |