diff options
author | deischen <deischen@FreeBSD.org> | 2000-10-25 11:46:07 +0000 |
---|---|---|
committer | deischen <deischen@FreeBSD.org> | 2000-10-25 11:46:07 +0000 |
commit | 727a941a161db6715518f117484b20847bc26cad (patch) | |
tree | 428e65909bc8fa35eed7f09de11d0e64c76ebdb8 /lib/libpthread | |
parent | 6a37abd487cc8d6879d9219fdf5cd3e2f76a2f5d (diff) | |
download | FreeBSD-src-727a941a161db6715518f117484b20847bc26cad.zip FreeBSD-src-727a941a161db6715518f117484b20847bc26cad.tar.gz |
Make pthread_kill() know about temporary signal handlers installed
by sigwait(). This prevents a signal from being sent to the process
when there are no application installed signal handlers.
Correct a typo in sigwait (foo -> foo[i]).
Diffstat (limited to 'lib/libpthread')
-rw-r--r-- | lib/libpthread/thread/thr_sig.c | 148 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_sigwait.c | 8 |
2 files changed, 124 insertions, 32 deletions
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index b2b8c92..f19582d 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -45,6 +45,7 @@ /* 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_handle_special(int sig); static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp); @@ -765,32 +766,131 @@ thread_sig_add(pthread_t pthread, int sig, int has_args) } } +static void +thread_sig_check_state(pthread_t pthread, int sig) +{ + /* + * Process according to thread state: + */ + switch (pthread->state) { + /* + * States which do not change when a signal is trapped: + */ + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + case PS_SIGTHREAD: + case PS_RUNNING: + case PS_SUSPENDED: + case PS_SPINBLOCK: + case PS_COND_WAIT: + case PS_JOIN: + case PS_MUTEX_WAIT: + 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; + + /* + * The wait state is a special case due to the handling of + * SIGCHLD signals. + */ + case PS_WAIT_WAIT: + if (sig == SIGCHLD) { + /* + * Remove the thread from the wait queue and + * make it runnable: + */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + break; + + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_SIGSUSPEND: + case PS_SLEEP_WAIT: + /* + * Remove the thread from the wait queue and make it + * runnable: + */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Flag the operation as interrupted: */ + pthread->interrupted = 1; + break; + + /* + * These states are additionally in the work queue: + */ + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_FILE_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* + * Remove the thread from the wait and work queues, and + * make it runnable: + */ + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Flag the operation as interrupted: */ + pthread->interrupted = 1; + break; + } +} + /* * Send a signal to a specific thread (ala pthread_kill): */ void _thread_sig_send(pthread_t pthread, int sig) { + /* Check for signals whose actions are SIG_DFL: */ + if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) { + /* + * Check to see if a temporary signal handler is + * installed for sigwaiters: + */ + if (_thread_dfl_count[sig] == 0) + /* + * Deliver the signal to the process if a handler + * is not installed: + */ + kill(getpid(), sig); + /* + * Assuming we're still running after the above kill(), + * make any necessary state changes to the thread: + */ + thread_sig_check_state(pthread, sig); + } /* * Check that the signal is not being ignored: */ - if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { + else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { if (pthread->state == PS_SIGWAIT && 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 if (pthread == _thread_run) { /* Add the signal to the pending set: */ sigaddset(&pthread->sigpend, sig); - /* - * Deliver the signal to the process if a - * handler is not installed: - */ - if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) - kill(getpid(), sig); if (!sigismember(&pthread->sigmask, sig)) { /* * Call the kernel scheduler which will safely @@ -798,29 +898,19 @@ _thread_sig_send(pthread_t pthread, int sig) */ _thread_kern_sched_sig(); } - } else { - if (pthread->state != PS_SIGWAIT && - !sigismember(&pthread->sigmask, sig)) { - /* Protect the scheduling queues: */ - _thread_kern_sig_defer(); - /* - * Perform any state changes due to signal - * arrival: - */ - 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); - + } else if (!sigismember(&pthread->sigmask, sig)) { + /* Protect the scheduling queues: */ + _thread_kern_sig_defer(); /* - * Deliver the signal to the process if a - * handler is not installed: + * Perform any state changes due to signal + * arrival: */ - if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) - kill(getpid(), 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); } } } diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c index 6ba6855..f2c6ea1 100644 --- a/lib/libpthread/thread/thr_sigwait.c +++ b/lib/libpthread/thread/thr_sigwait.c @@ -108,10 +108,12 @@ sigwait(const sigset_t *set, int *sig) * mask because a subsequent sigaction could enable an * ignored signal. */ + sigemptyset(&tempset); for (i = 1; i < NSIG; i++) { if (sigismember(&waitset, i) && (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { _thread_dfl_count[i]++; + sigaddset(&tempset, i); if (_thread_dfl_count[i] == 1) { if (_thread_sys_sigaction(i,&act,NULL) != 0) ret = -1; @@ -151,10 +153,10 @@ sigwait(const sigset_t *set, int *sig) /* Restore the sigactions: */ act.sa_handler = SIG_DFL; for (i = 1; i < NSIG; i++) { - if (sigismember(&waitset, i) && - (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { + if (sigismember(&tempset, i)) { _thread_dfl_count[i]--; - if (_thread_dfl_count == 0) { + if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) && + (_thread_dfl_count[i] == 0)) { if (_thread_sys_sigaction(i,&act,NULL) != 0) ret = -1; } |