summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/thread/thr_sig.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/thread/thr_sig.c')
-rw-r--r--lib/libpthread/thread/thr_sig.c222
1 files changed, 103 insertions, 119 deletions
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index a05f914..1bd93b7 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -43,13 +43,16 @@
#include "pthread_private.h"
/* Prototypes: */
-static void thread_sig_add(pthread_t pthread, int sig, int has_args);
-static void thread_sig_check_state(pthread_t pthread, int sig);
-static pthread_t thread_sig_find(int sig);
+static void thread_sig_add(struct pthread *pthread, int sig, int has_args);
+static void thread_sig_check_state(struct pthread *pthread, int sig);
+static struct pthread *thread_sig_find(int sig);
static void thread_sig_handle_special(int sig);
-static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp);
-static void thread_sigframe_add(pthread_t thread, int sig, int has_args);
-static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf);
+static void thread_sigframe_add(struct pthread *thread, int sig,
+ int has_args);
+static void thread_sigframe_save(struct pthread *thread,
+ struct pthread_signal_frame *psf);
+static void thread_sig_invoke_handler(int sig, siginfo_t *info,
+ ucontext_t *ucp);
/* #define DEBUG_SIGNAL */
#ifdef DEBUG_SIGNAL
@@ -70,23 +73,14 @@ void
_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
{
struct pthread *curthread = _get_curthread();
- pthread_t pthread, pthread_h;
- void *stackp;
- int in_sched = 0;
+ struct pthread *pthread, *pthread_h;
+ int in_sched = _thread_kern_in_sched;
char c;
if (ucp == NULL)
PANIC("Thread signal handler received null context");
DBG_MSG("Got signal %d, current thread %p\n", sig, curthread);
- if (_thread_kern_in_sched != 0)
- in_sched = 1;
- else {
- stackp = (void *)GET_STACK_UC(ucp);
- if ((stackp >= _thread_kern_sched_stack) &&
- (stackp <= _thread_kern_sched_stack + SCHED_STACK_SIZE))
- in_sched = 1;
- }
/* Check if an interval timer signal: */
if (sig == _SCHED_SIGNAL) {
/* Update the scheduling clock: */
@@ -107,16 +101,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
else if (curthread->sig_defer_count > 0)
curthread->yield_on_sig_undefer = 1;
else {
- /*
- * Save the context of the currently running thread:
- */
- thread_sig_savecontext(curthread, ucp);
-
- /*
- * Schedule the next thread. This function is not
- * expected to return because it will do a longjmp
- * instead.
- */
+ /* Schedule the next thread: */
_thread_kern_sched(ucp);
/*
@@ -210,18 +195,30 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
thread_sig_handle_special(sig);
pthread_h = NULL;
- if ((pthread = thread_sig_find(sig)) != NULL) {
- DBG_MSG("Got signal %d, adding frame to thread %p\n",
- sig, pthread);
+ if ((pthread = thread_sig_find(sig)) == NULL)
+ DBG_MSG("No thread to handle signal %d\n", sig);
+ else if (pthread == curthread) {
/*
- * A thread was found that can handle the signal.
- * Save the context of the currently running thread
- * so that we can switch to another thread without
- * losing track of where the current thread left off.
- * This also applies if the current thread is the
- * thread to be signaled.
+ * Unblock the signal and restore the process signal
+ * mask in case we don't return from the handler:
*/
- thread_sig_savecontext(curthread, ucp);
+ _thread_sigq[sig - 1].blocked = 0;
+ __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL);
+
+ /* Call the signal handler for the current thread: */
+ thread_sig_invoke_handler(sig, info, ucp);
+
+ /*
+ * Set the process signal mask in the context; it
+ * could have changed by the handler.
+ */
+ ucp->uc_sigmask = _process_sigmask;
+
+ /* Resume the interrupted thread: */
+ __sys_sigreturn(ucp);
+ } else {
+ DBG_MSG("Got signal %d, adding frame to thread %p\n",
+ sig, pthread);
/* Setup the target thread to receive the signal: */
thread_sig_add(pthread, sig, /*has_args*/ 1);
@@ -231,8 +228,6 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
DBG_MSG("Finished adding frame, head of prio list %p\n",
pthread_h);
}
- else
- DBG_MSG("No thread to handle signal %d\n", sig);
SIG_SET_INACTIVE();
/*
@@ -241,8 +236,8 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* signal and the currently running thread is not in a
* signal handler.
*/
- if ((pthread == curthread) || ((pthread_h != NULL) &&
- (pthread_h->active_priority > curthread->active_priority))) {
+ if ((pthread_h != NULL) &&
+ (pthread_h->active_priority > curthread->active_priority)) {
/* Enter the kernel scheduler: */
_thread_kern_sched(ucp);
}
@@ -255,27 +250,57 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
}
static void
-thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp)
-{
- memcpy(&pthread->ctx.uc, ucp, sizeof(*ucp));
-
- /* XXX - Save FP registers too? */
- FP_SAVE_UC(&pthread->ctx.uc);
+thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+ {
+ struct pthread *curthread = _get_curthread();
+ void (*sigfunc)(int, siginfo_t *, void *);
+ int saved_seqno;
+ sigset_t saved_sigmask;
- /* Mark the context saved as a ucontext: */
- pthread->ctxtype = CTX_UC;
+ /* Invoke the signal handler without going through the scheduler:
+ */
+ DBG_MSG("Got signal %d, calling handler for current thread %p\n",
+ sig, curthread);
+
+ /* Save the threads signal mask: */
+ saved_sigmask = curthread->sigmask;
+ saved_seqno = curthread->sigmask_seqno;
+
+ /* Setup the threads signal mask: */
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&curthread->sigmask, sig);
+
+ /*
+ * Check that a custom handler is installed and if
+ * the signal is not blocked:
+ */
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ if (((__sighandler_t *)sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)sigfunc != SIG_IGN)) {
+ if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
+ (info == NULL))
+ (*(sigfunc))(sig, info, ucp);
+ else
+ (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp);
+ }
+ /*
+ * Only restore the signal mask if it hasn't been changed by the
+ * application during invocation of the signal handler:
+ */
+ if (curthread->sigmask_seqno == saved_seqno)
+ curthread->sigmask = saved_sigmask;
}
/*
* Find a thread that can handle the signal.
*/
-pthread_t
+struct pthread *
thread_sig_find(int sig)
{
struct pthread *curthread = _get_curthread();
int handler_installed;
- pthread_t pthread, pthread_next;
- pthread_t suspended_thread, signaled_thread;
+ struct pthread *pthread, *pthread_next;
+ struct pthread *suspended_thread, *signaled_thread;
DBG_MSG("Looking for thread to handle signal %d\n", sig);
/* Check if the signal requires a dump of thread information: */
@@ -416,7 +441,7 @@ thread_sig_find(int sig)
}
void
-_thread_sig_check_pending(pthread_t pthread)
+_thread_sig_check_pending(struct pthread *pthread)
{
sigset_t sigset;
int i;
@@ -452,7 +477,7 @@ _thread_sig_check_pending(pthread_t pthread)
void
_thread_sig_handle_pending(void)
{
- pthread_t pthread;
+ struct pthread *pthread;
int i, sig;
PTHREAD_ASSERT(_thread_kern_in_sched != 0,
@@ -493,7 +518,7 @@ _thread_sig_handle_pending(void)
static void
thread_sig_handle_special(int sig)
{
- pthread_t pthread, pthread_next;
+ struct pthread *pthread, *pthread_next;
int i;
switch (sig) {
@@ -567,7 +592,7 @@ thread_sig_handle_special(int sig)
* unmasked.
*/
static void
-thread_sig_add(pthread_t pthread, int sig, int has_args)
+thread_sig_add(struct pthread *pthread, int sig, int has_args)
{
int restart;
int suppress_handler = 0;
@@ -775,7 +800,7 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
}
static void
-thread_sig_check_state(pthread_t pthread, int sig)
+thread_sig_check_state(struct pthread *pthread, int sig)
{
/*
* Process according to thread state:
@@ -865,7 +890,7 @@ thread_sig_check_state(pthread_t pthread, int sig)
* Send a signal to a specific thread (ala pthread_kill):
*/
void
-_thread_sig_send(pthread_t pthread, int sig)
+_thread_sig_send(struct pthread *pthread, int sig)
{
struct pthread *curthread = _get_curthread();
@@ -898,17 +923,13 @@ _thread_sig_send(pthread_t pthread, int sig)
/* Return the signal number: */
pthread->signo = sig;
- } else if (pthread == curthread) {
+ } else if (sigismember(&pthread->sigmask, sig))
/* Add the signal to the pending set: */
sigaddset(&pthread->sigpend, sig);
- if (!sigismember(&pthread->sigmask, sig)) {
- /*
- * Call the kernel scheduler which will safely
- * install a signal frame for this thread:
- */
- _thread_kern_sched_sig();
- }
- } else if (!sigismember(&pthread->sigmask, sig)) {
+ else if (pthread == curthread)
+ /* Call the signal handler for the current thread: */
+ thread_sig_invoke_handler(sig, NULL, NULL);
+ else {
/* Protect the scheduling queues: */
_thread_kern_sig_defer();
/*
@@ -918,9 +939,6 @@ _thread_sig_send(pthread_t pthread, int sig)
thread_sig_add(pthread, sig, /* has args */ 0);
/* Unprotect the scheduling queues: */
_thread_kern_sig_undefer();
- } else {
- /* Increment the pending signal count. */
- sigaddset(&pthread->sigpend,sig);
}
}
}
@@ -933,7 +951,6 @@ _thread_sig_send(pthread_t pthread, int sig)
void
_thread_sig_wrapper(void)
{
- void (*sigfunc)(int, siginfo_t *, void *);
struct pthread_signal_frame *psf;
struct pthread *thread = _get_curthread();
@@ -994,27 +1011,13 @@ _thread_sig_wrapper(void)
thread->sig_defer_count = 0;
/*
- * Check that a custom handler is installed and if the signal
- * is not blocked:
+ * Dispatch the signal via the custom signal handler:
*/
- sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction;
- if (((__sighandler_t *)sigfunc != SIG_DFL) &&
- ((__sighandler_t *)sigfunc != SIG_IGN)) {
- DBG_MSG("_thread_sig_wrapper: Calling signal handler for "
- "thread 0x%p\n", thread);
- /*
- * Dispatch the signal via the custom signal
- * handler:
- */
- if (psf->sig_has_args == 0)
- (*(sigfunc))(psf->signo, NULL, NULL);
- else if ((_thread_sigact[psf->signo - 1].sa_flags &
- SA_SIGINFO) != 0)
- (*(sigfunc))(psf->signo, &psf->siginfo, &psf->uc);
- else
- (*(sigfunc))(psf->signo,
- (siginfo_t *)psf->siginfo.si_code, &psf->uc);
- }
+ if (psf->sig_has_args == 0)
+ thread_sig_invoke_handler(psf->signo, NULL, NULL);
+ else
+ thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc);
+
/*
* Call the kernel scheduler to safely restore the frame and
* schedule the next thread:
@@ -1023,27 +1026,13 @@ _thread_sig_wrapper(void)
}
static void
-thread_sigframe_add(pthread_t thread, int sig, int has_args)
+thread_sigframe_add(struct pthread *thread, int sig, int has_args)
{
struct pthread_signal_frame *psf = NULL;
- unsigned long stackp = 0;
+ unsigned long stackp;
- /* Get the top of the threads stack: */
- switch (thread->ctxtype) {
- case CTX_JB:
- case CTX_JB_NOSIG:
- stackp = GET_STACK_JB(thread->ctx.jb);
- break;
- case CTX_SJB:
- stackp = GET_STACK_SJB(thread->ctx.sigjb);
- break;
- case CTX_UC:
- stackp = GET_STACK_UC(&thread->ctx.uc);
- break;
- default:
- PANIC("Invalid thread context type");
- break;
- }
+ /* Get the top of the threads stack: */
+ stackp = GET_STACK_JB(thread->ctx.jb);
/*
* Leave a little space on the stack and round down to the
@@ -1077,8 +1066,6 @@ thread_sigframe_add(pthread_t thread, int sig, int has_args)
/* Set up the new frame: */
thread->curframe = psf;
- thread->ctxtype = CTX_JB_NOSIG;
- thread->longjmp_val = 1;
thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
PTHREAD_FLAGS_IN_SYNCQ;
/*
@@ -1091,10 +1078,10 @@ thread_sigframe_add(pthread_t thread, int sig, int has_args)
}
void
-_thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
+_thread_sigframe_restore(struct pthread *thread,
+ struct pthread_signal_frame *psf)
{
- thread->ctxtype = psf->ctxtype;
- memcpy(&thread->ctx.uc, &psf->ctx.uc, sizeof(thread->ctx.uc));
+ memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx));
/*
* Only restore the signal mask if it hasn't been changed
* by the application during invocation of the signal handler:
@@ -1107,16 +1094,14 @@ _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
thread->state = psf->saved_state.psd_state;
thread->flags = psf->saved_state.psd_flags;
thread->interrupted = psf->saved_state.psd_interrupted;
- thread->longjmp_val = psf->saved_state.psd_longjmp_val;
thread->signo = psf->saved_state.psd_signo;
thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
}
static void
-thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf)
+thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf)
{
- psf->ctxtype = thread->ctxtype;
- memcpy(&psf->ctx.uc, &thread->ctx.uc, sizeof(thread->ctx.uc));
+ memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx));
psf->saved_state.psd_sigmask = thread->sigmask;
psf->saved_state.psd_curframe = thread->curframe;
psf->saved_state.psd_wakeup_time = thread->wakeup_time;
@@ -1125,7 +1110,6 @@ thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf)
psf->saved_state.psd_flags = thread->flags &
(PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
psf->saved_state.psd_interrupted = thread->interrupted;
- psf->saved_state.psd_longjmp_val = thread->longjmp_val;
psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
psf->saved_state.psd_signo = thread->signo;
psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
OpenPOWER on IntegriCloud