diff options
Diffstat (limited to 'lib/libpthread')
-rw-r--r-- | lib/libpthread/thread/thr_init.c | 15 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_kern.c | 35 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_private.h | 5 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_sig.c | 2 |
4 files changed, 38 insertions, 19 deletions
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c index 35731c4..be671a1 100644 --- a/lib/libpthread/thread/thr_init.c +++ b/lib/libpthread/thread/thr_init.c @@ -92,7 +92,6 @@ _thread_init(void) int mib[2]; struct clockinfo clockinfo; struct sigaction act; - struct sigaltstack alt; /* Check if this function has already been called: */ if (_thread_initial) @@ -281,11 +280,15 @@ _thread_init(void) /* Clear the signal queue: */ memset(_thread_sigq, 0, sizeof(_thread_sigq)); - /* Create and install an alternate signal stack: */ - alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */ - alt.ss_size = SIGSTKSZ; - alt.ss_flags = 0; - if (_thread_sys_sigaltstack(&alt, NULL) != 0) + /* + * Create and install an alternate signal stack of + * the recommended size: + */ + _thread_sigstack.ss_sp = malloc(SIGSTKSZ); + _thread_sigstack.ss_size = SIGSTKSZ; + _thread_sigstack.ss_flags = 0; + if ((_thread_sigstack.ss_sp == NULL) || + (_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0)) PANIC("Unable to install alternate signal stack"); /* Enter a loop to get the existing signal status: */ diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index 4d92385..2b7b270 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -71,6 +71,7 @@ thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in); /* Static variables: */ static int last_tick = 0; +static int called_from_handler = 0; /* * This is called when a signal handler finishes and wants to @@ -106,20 +107,12 @@ _thread_kern_sched(ucontext_t *scp) /* Check if this function was called from the signal handler: */ if (scp != NULL) { - /* - * The signal handler should have saved the state of - * the current thread. Restore the process signal - * mask. - */ - if (_thread_sys_sigprocmask(SIG_SETMASK, - &_process_sigmask, NULL) != 0) - PANIC("Unable to restore process mask after signal"); + called_from_handler = 1; /* * We're running on the signal stack; just call the * kernel scheduler directly. */ DBG_MSG("Entering scheduler due to signal\n"); - _thread_kern_scheduler(); } else { /* Save the state of the current thread: */ if (_setjmp(_thread_run->ctx.jb) == 0) { @@ -162,9 +155,9 @@ _thread_kern_sched(ucontext_t *scp) } return; } - /* Switch to the thread scheduler: */ - ___longjmp(_thread_kern_sched_jb, 1); } + /* Switch to the thread scheduler: */ + ___longjmp(_thread_kern_sched_jb, 1); } void @@ -188,6 +181,26 @@ _thread_kern_scheduler(void) if ((_thread_run->flags & PTHREAD_FLAGS_PRIVATE) == 0) _last_user_thread = _thread_run; + if (called_from_handler != 0) { + called_from_handler = 0; + + /* + * The signal handler should have saved the state of + * the current thread. Restore the process signal + * mask. + */ + if (_thread_sys_sigprocmask(SIG_SETMASK, + &_process_sigmask, NULL) != 0) + PANIC("Unable to restore process mask after signal"); + + /* + * Since the signal handler didn't return normally, we + * have to tell the kernel to reuse the signal stack. + */ + if (_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0) + PANIC("Unable to restore alternate signal stack"); + } + /* Are there pending signals for this thread? */ if (_thread_run->check_pending != 0) { _thread_run->check_pending = 0; diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index e8fff12..9d6bc31 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -1127,6 +1127,9 @@ SCLASS volatile int _sigq_check_reqd #endif ; +/* The signal stack. */ +SCLASS struct sigaltstack _thread_sigstack; + /* Thread switch hook. */ SCLASS pthread_switch_routine_t _sched_switch_hook #ifdef GLOBAL_PTHREAD_PRIVATE @@ -1268,7 +1271,7 @@ int _thread_sys_sigsuspend(const sigset_t *); int _thread_sys_siginterrupt(int, int); int _thread_sys_sigpause(int); int _thread_sys_sigreturn(ucontext_t *); -int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *); +int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); int _thread_sys_sigstack(const struct sigstack *, struct sigstack *); int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *); void _thread_sys_psignal(unsigned int, const char *); diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index 3bcd9c1..3ac9740 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -1066,7 +1066,7 @@ thread_sigframe_add(pthread_t thread, int sig, int has_args) /* * Set up the context: */ - stackp += sizeof(double); + stackp -= sizeof(double); _setjmp(thread->ctx.jb); SET_STACK_JB(thread->ctx.jb, stackp); SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper); |