mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-02 04:13:39 +00:00
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:
parent
d55b402ee4
commit
5321c2a9b0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=130374
@ -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;
|
||||
|
@ -657,6 +657,7 @@ struct pthread {
|
||||
*/
|
||||
sigset_t sigmask;
|
||||
sigset_t sigpend;
|
||||
sigset_t *oldsigmask;
|
||||
volatile int check_pending;
|
||||
int refcount;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -657,6 +657,7 @@ struct pthread {
|
||||
*/
|
||||
sigset_t sigmask;
|
||||
sigset_t sigpend;
|
||||
sigset_t *oldsigmask;
|
||||
volatile int check_pending;
|
||||
int refcount;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user