diff options
author | deischen <deischen@FreeBSD.org> | 1999-12-17 00:56:36 +0000 |
---|---|---|
committer | deischen <deischen@FreeBSD.org> | 1999-12-17 00:56:36 +0000 |
commit | 17ee572a14054fb3c892f9dc5ee491e75bc8f3f5 (patch) | |
tree | 5d51d9a812640e396f61d1c8d3b91b7f6c0cdba7 /lib/libpthread/thread/thr_kill.c | |
parent | 3bd28ea93ef0db4dbbbf6b6671392ccbc020a864 (diff) | |
download | FreeBSD-src-17ee572a14054fb3c892f9dc5ee491e75bc8f3f5.zip FreeBSD-src-17ee572a14054fb3c892f9dc5ee491e75bc8f3f5.tar.gz |
Fixes for signal handling:
o Don't call signal handlers with the signal handler access lock
held.
o Remove pending signals before calling signal handlers. If
pending signals were not removed prior to handling them,
invocation of the handler could cause the handler to be
called more than once for the same signal. Found by: JB
o When SIGCHLD arrives, wake up all threads in PS_WAIT_WAIT
(wait4).
PR: bin/15328
Reviewed by: jasone
Diffstat (limited to 'lib/libpthread/thread/thr_kill.c')
-rw-r--r-- | lib/libpthread/thread/thr_kill.c | 94 |
1 files changed, 1 insertions, 93 deletions
diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c index 6b25550..4bf1761 100644 --- a/lib/libpthread/thread/thr_kill.c +++ b/lib/libpthread/thread/thr_kill.c @@ -46,7 +46,6 @@ pthread_kill(pthread_t pthread, int sig) if (sig < 0 || sig >= NSIG) /* Invalid signal: */ ret = EINVAL; - /* * Ensure the thread is in the list of active threads, and the * signal is valid (signal 0 specifies error checking only) and @@ -60,98 +59,7 @@ pthread_kill(pthread_t pthread, int sig) */ _thread_kern_sig_defer(); - switch (pthread->state) { - case PS_SIGSUSPEND: - /* - * Only wake up the thread if the signal is unblocked - * and there is a handler installed for the signal. - */ - if (!sigismember(&pthread->sigmask, sig) && - _thread_sigact[sig - 1].sa_handler != SIG_DFL) { - /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); - - /* Return the signal number: */ - pthread->signo = sig; - } - /* Increment the pending signal count: */ - sigaddset(&pthread->sigpend,sig); - break; - - case PS_SIGWAIT: - /* Wake up the thread if the signal is blocked. */ - if (sigismember(pthread->data.sigwait, sig)) { - /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); - - /* Return the signal number: */ - pthread->signo = sig; - } else - /* Increment the pending signal count. */ - sigaddset(&pthread->sigpend,sig); - break; - - case PS_FDR_WAIT: - case PS_FDW_WAIT: - case PS_POLL_WAIT: - case PS_SLEEP_WAIT: - case PS_SELECT_WAIT: - if (!sigismember(&pthread->sigmask, sig) && - (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) { - /* Flag the operation as interrupted: */ - pthread->interrupted = 1; - - if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) - PTHREAD_WORKQ_REMOVE(pthread); - - /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); - - /* Return the signal number: */ - pthread->signo = sig; - } else { - /* Increment the pending signal count: */ - sigaddset(&pthread->sigpend,sig); - } - break; - - default: - /* Increment the pending signal count: */ - sigaddset(&pthread->sigpend,sig); - break; - } - - - /* - * Check that a custom handler is installed - * and if the signal is not blocked: - */ - if (_thread_sigact[sig - 1].sa_handler != SIG_DFL && - _thread_sigact[sig - 1].sa_handler != SIG_IGN && - sigismember(&pthread->sigpend, sig) && - !sigismember(&pthread->sigmask, sig)) { - pthread_t pthread_saved = _thread_run; - - /* Current thread inside critical region? */ - if (_thread_run->sig_defer_count > 0) - pthread->sig_defer_count++; - - _thread_run = pthread; - - /* Clear the pending signal: */ - sigdelset(&pthread->sigpend, sig); - - /* - * Dispatch the signal via the custom signal - * handler: - */ - (*(_thread_sigact[sig - 1].sa_handler))(sig); - - _thread_run = pthread_saved; - - if (_thread_run->sig_defer_count > 0) - pthread->sig_defer_count--; - } + _thread_sig_send(pthread, sig); /* * Undefer and handle pending signals, yielding if |