mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
MFC r198506:
In kern_sigsuspend(), manipulate thread signal mask using kern_sigprocmask(). Also, do cursig/postsig loop immediately after waiting for signal, repeating the wait if wakeup was spurious due to race with other thread fetching signal from the process queue before us. MFC r199136: Use cpu_set_syscall_retval(9) to set syscall result, and return EJUSTRETURN from kern_sigsuspend() to prevent syscall return code from modifying wrong frame. Take care of possibility that pending SIGCONT might be cancelled by SIGSTOP, causing postsig() not to deliver any catched signal.
This commit is contained in:
parent
9fe2c7cecd
commit
3134e1153f
4 changed files with 40 additions and 42 deletions
|
|
@ -2579,21 +2579,10 @@ int
|
|||
ofreebsd32_sigsuspend(struct thread *td,
|
||||
struct ofreebsd32_sigsuspend_args *uap)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
sigset_t mask;
|
||||
|
||||
PROC_LOCK(p);
|
||||
td->td_oldsigmask = td->td_sigmask;
|
||||
td->td_pflags |= TDP_OLDMASK;
|
||||
OSIG2SIG(uap->mask, mask);
|
||||
SIG_CANTMASK(mask);
|
||||
SIGSETLO(td->td_sigmask, mask);
|
||||
signotify(td);
|
||||
while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "opause", 0) == 0)
|
||||
/* void */;
|
||||
PROC_UNLOCK(p);
|
||||
/* always return EINTR rather than ERESTART... */
|
||||
return (EINTR);
|
||||
return (kern_sigsuspend(td, mask));
|
||||
}
|
||||
|
||||
struct sigstack32 {
|
||||
|
|
|
|||
|
|
@ -966,14 +966,15 @@ execsigs(struct proc *p)
|
|||
*/
|
||||
int
|
||||
kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset,
|
||||
int old)
|
||||
int flags)
|
||||
{
|
||||
sigset_t new_block, oset1;
|
||||
struct proc *p;
|
||||
int error;
|
||||
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
if (!(flags & SIGPROCMASK_PROC_LOCKED))
|
||||
PROC_LOCK(p);
|
||||
if (oset != NULL)
|
||||
*oset = td->td_sigmask;
|
||||
|
||||
|
|
@ -995,7 +996,7 @@ kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset,
|
|||
case SIG_SETMASK:
|
||||
SIG_CANTMASK(*set);
|
||||
oset1 = td->td_sigmask;
|
||||
if (old)
|
||||
if (flags & SIGPROCMASK_OLD)
|
||||
SIGSETLO(td->td_sigmask, *set);
|
||||
else
|
||||
td->td_sigmask = *set;
|
||||
|
|
@ -1021,7 +1022,8 @@ kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset,
|
|||
if (p->p_numthreads != 1)
|
||||
reschedule_signals(p, new_block);
|
||||
|
||||
PROC_UNLOCK(p);
|
||||
if (!(flags & SIGPROCMASK_PROC_LOCKED))
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
|
@ -1454,6 +1456,7 @@ int
|
|||
kern_sigsuspend(struct thread *td, sigset_t mask)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
int has_sig, sig;
|
||||
|
||||
/*
|
||||
* When returning from sigsuspend, we want
|
||||
|
|
@ -1463,16 +1466,29 @@ kern_sigsuspend(struct thread *td, sigset_t mask)
|
|||
* to indicate this.
|
||||
*/
|
||||
PROC_LOCK(p);
|
||||
td->td_oldsigmask = td->td_sigmask;
|
||||
kern_sigprocmask(td, SIG_SETMASK, &mask, &td->td_oldsigmask,
|
||||
SIGPROCMASK_PROC_LOCKED);
|
||||
td->td_pflags |= TDP_OLDMASK;
|
||||
SIG_CANTMASK(mask);
|
||||
td->td_sigmask = mask;
|
||||
signotify(td);
|
||||
while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause", 0) == 0)
|
||||
/* void */;
|
||||
|
||||
/*
|
||||
* Process signals now. Otherwise, we can get spurious wakeup
|
||||
* due to signal entered process queue, but delivered to other
|
||||
* thread. But sigsuspend should return only on signal
|
||||
* delivery.
|
||||
*/
|
||||
cpu_set_syscall_retval(td, EINTR);
|
||||
for (has_sig = 0; !has_sig;) {
|
||||
while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause",
|
||||
0) == 0)
|
||||
/* void */;
|
||||
thread_suspend_check(0);
|
||||
mtx_lock(&p->p_sigacts->ps_mtx);
|
||||
while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0)
|
||||
has_sig += postsig(sig);
|
||||
mtx_unlock(&p->p_sigacts->ps_mtx);
|
||||
}
|
||||
PROC_UNLOCK(p);
|
||||
/* always return EINTR rather than ERESTART... */
|
||||
return (EINTR);
|
||||
return (EJUSTRETURN);
|
||||
}
|
||||
|
||||
#ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */
|
||||
|
|
@ -1491,21 +1507,10 @@ osigsuspend(td, uap)
|
|||
struct thread *td;
|
||||
struct osigsuspend_args *uap;
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
sigset_t mask;
|
||||
|
||||
PROC_LOCK(p);
|
||||
td->td_oldsigmask = td->td_sigmask;
|
||||
td->td_pflags |= TDP_OLDMASK;
|
||||
OSIG2SIG(uap->mask, mask);
|
||||
SIG_CANTMASK(mask);
|
||||
SIGSETLO(td->td_sigmask, mask);
|
||||
signotify(td);
|
||||
while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "opause", 0) == 0)
|
||||
/* void */;
|
||||
PROC_UNLOCK(p);
|
||||
/* always return EINTR rather than ERESTART... */
|
||||
return (EINTR);
|
||||
return (kern_sigsuspend(td, mask));
|
||||
}
|
||||
#endif /* COMPAT_43 */
|
||||
|
||||
|
|
@ -2662,7 +2667,7 @@ thread_stopped(struct proc *p)
|
|||
* Take the action for the specified signal
|
||||
* from the current set of pending signals.
|
||||
*/
|
||||
void
|
||||
int
|
||||
postsig(sig)
|
||||
register int sig;
|
||||
{
|
||||
|
|
@ -2681,7 +2686,7 @@ postsig(sig)
|
|||
ksiginfo_init(&ksi);
|
||||
if (sigqueue_get(&td->td_sigqueue, sig, &ksi) == 0 &&
|
||||
sigqueue_get(&p->p_sigqueue, sig, &ksi) == 0)
|
||||
return;
|
||||
return (0);
|
||||
ksi.ksi_signo = sig;
|
||||
if (ksi.ksi_code == SI_TIMER)
|
||||
itimer_accept(p, ksi.ksi_timerid, &ksi);
|
||||
|
|
@ -2747,6 +2752,7 @@ postsig(sig)
|
|||
}
|
||||
(*p->p_sysent->sv_sendsig)(action, &ksi, &returnmask);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -316,6 +316,10 @@ extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */
|
|||
#define SIG_STOP_ALLOWED 100
|
||||
#define SIG_STOP_NOT_ALLOWED 101
|
||||
|
||||
/* flags for kern_sigprocmask */
|
||||
#define SIGPROCMASK_OLD 0x0001
|
||||
#define SIGPROCMASK_PROC_LOCKED 0x0002
|
||||
|
||||
/*
|
||||
* Machine-independent functions:
|
||||
*/
|
||||
|
|
@ -325,7 +329,7 @@ void gsignal(int pgid, int sig);
|
|||
void killproc(struct proc *p, char *why);
|
||||
void pgsigio(struct sigio **, int signum, int checkctty);
|
||||
void pgsignal(struct pgrp *pgrp, int sig, int checkctty);
|
||||
void postsig(int sig);
|
||||
int postsig(int sig);
|
||||
void psignal(struct proc *p, int sig);
|
||||
int psignal_event(struct proc *p, struct sigevent *, ksiginfo_t *);
|
||||
struct sigacts *sigacts_alloc(void);
|
||||
|
|
@ -359,7 +363,8 @@ void sigqueue_delete_stopmask_proc(struct proc *);
|
|||
void sigqueue_take(ksiginfo_t *ksi);
|
||||
int kern_sigtimedwait(struct thread *, sigset_t,
|
||||
ksiginfo_t *, struct timespec *);
|
||||
|
||||
int kern_sigprocmask(struct thread *td, int how,
|
||||
sigset_t *set, sigset_t *oset, int flags);
|
||||
/*
|
||||
* Machine-dependent functions:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -190,8 +190,6 @@ int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf,
|
|||
int kern_sigaction(struct thread *td, int sig, struct sigaction *act,
|
||||
struct sigaction *oact, int flags);
|
||||
int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss);
|
||||
int kern_sigprocmask(struct thread *td, int how,
|
||||
sigset_t *set, sigset_t *oset, int old);
|
||||
int kern_sigsuspend(struct thread *td, sigset_t mask);
|
||||
int kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
struct stat *sbp);
|
||||
|
|
|
|||
Loading…
Reference in a new issue