diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc_r/uthread/pthread_private.h | 55 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_create.c | 8 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_init.c | 12 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_kern.c | 138 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_sig.c | 222 | ||||
-rw-r--r-- | lib/libkse/thread/thr_create.c | 8 | ||||
-rw-r--r-- | lib/libkse/thread/thr_init.c | 12 | ||||
-rw-r--r-- | lib/libkse/thread/thr_kern.c | 138 | ||||
-rw-r--r-- | lib/libkse/thread/thr_private.h | 55 | ||||
-rw-r--r-- | lib/libkse/thread/thr_sig.c | 222 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_create.c | 8 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_init.c | 12 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_kern.c | 138 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_private.h | 55 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_sig.c | 222 |
15 files changed, 501 insertions, 804 deletions
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h index 65661f7..c294693 100644 --- a/lib/libc_r/uthread/pthread_private.h +++ b/lib/libc_r/uthread/pthread_private.h @@ -603,38 +603,13 @@ struct pthread_state_data { struct join_status { struct pthread *thread; - int ret; + void *ret; int error; }; /* - * Normally thread contexts are stored as jmp_bufs via _setjmp()/_longjmp(), - * but they may also be sigjmp_buf and ucontext_t. When a thread is - * interrupted by a signal, it's context is saved as a ucontext_t. An - * application is also free to use [_]longjmp()/[_]siglongjmp() to jump - * between contexts within the same thread. Future support will also - * include setcontext()/getcontext(). - * - * Define an enumerated type that can identify the 4 different context - * types. - */ -typedef enum { - CTX_JB_NOSIG, /* context is jmp_buf without saved sigset */ - CTX_JB, /* context is jmp_buf (with saved sigset) */ - CTX_SJB, /* context is sigjmp_buf (with saved sigset) */ - CTX_UC /* context is ucontext_t (with saved sigset) */ -} thread_context_t; - -/* - * There are 2 basic contexts that a frame may contain at any - * one time: - * - * o ctx - The context that the thread should return to after normal - * completion of the signal handler. - * o sig_jb - The context just before the signal handler is invoked. - * Attempts at abnormal returns from user supplied signal handlers - * will return back to the signal context to perform any necessary - * cleanup. + * The frame that is added to the top of a threads stack when setting up + * up the thread to run a signal handler. */ struct pthread_signal_frame { /* @@ -643,19 +618,12 @@ struct pthread_signal_frame { struct pthread_state_data saved_state; /* - * Threads return context; ctxtype identifies the type of context. - * For signal frame 0, these point to the context storage area - * within the pthread structure. When handling signals (frame > 0), - * these point to a context storage area that is allocated off the - * threads stack. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; int signo; /* signal, arg 1 to sighandler */ int sig_has_args; /* use signal args if true */ ucontext_t uc; @@ -696,15 +664,12 @@ struct pthread { struct pthread_attr attr; /* - * Threads return context; ctxtype identifies the type of context. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; /* * Used for tracking delivery of signal handlers. @@ -1145,9 +1110,6 @@ 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 @@ -1257,11 +1219,12 @@ void _thread_kern_set_timeout(const struct timespec *); void _thread_kern_sig_defer(void); void _thread_kern_sig_undefer(void); void _thread_sig_handler(int, siginfo_t *, ucontext_t *); -void _thread_sig_check_pending(pthread_t pthread); +void _thread_sig_check_pending(struct pthread *pthread); void _thread_sig_handle_pending(void); -void _thread_sig_send(pthread_t pthread, int sig); +void _thread_sig_send(struct pthread *pthread, int sig); void _thread_sig_wrapper(void); -void _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf); +void _thread_sigframe_restore(struct pthread *thread, + struct pthread_signal_frame *psf); void _thread_start(void); void _thread_seterrno(pthread_t, int); int _thread_fd_table_init(int fd); diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c index 7c52b4b..70227ea 100644 --- a/lib/libc_r/uthread/uthread_create.c +++ b/lib/libc_r/uthread/uthread_create.c @@ -50,16 +50,11 @@ int _thread_next_offset = OFF(tle.tqe_next); int _thread_uniqueid_offset = OFF(uniqueid); int _thread_state_offset = OFF(state); int _thread_name_offset = OFF(name); -int _thread_ctxtype_offset = OFF(ctxtype); int _thread_ctx_offset = OFF(ctx); #undef OFF int _thread_PS_RUNNING_value = PS_RUNNING; int _thread_PS_DEAD_value = PS_DEAD; -int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG; -int _thread_CTX_JB_value = CTX_JB; -int _thread_CTX_SJB_value = CTX_SJB; -int _thread_CTX_UC_value = CTX_UC; __weak_reference(_pthread_create, pthread_create); @@ -148,9 +143,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, (long)new_thread->stack + pattr->stacksize_attr - sizeof(double)); - /* Initialize the rest of the frame: */ - new_thread->ctxtype = CTX_JB_NOSIG; - /* Copy the thread attributes: */ memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c index cac38dc..689e85b 100644 --- a/lib/libc_r/uthread/uthread_init.c +++ b/lib/libc_r/uthread/uthread_init.c @@ -334,7 +334,6 @@ _thread_init(void) /* Initialize the initial context: */ _thread_initial->curframe = NULL; - _thread_initial->ctxtype = CTX_JB_NOSIG; /* Initialise the rest of the fields: */ _thread_initial->poll_data.nfds = 0; @@ -360,17 +359,6 @@ _thread_init(void) /* Clear the signal queue: */ memset(_thread_sigq, 0, sizeof(_thread_sigq)); - /* - * 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) || - (__sys_sigaltstack(&_thread_sigstack, NULL) != 0)) - PANIC("Unable to install alternate signal stack"); - /* Enter a loop to get the existing signal status: */ for (i = 1; i < NSIG; i++) { /* Check for signals which cannot be trapped: */ diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c index ec4c233..a4cc3c3 100644 --- a/lib/libc_r/uthread/uthread_kern.c +++ b/lib/libc_r/uthread/uthread_kern.c @@ -100,7 +100,7 @@ _thread_kern_sched_frame(struct pthread_signal_frame *psf) void -_thread_kern_sched(ucontext_t *scp) +_thread_kern_sched(ucontext_t *ucp) { struct pthread *curthread = _get_curthread(); @@ -112,50 +112,61 @@ _thread_kern_sched(ucontext_t *scp) _thread_kern_in_sched = 1; /* Check if this function was called from the signal handler: */ - if (scp != NULL) { + if (ucp != NULL) { + /* XXX - Save FP registers? */ + FP_SAVE_UC(ucp); called_from_handler = 1; DBG_MSG("Entering scheduler due to signal\n"); - } else { - /* Save the state of the current thread: */ - if (_setjmp(curthread->ctx.jb) == 0) { - /* Flag the jump buffer was the last state saved: */ - curthread->ctxtype = CTX_JB_NOSIG; - curthread->longjmp_val = 1; - } else { - DBG_MSG("Returned from ___longjmp, thread %p\n", - curthread); - /* - * This point is reached when a longjmp() is called - * to restore the state of a thread. - * - * This is the normal way out of the scheduler. - */ - _thread_kern_in_sched = 0; + } - if (curthread->sig_defer_count == 0) { - if (((curthread->cancelflags & - PTHREAD_AT_CANCEL_POINT) == 0) && - ((curthread->cancelflags & - PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) - /* - * Cancellations override signals. - * - * Stick a cancellation point at the - * start of each async-cancellable - * thread's resumption. - * - * We allow threads woken at cancel - * points to do their own checks. - */ - pthread_testcancel(); - } + /* Save the state of the current thread: */ + if (_setjmp(curthread->ctx.jb) != 0) { + DBG_MSG("Returned from ___longjmp, thread %p\n", + curthread); + /* + * This point is reached when a longjmp() is called + * to restore the state of a thread. + * + * This is the normal way out of the scheduler. + */ + _thread_kern_in_sched = 0; - if (_sched_switch_hook != NULL) { - /* Run the installed switch hook: */ - thread_run_switch_hook(_last_user_thread, - curthread); - } + if (curthread->sig_defer_count == 0) { + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + /* + * Cancellations override signals. + * + * Stick a cancellation point at the + * start of each async-cancellable + * thread's resumption. + * + * We allow threads woken at cancel + * points to do their own checks. + */ + pthread_testcancel(); + } + + if (_sched_switch_hook != NULL) { + /* Run the installed switch hook: */ + thread_run_switch_hook(_last_user_thread, curthread); + } + if (ucp == NULL) return; + else { + /* XXX - Restore FP registers? */ + FP_RESTORE_UC(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); } } /* Switch to the thread scheduler: */ @@ -190,20 +201,12 @@ _thread_kern_scheduler(void) called_from_handler = 0; /* - * The signal handler should have saved the state of - * the current thread. Restore the process signal - * mask. + * We were called from a signal handler; restore the process + * signal mask. */ if (__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 (__sys_sigaltstack(&_thread_sigstack, NULL) != 0) - PANIC("Unable to restore alternate signal stack"); } /* @@ -581,42 +584,11 @@ _thread_kern_scheduler(void) /* * Continue the thread at its current frame: */ - switch(curthread->ctxtype) { - case CTX_JB_NOSIG: - ___longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_JB: - __longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_SJB: - __siglongjmp(curthread->ctx.sigjb, - curthread->longjmp_val); - break; - case CTX_UC: - /* XXX - Restore FP regsisters? */ - FP_RESTORE_UC(&curthread->ctx.uc); - - /* - * Do a sigreturn to restart the thread that - * was interrupted by a signal: - */ - _thread_kern_in_sched = 0; - #if NOT_YET - _setcontext(&curthread->ctx.uc); + _setcontext(&curthread->ctx.uc); #else - /* - * Ensure the process signal mask is set - * correctly: - */ - curthread->ctx.uc.uc_sigmask = - _process_sigmask; - __sys_sigreturn(&curthread->ctx.uc); + ___longjmp(curthread->ctx.jb, 1); #endif - break; - } /* This point should not be reached. */ PANIC("Thread has returned from sigreturn or longjmp"); } diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c index a05f914..1bd93b7 100644 --- a/lib/libc_r/uthread/uthread_sig.c +++ b/lib/libc_r/uthread/uthread_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; diff --git a/lib/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c index 7c52b4b..70227ea 100644 --- a/lib/libkse/thread/thr_create.c +++ b/lib/libkse/thread/thr_create.c @@ -50,16 +50,11 @@ int _thread_next_offset = OFF(tle.tqe_next); int _thread_uniqueid_offset = OFF(uniqueid); int _thread_state_offset = OFF(state); int _thread_name_offset = OFF(name); -int _thread_ctxtype_offset = OFF(ctxtype); int _thread_ctx_offset = OFF(ctx); #undef OFF int _thread_PS_RUNNING_value = PS_RUNNING; int _thread_PS_DEAD_value = PS_DEAD; -int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG; -int _thread_CTX_JB_value = CTX_JB; -int _thread_CTX_SJB_value = CTX_SJB; -int _thread_CTX_UC_value = CTX_UC; __weak_reference(_pthread_create, pthread_create); @@ -148,9 +143,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, (long)new_thread->stack + pattr->stacksize_attr - sizeof(double)); - /* Initialize the rest of the frame: */ - new_thread->ctxtype = CTX_JB_NOSIG; - /* Copy the thread attributes: */ memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c index cac38dc..689e85b 100644 --- a/lib/libkse/thread/thr_init.c +++ b/lib/libkse/thread/thr_init.c @@ -334,7 +334,6 @@ _thread_init(void) /* Initialize the initial context: */ _thread_initial->curframe = NULL; - _thread_initial->ctxtype = CTX_JB_NOSIG; /* Initialise the rest of the fields: */ _thread_initial->poll_data.nfds = 0; @@ -360,17 +359,6 @@ _thread_init(void) /* Clear the signal queue: */ memset(_thread_sigq, 0, sizeof(_thread_sigq)); - /* - * 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) || - (__sys_sigaltstack(&_thread_sigstack, NULL) != 0)) - PANIC("Unable to install alternate signal stack"); - /* Enter a loop to get the existing signal status: */ for (i = 1; i < NSIG; i++) { /* Check for signals which cannot be trapped: */ diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c index ec4c233..a4cc3c3 100644 --- a/lib/libkse/thread/thr_kern.c +++ b/lib/libkse/thread/thr_kern.c @@ -100,7 +100,7 @@ _thread_kern_sched_frame(struct pthread_signal_frame *psf) void -_thread_kern_sched(ucontext_t *scp) +_thread_kern_sched(ucontext_t *ucp) { struct pthread *curthread = _get_curthread(); @@ -112,50 +112,61 @@ _thread_kern_sched(ucontext_t *scp) _thread_kern_in_sched = 1; /* Check if this function was called from the signal handler: */ - if (scp != NULL) { + if (ucp != NULL) { + /* XXX - Save FP registers? */ + FP_SAVE_UC(ucp); called_from_handler = 1; DBG_MSG("Entering scheduler due to signal\n"); - } else { - /* Save the state of the current thread: */ - if (_setjmp(curthread->ctx.jb) == 0) { - /* Flag the jump buffer was the last state saved: */ - curthread->ctxtype = CTX_JB_NOSIG; - curthread->longjmp_val = 1; - } else { - DBG_MSG("Returned from ___longjmp, thread %p\n", - curthread); - /* - * This point is reached when a longjmp() is called - * to restore the state of a thread. - * - * This is the normal way out of the scheduler. - */ - _thread_kern_in_sched = 0; + } - if (curthread->sig_defer_count == 0) { - if (((curthread->cancelflags & - PTHREAD_AT_CANCEL_POINT) == 0) && - ((curthread->cancelflags & - PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) - /* - * Cancellations override signals. - * - * Stick a cancellation point at the - * start of each async-cancellable - * thread's resumption. - * - * We allow threads woken at cancel - * points to do their own checks. - */ - pthread_testcancel(); - } + /* Save the state of the current thread: */ + if (_setjmp(curthread->ctx.jb) != 0) { + DBG_MSG("Returned from ___longjmp, thread %p\n", + curthread); + /* + * This point is reached when a longjmp() is called + * to restore the state of a thread. + * + * This is the normal way out of the scheduler. + */ + _thread_kern_in_sched = 0; - if (_sched_switch_hook != NULL) { - /* Run the installed switch hook: */ - thread_run_switch_hook(_last_user_thread, - curthread); - } + if (curthread->sig_defer_count == 0) { + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + /* + * Cancellations override signals. + * + * Stick a cancellation point at the + * start of each async-cancellable + * thread's resumption. + * + * We allow threads woken at cancel + * points to do their own checks. + */ + pthread_testcancel(); + } + + if (_sched_switch_hook != NULL) { + /* Run the installed switch hook: */ + thread_run_switch_hook(_last_user_thread, curthread); + } + if (ucp == NULL) return; + else { + /* XXX - Restore FP registers? */ + FP_RESTORE_UC(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); } } /* Switch to the thread scheduler: */ @@ -190,20 +201,12 @@ _thread_kern_scheduler(void) called_from_handler = 0; /* - * The signal handler should have saved the state of - * the current thread. Restore the process signal - * mask. + * We were called from a signal handler; restore the process + * signal mask. */ if (__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 (__sys_sigaltstack(&_thread_sigstack, NULL) != 0) - PANIC("Unable to restore alternate signal stack"); } /* @@ -581,42 +584,11 @@ _thread_kern_scheduler(void) /* * Continue the thread at its current frame: */ - switch(curthread->ctxtype) { - case CTX_JB_NOSIG: - ___longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_JB: - __longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_SJB: - __siglongjmp(curthread->ctx.sigjb, - curthread->longjmp_val); - break; - case CTX_UC: - /* XXX - Restore FP regsisters? */ - FP_RESTORE_UC(&curthread->ctx.uc); - - /* - * Do a sigreturn to restart the thread that - * was interrupted by a signal: - */ - _thread_kern_in_sched = 0; - #if NOT_YET - _setcontext(&curthread->ctx.uc); + _setcontext(&curthread->ctx.uc); #else - /* - * Ensure the process signal mask is set - * correctly: - */ - curthread->ctx.uc.uc_sigmask = - _process_sigmask; - __sys_sigreturn(&curthread->ctx.uc); + ___longjmp(curthread->ctx.jb, 1); #endif - break; - } /* This point should not be reached. */ PANIC("Thread has returned from sigreturn or longjmp"); } diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h index 65661f7..c294693 100644 --- a/lib/libkse/thread/thr_private.h +++ b/lib/libkse/thread/thr_private.h @@ -603,38 +603,13 @@ struct pthread_state_data { struct join_status { struct pthread *thread; - int ret; + void *ret; int error; }; /* - * Normally thread contexts are stored as jmp_bufs via _setjmp()/_longjmp(), - * but they may also be sigjmp_buf and ucontext_t. When a thread is - * interrupted by a signal, it's context is saved as a ucontext_t. An - * application is also free to use [_]longjmp()/[_]siglongjmp() to jump - * between contexts within the same thread. Future support will also - * include setcontext()/getcontext(). - * - * Define an enumerated type that can identify the 4 different context - * types. - */ -typedef enum { - CTX_JB_NOSIG, /* context is jmp_buf without saved sigset */ - CTX_JB, /* context is jmp_buf (with saved sigset) */ - CTX_SJB, /* context is sigjmp_buf (with saved sigset) */ - CTX_UC /* context is ucontext_t (with saved sigset) */ -} thread_context_t; - -/* - * There are 2 basic contexts that a frame may contain at any - * one time: - * - * o ctx - The context that the thread should return to after normal - * completion of the signal handler. - * o sig_jb - The context just before the signal handler is invoked. - * Attempts at abnormal returns from user supplied signal handlers - * will return back to the signal context to perform any necessary - * cleanup. + * The frame that is added to the top of a threads stack when setting up + * up the thread to run a signal handler. */ struct pthread_signal_frame { /* @@ -643,19 +618,12 @@ struct pthread_signal_frame { struct pthread_state_data saved_state; /* - * Threads return context; ctxtype identifies the type of context. - * For signal frame 0, these point to the context storage area - * within the pthread structure. When handling signals (frame > 0), - * these point to a context storage area that is allocated off the - * threads stack. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; int signo; /* signal, arg 1 to sighandler */ int sig_has_args; /* use signal args if true */ ucontext_t uc; @@ -696,15 +664,12 @@ struct pthread { struct pthread_attr attr; /* - * Threads return context; ctxtype identifies the type of context. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; /* * Used for tracking delivery of signal handlers. @@ -1145,9 +1110,6 @@ 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 @@ -1257,11 +1219,12 @@ void _thread_kern_set_timeout(const struct timespec *); void _thread_kern_sig_defer(void); void _thread_kern_sig_undefer(void); void _thread_sig_handler(int, siginfo_t *, ucontext_t *); -void _thread_sig_check_pending(pthread_t pthread); +void _thread_sig_check_pending(struct pthread *pthread); void _thread_sig_handle_pending(void); -void _thread_sig_send(pthread_t pthread, int sig); +void _thread_sig_send(struct pthread *pthread, int sig); void _thread_sig_wrapper(void); -void _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf); +void _thread_sigframe_restore(struct pthread *thread, + struct pthread_signal_frame *psf); void _thread_start(void); void _thread_seterrno(pthread_t, int); int _thread_fd_table_init(int fd); diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c index a05f914..1bd93b7 100644 --- a/lib/libkse/thread/thr_sig.c +++ b/lib/libkse/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; diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c index 7c52b4b..70227ea 100644 --- a/lib/libpthread/thread/thr_create.c +++ b/lib/libpthread/thread/thr_create.c @@ -50,16 +50,11 @@ int _thread_next_offset = OFF(tle.tqe_next); int _thread_uniqueid_offset = OFF(uniqueid); int _thread_state_offset = OFF(state); int _thread_name_offset = OFF(name); -int _thread_ctxtype_offset = OFF(ctxtype); int _thread_ctx_offset = OFF(ctx); #undef OFF int _thread_PS_RUNNING_value = PS_RUNNING; int _thread_PS_DEAD_value = PS_DEAD; -int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG; -int _thread_CTX_JB_value = CTX_JB; -int _thread_CTX_SJB_value = CTX_SJB; -int _thread_CTX_UC_value = CTX_UC; __weak_reference(_pthread_create, pthread_create); @@ -148,9 +143,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, (long)new_thread->stack + pattr->stacksize_attr - sizeof(double)); - /* Initialize the rest of the frame: */ - new_thread->ctxtype = CTX_JB_NOSIG; - /* Copy the thread attributes: */ memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c index cac38dc..689e85b 100644 --- a/lib/libpthread/thread/thr_init.c +++ b/lib/libpthread/thread/thr_init.c @@ -334,7 +334,6 @@ _thread_init(void) /* Initialize the initial context: */ _thread_initial->curframe = NULL; - _thread_initial->ctxtype = CTX_JB_NOSIG; /* Initialise the rest of the fields: */ _thread_initial->poll_data.nfds = 0; @@ -360,17 +359,6 @@ _thread_init(void) /* Clear the signal queue: */ memset(_thread_sigq, 0, sizeof(_thread_sigq)); - /* - * 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) || - (__sys_sigaltstack(&_thread_sigstack, NULL) != 0)) - PANIC("Unable to install alternate signal stack"); - /* Enter a loop to get the existing signal status: */ for (i = 1; i < NSIG; i++) { /* Check for signals which cannot be trapped: */ diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index ec4c233..a4cc3c3 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -100,7 +100,7 @@ _thread_kern_sched_frame(struct pthread_signal_frame *psf) void -_thread_kern_sched(ucontext_t *scp) +_thread_kern_sched(ucontext_t *ucp) { struct pthread *curthread = _get_curthread(); @@ -112,50 +112,61 @@ _thread_kern_sched(ucontext_t *scp) _thread_kern_in_sched = 1; /* Check if this function was called from the signal handler: */ - if (scp != NULL) { + if (ucp != NULL) { + /* XXX - Save FP registers? */ + FP_SAVE_UC(ucp); called_from_handler = 1; DBG_MSG("Entering scheduler due to signal\n"); - } else { - /* Save the state of the current thread: */ - if (_setjmp(curthread->ctx.jb) == 0) { - /* Flag the jump buffer was the last state saved: */ - curthread->ctxtype = CTX_JB_NOSIG; - curthread->longjmp_val = 1; - } else { - DBG_MSG("Returned from ___longjmp, thread %p\n", - curthread); - /* - * This point is reached when a longjmp() is called - * to restore the state of a thread. - * - * This is the normal way out of the scheduler. - */ - _thread_kern_in_sched = 0; + } - if (curthread->sig_defer_count == 0) { - if (((curthread->cancelflags & - PTHREAD_AT_CANCEL_POINT) == 0) && - ((curthread->cancelflags & - PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) - /* - * Cancellations override signals. - * - * Stick a cancellation point at the - * start of each async-cancellable - * thread's resumption. - * - * We allow threads woken at cancel - * points to do their own checks. - */ - pthread_testcancel(); - } + /* Save the state of the current thread: */ + if (_setjmp(curthread->ctx.jb) != 0) { + DBG_MSG("Returned from ___longjmp, thread %p\n", + curthread); + /* + * This point is reached when a longjmp() is called + * to restore the state of a thread. + * + * This is the normal way out of the scheduler. + */ + _thread_kern_in_sched = 0; - if (_sched_switch_hook != NULL) { - /* Run the installed switch hook: */ - thread_run_switch_hook(_last_user_thread, - curthread); - } + if (curthread->sig_defer_count == 0) { + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + /* + * Cancellations override signals. + * + * Stick a cancellation point at the + * start of each async-cancellable + * thread's resumption. + * + * We allow threads woken at cancel + * points to do their own checks. + */ + pthread_testcancel(); + } + + if (_sched_switch_hook != NULL) { + /* Run the installed switch hook: */ + thread_run_switch_hook(_last_user_thread, curthread); + } + if (ucp == NULL) return; + else { + /* XXX - Restore FP registers? */ + FP_RESTORE_UC(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); } } /* Switch to the thread scheduler: */ @@ -190,20 +201,12 @@ _thread_kern_scheduler(void) called_from_handler = 0; /* - * The signal handler should have saved the state of - * the current thread. Restore the process signal - * mask. + * We were called from a signal handler; restore the process + * signal mask. */ if (__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 (__sys_sigaltstack(&_thread_sigstack, NULL) != 0) - PANIC("Unable to restore alternate signal stack"); } /* @@ -581,42 +584,11 @@ _thread_kern_scheduler(void) /* * Continue the thread at its current frame: */ - switch(curthread->ctxtype) { - case CTX_JB_NOSIG: - ___longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_JB: - __longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_SJB: - __siglongjmp(curthread->ctx.sigjb, - curthread->longjmp_val); - break; - case CTX_UC: - /* XXX - Restore FP regsisters? */ - FP_RESTORE_UC(&curthread->ctx.uc); - - /* - * Do a sigreturn to restart the thread that - * was interrupted by a signal: - */ - _thread_kern_in_sched = 0; - #if NOT_YET - _setcontext(&curthread->ctx.uc); + _setcontext(&curthread->ctx.uc); #else - /* - * Ensure the process signal mask is set - * correctly: - */ - curthread->ctx.uc.uc_sigmask = - _process_sigmask; - __sys_sigreturn(&curthread->ctx.uc); + ___longjmp(curthread->ctx.jb, 1); #endif - break; - } /* This point should not be reached. */ PANIC("Thread has returned from sigreturn or longjmp"); } diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index 65661f7..c294693 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -603,38 +603,13 @@ struct pthread_state_data { struct join_status { struct pthread *thread; - int ret; + void *ret; int error; }; /* - * Normally thread contexts are stored as jmp_bufs via _setjmp()/_longjmp(), - * but they may also be sigjmp_buf and ucontext_t. When a thread is - * interrupted by a signal, it's context is saved as a ucontext_t. An - * application is also free to use [_]longjmp()/[_]siglongjmp() to jump - * between contexts within the same thread. Future support will also - * include setcontext()/getcontext(). - * - * Define an enumerated type that can identify the 4 different context - * types. - */ -typedef enum { - CTX_JB_NOSIG, /* context is jmp_buf without saved sigset */ - CTX_JB, /* context is jmp_buf (with saved sigset) */ - CTX_SJB, /* context is sigjmp_buf (with saved sigset) */ - CTX_UC /* context is ucontext_t (with saved sigset) */ -} thread_context_t; - -/* - * There are 2 basic contexts that a frame may contain at any - * one time: - * - * o ctx - The context that the thread should return to after normal - * completion of the signal handler. - * o sig_jb - The context just before the signal handler is invoked. - * Attempts at abnormal returns from user supplied signal handlers - * will return back to the signal context to perform any necessary - * cleanup. + * The frame that is added to the top of a threads stack when setting up + * up the thread to run a signal handler. */ struct pthread_signal_frame { /* @@ -643,19 +618,12 @@ struct pthread_signal_frame { struct pthread_state_data saved_state; /* - * Threads return context; ctxtype identifies the type of context. - * For signal frame 0, these point to the context storage area - * within the pthread structure. When handling signals (frame > 0), - * these point to a context storage area that is allocated off the - * threads stack. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; int signo; /* signal, arg 1 to sighandler */ int sig_has_args; /* use signal args if true */ ucontext_t uc; @@ -696,15 +664,12 @@ struct pthread { struct pthread_attr attr; /* - * Threads return context; ctxtype identifies the type of context. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; /* * Used for tracking delivery of signal handlers. @@ -1145,9 +1110,6 @@ 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 @@ -1257,11 +1219,12 @@ void _thread_kern_set_timeout(const struct timespec *); void _thread_kern_sig_defer(void); void _thread_kern_sig_undefer(void); void _thread_sig_handler(int, siginfo_t *, ucontext_t *); -void _thread_sig_check_pending(pthread_t pthread); +void _thread_sig_check_pending(struct pthread *pthread); void _thread_sig_handle_pending(void); -void _thread_sig_send(pthread_t pthread, int sig); +void _thread_sig_send(struct pthread *pthread, int sig); void _thread_sig_wrapper(void); -void _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf); +void _thread_sigframe_restore(struct pthread *thread, + struct pthread_signal_frame *psf); void _thread_start(void); void _thread_seterrno(pthread_t, int); int _thread_fd_table_init(int fd); 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; |