diff options
Diffstat (limited to 'lib/libc_r/uthread/uthread_sig.c')
-rw-r--r-- | lib/libc_r/uthread/uthread_sig.c | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c index 3617b36..b61e21c 100644 --- a/lib/libc_r/uthread/uthread_sig.c +++ b/lib/libc_r/uthread/uthread_sig.c @@ -53,7 +53,7 @@ static void thread_sigframe_add(struct pthread *thread, int sig, 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); + ucontext_t *ucp, int unblock); /*#define DEBUG_SIGNAL*/ #ifdef DEBUG_SIGNAL @@ -77,6 +77,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) struct pthread *pthread, *pthread_h; int in_sched = _thread_kern_in_sched; char c; + sigset_t sigset; if (ucp == NULL) PANIC("Thread signal handler received null context"); @@ -126,7 +127,14 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) * be ready to read when this signal handler returns. */ if (_queue_signals != 0) { - __sys_write(_thread_kern_pipe[1], &c, 1); + ssize_t wgot; + do { + wgot = __sys_write(_thread_kern_pipe[1], &c, + 1); + } while (wgot < 0 && errno == EINTR); + if (wgot < 0 && errno != EAGAIN) { + PANIC("Failed to queue signal"); + } DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig); } if (_thread_sigq[sig - 1].blocked == 0) { @@ -199,15 +207,8 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) if ((pthread = thread_sig_find(sig)) == NULL) DBG_MSG("No thread to handle signal %d\n", sig); else if (pthread == curthread) { - /* - * Unblock the signal and restore the process signal - * mask in case we don't return from the handler: - */ - _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); + thread_sig_invoke_handler(sig, info, ucp, 2); /* * Set the process signal mask in the context; it @@ -215,6 +216,16 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) */ ucp->uc_sigmask = _process_sigmask; + /* + * The signal mask was restored; check for any + * pending signals: + */ + sigset = curthread->sigpend; + SIGSETOR(sigset, _process_sigpending); + SIGSETNAND(sigset, curthread->sigmask); + if (SIGNOTEMPTY(sigset)) + curthread->check_pending = 1; + /* Resume the interrupted thread: */ __sys_sigreturn(ucp); } else { @@ -251,7 +262,8 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) } static void -thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp) +thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp, + int unblock) { struct pthread *curthread = _get_curthread(); void (*sigfunc)(int, siginfo_t *, void *); @@ -271,6 +283,17 @@ thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp) SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); sigaddset(&curthread->sigmask, sig); + if (unblock > 0) { + /* + * Unblock the signal and restore the process signal + * mask in case we don't return from the handler: + */ + _thread_sigq[sig - 1].blocked = 0; + if (unblock > 1) + __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, + NULL); + } + /* * Check that a custom handler is installed and if * the signal is not blocked: @@ -418,13 +441,14 @@ thread_sig_find(int sig) } if (suspended_thread == NULL && - signaled_thread == NULL) + signaled_thread == NULL) { /* * Add it to the set of signals pending * on the process: */ + _thread_sigq[sig - 1].blocked = 0; sigaddset(&_process_sigpending, sig); - else { + } else { /* * We only deliver the signal to one thread; * give preference to the suspended thread: @@ -937,7 +961,7 @@ _thread_sig_send(struct pthread *pthread, int sig) sigaddset(&pthread->sigpend, sig); else if (pthread == curthread) /* Call the signal handler for the current thread: */ - thread_sig_invoke_handler(sig, NULL, NULL); + thread_sig_invoke_handler(sig, NULL, NULL, 0); else { /* Protect the scheduling queues: */ _thread_kern_sig_defer(); @@ -1004,9 +1028,6 @@ _thread_sig_wrapper(void) } } - /* Unblock the signal in case we don't return from the handler: */ - _thread_sigq[psf->signo - 1].blocked = 0; - /* * Lower the priority before calling the handler in case * it never returns (longjmps back): @@ -1023,9 +1044,10 @@ _thread_sig_wrapper(void) * Dispatch the signal via the custom signal handler: */ if (psf->sig_has_args == 0) - thread_sig_invoke_handler(psf->signo, NULL, NULL); + thread_sig_invoke_handler(psf->signo, NULL, NULL, 1); else - thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc); + thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc, + 1); /* * Call the kernel scheduler to safely restore the frame and |