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 <sean@mcneil.com>
This commit is contained in:
David Xu 2004-06-12 07:40:01 +00:00
parent d55b402ee4
commit 5321c2a9b0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=130374
8 changed files with 50 additions and 44 deletions

View File

@ -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;

View File

@ -657,6 +657,7 @@ struct pthread {
*/
sigset_t sigmask;
sigset_t sigpend;
sigset_t *oldsigmask;
volatile int check_pending;
int refcount;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -657,6 +657,7 @@ struct pthread {
*/
sigset_t sigmask;
sigset_t sigpend;
sigset_t *oldsigmask;
volatile int check_pending;
int refcount;

View File

@ -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;

View File

@ -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;