sigfastblock: fix delivery of the pending signals in single-threaded processes.
If single-threaded process receives a signal during critical section established by sigfastblock(2) word, unblock did not caused signal delivery because sigfastblock(SIGFASTBLOCK_UNBLOCK) failed to request ast handling of the pending signals. Set TDF_ASTPENDING | TDF_NEEDSIGCHK on unblock or when kernel forces end of sigfastblock critical section, to cause syscall exit to recheck and deliver any signal pending. Reported by: corydoras@ridiculousfish.com PR: 246385 Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
f88ecf821e
commit
fb3c434ba2
@ -3976,6 +3976,22 @@ sigfastblock_fetch_sig(struct thread *td, bool sendsig, uint32_t *valp)
|
||||
return (true);
|
||||
}
|
||||
|
||||
static void
|
||||
sigfastblock_resched(struct thread *td, bool resched)
|
||||
{
|
||||
struct proc *p;
|
||||
|
||||
if (resched) {
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
reschedule_signals(p, td->td_sigmask, 0);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
thread_lock(td);
|
||||
td->td_flags |= TDF_ASTPENDING | TDF_NEEDSIGCHK;
|
||||
thread_unlock(td);
|
||||
}
|
||||
|
||||
int
|
||||
sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
|
||||
{
|
||||
@ -4046,11 +4062,8 @@ sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
|
||||
* signals to current thread. But notify others about
|
||||
* fake unblock.
|
||||
*/
|
||||
if (error == 0 && p->p_numthreads != 1) {
|
||||
PROC_LOCK(p);
|
||||
reschedule_signals(p, td->td_sigmask, 0);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
sigfastblock_resched(td, error == 0 && p->p_numthreads != 1);
|
||||
|
||||
break;
|
||||
|
||||
case SIGFASTBLOCK_UNSETPTR:
|
||||
@ -4079,7 +4092,6 @@ sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap)
|
||||
void
|
||||
sigfastblock_clear(struct thread *td)
|
||||
{
|
||||
struct proc *p;
|
||||
bool resched;
|
||||
|
||||
if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0)
|
||||
@ -4088,12 +4100,7 @@ sigfastblock_clear(struct thread *td)
|
||||
resched = (td->td_pflags & TDP_SIGFASTPENDING) != 0 ||
|
||||
SIGPENDING(td);
|
||||
td->td_pflags &= ~(TDP_SIGFASTBLOCK | TDP_SIGFASTPENDING);
|
||||
if (resched) {
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
reschedule_signals(p, td->td_sigmask, 0);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
sigfastblock_resched(td, resched);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user