diff options
Diffstat (limited to 'libpthread/linuxthreads/signals.c')
-rw-r--r-- | libpthread/linuxthreads/signals.c | 137 |
1 files changed, 86 insertions, 51 deletions
diff --git a/libpthread/linuxthreads/signals.c b/libpthread/linuxthreads/signals.c index 672b8e4d9..d8dbc78bd 100644 --- a/libpthread/linuxthreads/signals.c +++ b/libpthread/linuxthreads/signals.c @@ -16,9 +16,11 @@ #include <errno.h> #include <signal.h> +#include <stdio.h> #include "pthread.h" #include "internals.h" #include "spinlock.h" +#include <bits/sigcontextinfo.h> int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask) { @@ -70,27 +72,75 @@ int pthread_kill(pthread_t thread, int signo) return 0; } -union sighandler __sighandler[NSIG] = - { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } }; +/* User-provided signal handlers */ +typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT)); +static union +{ + arch_sighandler_t old; + void (*rt) (int, struct siginfo *, struct ucontext *); +} sighandler[NSIG]; + +/* The wrapper around user-provided signal handlers */ +static void pthread_sighandler(int signo, SIGCONTEXT ctx) +{ + pthread_descr self = thread_self(); + char * in_sighandler; + /* If we're in a sigwait operation, just record the signal received + and return without calling the user's handler */ + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); + return; + } + /* Record that we're in a signal handler and call the user's + handler function */ + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); + sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} + +/* The same, this time for real-time signals. */ +static void pthread_sighandler_rt(int signo, struct siginfo *si, + struct ucontext *uc) +{ + pthread_descr self = thread_self(); + char * in_sighandler; + /* If we're in a sigwait operation, just record the signal received + and return without calling the user's handler */ + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); + return; + } + /* Record that we're in a signal handler and call the user's + handler function */ + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); + sighandler[signo].rt(signo, si, uc); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} /* The wrapper around sigaction. Install our own signal handler around the signal. */ -int __pthread_sigaction(int sig, const struct sigaction * act, - struct sigaction * oact) +libpthread_hidden_proto(sigaction) +int sigaction(int sig, const struct sigaction * act, + struct sigaction * oact) { struct sigaction newact; struct sigaction *newactp; - __sighandler_t old = SIG_DFL; +#ifdef DEBUG_PT +printf(__FUNCTION__": pthreads wrapper!\n"); +#endif if (sig == __pthread_sig_restart || sig == __pthread_sig_cancel || (sig == __pthread_sig_debug && __pthread_sig_debug > 0)) - { - __set_errno (EINVAL); - return -1; - } - if (sig > 0 && sig < NSIG) - old = (__sighandler_t) __sighandler[sig].old; + return EINVAL; if (act) { newact = *act; @@ -98,46 +148,39 @@ int __pthread_sigaction(int sig, const struct sigaction * act, && sig > 0 && sig < NSIG) { if (act->sa_flags & SA_SIGINFO) - newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt; + newact.sa_handler = (__sighandler_t) pthread_sighandler_rt; else - newact.sa_handler = (__sighandler_t) __pthread_sighandler; - if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR) - __sighandler[sig].old = (arch_sighandler_t) act->sa_handler; + newact.sa_handler = (__sighandler_t) pthread_sighandler; } newactp = &newact; } else newactp = NULL; if (__libc_sigaction(sig, newactp, oact) == -1) - { - if (act && (sig > 0 && sig < NSIG)) - __sighandler[sig].old = (arch_sighandler_t) old; - return -1; - } + return -1; +#ifdef DEBUG_PT +printf(__FUNCTION__": sighandler installed, sigaction successful\n"); +#endif if (sig > 0 && sig < NSIG) { - if (oact != NULL - /* We may have inherited SIG_IGN from the parent, so return the - kernel's idea of the signal handler the first time - through. */ - && old != SIG_ERR) - oact->sa_handler = old; + if (oact != NULL) + oact->sa_handler = (__sighandler_t) sighandler[sig].old; if (act) - /* For the assignment it does not matter whether it's a normal + /* For the assignment is does not matter whether it's a normal or real-time signal. */ - __sighandler[sig].old = (arch_sighandler_t) act->sa_handler; + sighandler[sig].old = (arch_sighandler_t) act->sa_handler; } return 0; } -#ifdef SHARED -strong_alias(__pthread_sigaction, __sigaction) -strong_alias(__pthread_sigaction, sigaction) -#endif +libpthread_hidden_def(sigaction) + +/* A signal handler that does nothing */ +static void pthread_null_sighandler(int sig attribute_unused) { } /* sigwait -- synchronously wait for a signal */ -int __pthread_sigwait(const sigset_t * set, int * sig) +int sigwait(const sigset_t * set, int * sig) { - __volatile__ pthread_descr self = thread_self(); + volatile pthread_descr self = thread_self(); sigset_t mask; int s; sigjmp_buf jmpbuf; @@ -151,18 +194,17 @@ int __pthread_sigwait(const sigset_t * set, int * sig) signals in set is unspecified." */ __sigfillset(&mask); sigdelset(&mask, __pthread_sig_cancel); - for (s = 1; s < NSIG; s++) { + for (s = 1; s <= NSIG; s++) { if (sigismember(set, s) && s != __pthread_sig_restart && s != __pthread_sig_cancel && s != __pthread_sig_debug) { sigdelset(&mask, s); - if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR || - __sighandler[s].old == (arch_sighandler_t) SIG_DFL || - __sighandler[s].old == (arch_sighandler_t) SIG_IGN) { - sa.sa_handler = __pthread_null_sighandler; - __sigfillset(&sa.sa_mask); - sa.sa_flags = 0; + if (sighandler[s].old == NULL || + sighandler[s].old == (arch_sighandler_t) SIG_DFL || + sighandler[s].old == (arch_sighandler_t) SIG_IGN) { + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = pthread_null_sighandler; sigaction(s, &sa, NULL); } } @@ -187,13 +229,11 @@ int __pthread_sigwait(const sigset_t * set, int * sig) *sig = THREAD_GETMEM(self, p_signal); return 0; } -#ifdef SHARED -strong_alias (__pthread_sigwait, sigwait) -#endif /* Redefine raise() to send signal to calling thread only, as per POSIX 1003.1c */ -int __pthread_raise (int sig) +libpthread_hidden_proto(raise) +int raise (int sig) { int retcode = pthread_kill(pthread_self(), sig); if (retcode == 0) @@ -203,9 +243,4 @@ int __pthread_raise (int sig) return -1; } } -#ifdef SHARED -strong_alias (__pthread_raise, raise) -#endif - -/* This files handles cancellation internally. */ -LIBC_CANCEL_HANDLED (); +libpthread_hidden_def(raise) |