summaryrefslogtreecommitdiff
path: root/libpthread/linuxthreads/signals.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/linuxthreads/signals.c')
-rw-r--r--libpthread/linuxthreads/signals.c137
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)