Index: pthread.map =================================================================== RCS file: /home/ncvs/src/lib/libpthread/pthread.map,v retrieving revision 1.8 diff -u -r1.8 pthread.map --- pthread.map 9 Dec 2003 15:16:27 -0000 1.8 +++ pthread.map 28 Dec 2003 23:13:09 -0000 @@ -154,6 +154,7 @@ _sem_unlink; _sem_wait; _sigaction; + _sigaltstack; _sigpending; _sigprocmask; _sigsuspend; @@ -308,6 +309,7 @@ sem_unlink; sem_wait; sigaction; + sigaltstack; sigpending; sigprocmask; sigsuspend; Index: thread/Makefile.inc =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/Makefile.inc,v retrieving revision 1.46 diff -u -r1.46 Makefile.inc --- thread/Makefile.inc 9 Dec 2003 15:16:27 -0000 1.46 +++ thread/Makefile.inc 28 Dec 2003 23:13:09 -0000 @@ -89,6 +89,7 @@ thr_setschedparam.c \ thr_sig.c \ thr_sigaction.c \ + thr_sigaltstack.c \ thr_sigmask.c \ thr_sigpending.c \ thr_sigprocmask.c \ Index: thread/thr_create.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_create.c,v retrieving revision 1.51 diff -u -r1.51 thr_create.c --- thread/thr_create.c 14 Sep 2003 22:52:16 -0000 1.51 +++ thread/thr_create.c 28 Dec 2003 23:13:09 -0000 @@ -252,6 +252,9 @@ 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; Index: thread/thr_private.h =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_private.h,v retrieving revision 1.110 diff -u -r1.110 thr_private.h --- thread/thr_private.h 19 Dec 2003 12:57:08 -0000 1.110 +++ thread/thr_private.h 28 Dec 2003 23:13:10 -0000 @@ -798,6 +798,9 @@ struct pthread_specific_elem *specific; int specific_data_count; + /* Alternative stack for sigaltstack() */ + stack_t sigstk; + /* * Current locks bitmap for rtld. */ @@ -1154,6 +1157,7 @@ void _thr_hash_remove(struct pthread *); struct pthread *_thr_hash_find(struct pthread *); void _thr_finish_cancellation(void *arg); +int _thr_sigonstack(void *sp); /* * Aliases for _pthread functions. Should be called instead of Index: thread/thr_sig.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_sig.c,v retrieving revision 1.74 diff -u -r1.74 thr_sig.c --- thread/thr_sig.c 28 Dec 2003 12:20:04 -0000 1.74 +++ thread/thr_sig.c 28 Dec 2003 23:13:10 -0000 @@ -399,16 +399,31 @@ 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 @@ */ 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,70 @@ 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); + THR_SETCONTEXT(ret_uc); +} + +/* + * 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; + + once = 0; + THR_GETCONTEXT(&uc1); + if (once == 0) { + once = 1; + uc2 = uc1; /* Copy stupid i386 version of mc_len */ + uc2.uc_stack = curthread->sigstk; + makecontext(&uc2, (void (*)(void))handle_signal_wrapper, + 4, curthread, &uc1, shi); + THR_SETCONTEXT(&uc2); + } +} + int _thr_getprocsig(int sig, siginfo_t *siginfo) { @@ -1144,12 +1221,14 @@ 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 +1246,6 @@ PANIC("Cannot set signal handler info"); } } + __sys_sigaltstack(&curthread->sigstk, NULL); } --- /dev/null Mon Dec 29 07:22:00 2003 +++ thread/thr_sigaltstack.c Sun Dec 28 23:28:49 2003 @@ -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); +} +