summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/thread/thr_sig.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2003-07-09 14:30:51 +0000
committerdavidxu <davidxu@FreeBSD.org>2003-07-09 14:30:51 +0000
commitb14a2d89ea07034f41b853267f8f06d65fc33377 (patch)
treed2daeb2dd73fe7becbb0e19db3e0b8d877165b8a /lib/libpthread/thread/thr_sig.c
parentbeedaf29a12e8ffafdcd93268ebb750b3b44d254 (diff)
downloadFreeBSD-src-b14a2d89ea07034f41b853267f8f06d65fc33377.zip
FreeBSD-src-b14a2d89ea07034f41b853267f8f06d65fc33377.tar.gz
POSIX says if a thread is in sigwait state, although a signal may not in
its waitset, but if the signal is not masked by the thread, the signal can interrupt the thread and signal action can be invoked by the thread, sigwait should return with errno set to EINTR. Also save and restore thread internal state(timeout and interrupted) around signal handler invoking.
Diffstat (limited to 'lib/libpthread/thread/thr_sig.c')
-rw-r--r--lib/libpthread/thread/thr_sig.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index 6e95cdd..cef8399 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -217,7 +217,10 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
- } else if (SIGISMEMBER(thread->sigmask, sig)) {
+ } else if ((thread->state == PS_SIGWAIT &&
+ SIGISMEMBER(thread->oldsigmask, sig)) ||
+ (thread->state != PS_SIGWAIT &&
+ SIGISMEMBER(thread->sigmask, sig))) {
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
} else {
@@ -415,10 +418,10 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
if ((pthread->state == PS_DEAD) ||
(pthread->state == PS_DEADLOCK) ||
THR_IS_EXITING(pthread) ||
- THR_IS_SUSPENDED(pthread) ||
- SIGISMEMBER(pthread->sigmask, sig)) {
+ THR_IS_SUSPENDED(pthread)) {
; /* Skip this thread. */
- } else if (pthread->state == PS_SIGWAIT) {
+ } else if (pthread->state == PS_SIGWAIT &&
+ !SIGISMEMBER(pthread->sigmask, sig)) {
/*
* retrieve signal from kernel, if it is job control
* signal, and sigaction is SIG_DFL, then we will
@@ -447,7 +450,9 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
*/
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
return (NULL);
- } else {
+ } else if (!SIGISMEMBER(pthread->sigmask, sig) ||
+ (!SIGISMEMBER(pthread->oldsigmask, sig) &&
+ pthread->state == PS_SIGWAIT)) {
if (pthread->state == PS_SIGSUSPEND) {
if (suspended_thread == NULL) {
suspended_thread = pthread;
@@ -490,6 +495,8 @@ void
_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf)
{
+ int interrupted = curthread->interrupted;
+ int timeout = curthread->timeout;
siginfo_t siginfo;
int i;
kse_critical_t crit;
@@ -563,6 +570,9 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
_kse_critical_leave(&curthread->tmbx);
+ curthread->interrupted = interrupted;
+ curthread->timeout = timeout;
+
DBG_MSG("<<< thr_sig_rundown %p\n", curthread);
}
@@ -659,7 +669,8 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
#endif
if (pthread->curframe == NULL ||
- SIGISMEMBER(pthread->sigmask, sig) ||
+ (pthread->state != PS_SIGWAIT &&
+ SIGISMEMBER(pthread->sigmask, sig)) ||
THR_IN_CRITICAL(pthread)) {
/* thread is running or signal was being masked */
if (!fromproc) {
@@ -760,6 +771,9 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
/* Increment the pending signal count. */
SIGADDSET(pthread->sigpend, sig);
pthread->check_pending = 1;
+ pthread->interrupted = 1;
+ pthread->sigmask = pthread->oldsigmask;
+ _thr_setrunnable_unlocked(pthread);
}
return;
@@ -823,6 +837,9 @@ thr_sig_check_state(struct pthread *pthread, int sig)
/* Increment the pending signal count. */
SIGADDSET(pthread->sigpend, sig);
pthread->check_pending = 1;
+ pthread->interrupted = 1;
+ pthread->sigmask = pthread->oldsigmask;
+ _thr_setrunnable_unlocked(pthread);
}
break;
OpenPOWER on IntegriCloud