diff options
Diffstat (limited to 'lib/libpthread/thread')
-rw-r--r-- | lib/libpthread/thread/thr_sig.c | 29 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_sigwait.c | 11 |
2 files changed, 29 insertions, 11 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; diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c index ac44972..46dac92 100644 --- a/lib/libpthread/thread/thr_sigwait.c +++ b/lib/libpthread/thread/thr_sigwait.c @@ -123,6 +123,7 @@ lib_sigtimedwait(const sigset_t *set, siginfo_t *info, } } curthread->timeout = 0; + curthread->interrupted = 0; _thr_set_timeout(timeout); /* Wait for a signal: */ curthread->oldsigmask = curthread->sigmask; @@ -134,18 +135,18 @@ lib_sigtimedwait(const sigset_t *set, siginfo_t *info, _thr_sched_switch_unlocked(curthread); /* * Return the signal number to the caller: - * XXX Here is race, how about a signal come in before - * we reach here? so we might got an incorrect timeout - * status. */ if (siginfo.si_signo > 0) { ret = siginfo.si_signo; } else { - if (curthread->timeout) + if (curthread->interrupted) + errno = EINTR; + else if (curthread->timeout) errno = EAGAIN; ret = -1; } - + curthread->timeout = 0; + curthread->interrupted = 0; /* * Probably unnecessary, but since it's in a union struct * we don't know how it could be used in the future. |