summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/thread/thr_sig.c
diff options
context:
space:
mode:
authordeischen <deischen@FreeBSD.org>2002-02-09 19:58:41 +0000
committerdeischen <deischen@FreeBSD.org>2002-02-09 19:58:41 +0000
commit4ed9f7fd062cd8c757f7325cad3bc2ea2c340e84 (patch)
treedc39d813fe8f056c1b1cfa1a5216fba9998c6103 /lib/libpthread/thread/thr_sig.c
parent04de78234927ede2f34f9b1286fb8344dafa63fc (diff)
downloadFreeBSD-src-4ed9f7fd062cd8c757f7325cad3bc2ea2c340e84.zip
FreeBSD-src-4ed9f7fd062cd8c757f7325cad3bc2ea2c340e84.tar.gz
This has been sitting in my local tree long enough. Remove the use
of an alternate signal stack for handling signals. Let the kernel send signals on the stack of the current thread and teach the threads signal handler how to deliver signals to the current thread if it needs to. Also, always store a threads context as a jmp_buf. Eventually this will change to be a ucontext_t or mcontext_t. Other small nits. Use struct pthread * instead of pthread_t in internal library routines. The threads code wants struct pthread *, and pthread_t doesn't necessarily have to be the same. Reviewed by: jasone
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