From 5321c2a9b02e061e8f5afe4538634523e9e37927 Mon Sep 17 00:00:00 2001 From: David Xu Date: Sat, 12 Jun 2004 07:40:01 +0000 Subject: [PATCH] Check pending signals, if there is signal will be unblocked by sigsuspend, thread shouldn't wait, in old code, it may be ignored. When a signal handler is invoked in sigsuspend, thread gets two different signal masks, one is in thread structure, sigprocmask() can retrieve it, another is in ucontext which is a third parameter of signal handler, the former is the result of sigsuspend mask ORed with sigaction's sa_mask and current signal, the later is the mask in thread structure before sigsuspend is called. After signal handler is called, the mask in ucontext should be copied into thread structure, and becomes CURRENT signal mask, then sigsuspend returns to user code. Reviewed by: deischen Tested by: Sean McNeil --- lib/libkse/thread/thr_create.c | 1 + lib/libkse/thread/thr_private.h | 1 + lib/libkse/thread/thr_sig.c | 6 +++- lib/libkse/thread/thr_sigsuspend.c | 39 ++++++++++++-------------- lib/libpthread/thread/thr_create.c | 1 + lib/libpthread/thread/thr_private.h | 1 + lib/libpthread/thread/thr_sig.c | 6 +++- lib/libpthread/thread/thr_sigsuspend.c | 39 ++++++++++++-------------- 8 files changed, 50 insertions(+), 44 deletions(-) diff --git a/lib/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c index 38c2fc4ae214..0f7cbab9237d 100644 --- a/lib/libkse/thread/thr_create.c +++ b/lib/libkse/thread/thr_create.c @@ -256,6 +256,7 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->sigstk.ss_sp = 0; new_thread->sigstk.ss_size = 0; new_thread->sigstk.ss_flags = SS_DISABLE; + new_thread->oldsigmask = NULL; if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { new_thread->state = PS_SUSPENDED; diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h index 191f9c11e1b7..98c967b6e2f7 100644 --- a/lib/libkse/thread/thr_private.h +++ b/lib/libkse/thread/thr_private.h @@ -657,6 +657,7 @@ struct pthread { */ sigset_t sigmask; sigset_t sigpend; + sigset_t *oldsigmask; volatile int check_pending; int refcount; diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c index 2a8d667fc931..010a99948c2b 100644 --- a/lib/libkse/thread/thr_sig.c +++ b/lib/libkse/thread/thr_sig.c @@ -463,7 +463,11 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, ucp->uc_stack = curthread->sigstk; ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE) ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0); - ucp->uc_sigmask = sigmask; + if (curthread->oldsigmask) { + ucp->uc_sigmask = *(curthread->oldsigmask); + curthread->oldsigmask = NULL; + } else + ucp->uc_sigmask = sigmask; shi.sigfunc = sigfunc; shi.sig = sig; shi.sa_flags = sa_flags; diff --git a/lib/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c index cad57451b406..b7802e3685d9 100644 --- a/lib/libkse/thread/thr_sigsuspend.c +++ b/lib/libkse/thread/thr_sigsuspend.c @@ -44,7 +44,7 @@ int _sigsuspend(const sigset_t *set) { struct pthread *curthread = _get_curthread(); - sigset_t oldmask, newmask; + sigset_t oldmask, newmask, tempset; int ret = -1; if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) @@ -54,32 +54,29 @@ _sigsuspend(const sigset_t *set) if (set != NULL) { newmask = *set; SIG_CANTMASK(newmask); - THR_LOCK_SWITCH(curthread); - /* Save current sigmask */ - memcpy(&oldmask, &curthread->sigmask, sizeof(sigset_t)); + /* Save current sigmask: */ + oldmask = curthread->sigmask; + curthread->oldsigmask = &oldmask; /* Change the caller's mask: */ - memcpy(&curthread->sigmask, &newmask, sizeof(sigset_t)); - - THR_SET_STATE(curthread, PS_SIGSUSPEND); - - /* Wait for a signal: */ - _thr_sched_switch_unlocked(curthread); - + curthread->sigmask = newmask; + tempset = curthread->sigpend; + SIGSETNAND(tempset, newmask); + if (SIGISEMPTY(tempset)) { + THR_SET_STATE(curthread, PS_SIGSUSPEND); + /* Wait for a signal: */ + _thr_sched_switch_unlocked(curthread); + } else { + THR_UNLOCK_SWITCH(curthread); + /* check pending signal I can handle: */ + _thr_sig_check_pending(curthread); + } + THR_ASSERT(curthread->oldsigmask == NULL, + "oldsigmask is not cleared"); /* Always return an interrupted error: */ errno = EINTR; - - THR_SCHED_LOCK(curthread, curthread); - /* Restore the signal mask: */ - memcpy(&curthread->sigmask, &oldmask, sizeof(sigset_t)); - THR_SCHED_UNLOCK(curthread, curthread); - /* - * signal mask is reloaded, need to check if there is - * pending proc signal I can handle. - */ - _thr_sig_check_pending(curthread); } else { /* Return an invalid argument error: */ errno = EINVAL; diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c index 38c2fc4ae214..0f7cbab9237d 100644 --- a/lib/libpthread/thread/thr_create.c +++ b/lib/libpthread/thread/thr_create.c @@ -256,6 +256,7 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->sigstk.ss_sp = 0; new_thread->sigstk.ss_size = 0; new_thread->sigstk.ss_flags = SS_DISABLE; + new_thread->oldsigmask = NULL; if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { new_thread->state = PS_SUSPENDED; diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index 191f9c11e1b7..98c967b6e2f7 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -657,6 +657,7 @@ struct pthread { */ sigset_t sigmask; sigset_t sigpend; + sigset_t *oldsigmask; volatile int check_pending; int refcount; diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index 2a8d667fc931..010a99948c2b 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -463,7 +463,11 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, ucp->uc_stack = curthread->sigstk; ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE) ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0); - ucp->uc_sigmask = sigmask; + if (curthread->oldsigmask) { + ucp->uc_sigmask = *(curthread->oldsigmask); + curthread->oldsigmask = NULL; + } else + ucp->uc_sigmask = sigmask; shi.sigfunc = sigfunc; shi.sig = sig; shi.sa_flags = sa_flags; diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c index cad57451b406..b7802e3685d9 100644 --- a/lib/libpthread/thread/thr_sigsuspend.c +++ b/lib/libpthread/thread/thr_sigsuspend.c @@ -44,7 +44,7 @@ int _sigsuspend(const sigset_t *set) { struct pthread *curthread = _get_curthread(); - sigset_t oldmask, newmask; + sigset_t oldmask, newmask, tempset; int ret = -1; if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) @@ -54,32 +54,29 @@ _sigsuspend(const sigset_t *set) if (set != NULL) { newmask = *set; SIG_CANTMASK(newmask); - THR_LOCK_SWITCH(curthread); - /* Save current sigmask */ - memcpy(&oldmask, &curthread->sigmask, sizeof(sigset_t)); + /* Save current sigmask: */ + oldmask = curthread->sigmask; + curthread->oldsigmask = &oldmask; /* Change the caller's mask: */ - memcpy(&curthread->sigmask, &newmask, sizeof(sigset_t)); - - THR_SET_STATE(curthread, PS_SIGSUSPEND); - - /* Wait for a signal: */ - _thr_sched_switch_unlocked(curthread); - + curthread->sigmask = newmask; + tempset = curthread->sigpend; + SIGSETNAND(tempset, newmask); + if (SIGISEMPTY(tempset)) { + THR_SET_STATE(curthread, PS_SIGSUSPEND); + /* Wait for a signal: */ + _thr_sched_switch_unlocked(curthread); + } else { + THR_UNLOCK_SWITCH(curthread); + /* check pending signal I can handle: */ + _thr_sig_check_pending(curthread); + } + THR_ASSERT(curthread->oldsigmask == NULL, + "oldsigmask is not cleared"); /* Always return an interrupted error: */ errno = EINTR; - - THR_SCHED_LOCK(curthread, curthread); - /* Restore the signal mask: */ - memcpy(&curthread->sigmask, &oldmask, sizeof(sigset_t)); - THR_SCHED_UNLOCK(curthread, curthread); - /* - * signal mask is reloaded, need to check if there is - * pending proc signal I can handle. - */ - _thr_sig_check_pending(curthread); } else { /* Return an invalid argument error: */ errno = EINVAL;