Add new msleep(9) flag PBDY that shall be specified together with
PCATCH, to indicate that thread shall not be stopped upon receipt of SIGSTOP until it reaches the kernel->usermode boundary. Also change thread_single(SINGLE_NO_EXIT) to only stop threads at the user boundary unconditionally. Tested by: pho Reviewed by: jhb Approved by: re (kensmith)
This commit is contained in:
parent
79799053a7
commit
f33a947b56
@ -55,7 +55,7 @@ issig(int why)
|
|||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
mtx_lock(&p->p_sigacts->ps_mtx);
|
mtx_lock(&p->p_sigacts->ps_mtx);
|
||||||
sig = cursig(td);
|
sig = cursig(td, SIG_STOP_ALLOWED);
|
||||||
mtx_unlock(&p->p_sigacts->ps_mtx);
|
mtx_unlock(&p->p_sigacts->ps_mtx);
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
if (sig != 0)
|
if (sig != 0)
|
||||||
|
@ -100,7 +100,7 @@ SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 2, "int");
|
|||||||
static int coredump(struct thread *);
|
static int coredump(struct thread *);
|
||||||
static char *expand_name(const char *, uid_t, pid_t);
|
static char *expand_name(const char *, uid_t, pid_t);
|
||||||
static int killpg1(struct thread *td, int sig, int pgid, int all);
|
static int killpg1(struct thread *td, int sig, int pgid, int all);
|
||||||
static int issignal(struct thread *p);
|
static int issignal(struct thread *td, int stop_allowed);
|
||||||
static int sigprop(int sig);
|
static int sigprop(int sig);
|
||||||
static void tdsigwakeup(struct thread *, int, sig_t, int);
|
static void tdsigwakeup(struct thread *, int, sig_t, int);
|
||||||
static void sig_suspend_threads(struct thread *, struct proc *, int);
|
static void sig_suspend_threads(struct thread *, struct proc *, int);
|
||||||
@ -558,12 +558,14 @@ sigqueue_delete_stopmask_proc(struct proc *p)
|
|||||||
* action, the process stops in issignal().
|
* action, the process stops in issignal().
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cursig(struct thread *td)
|
cursig(struct thread *td, int stop_allowed)
|
||||||
{
|
{
|
||||||
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
|
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
|
||||||
|
KASSERT(stop_allowed == SIG_STOP_ALLOWED ||
|
||||||
|
stop_allowed == SIG_STOP_NOT_ALLOWED, ("cursig: stop_allowed"));
|
||||||
mtx_assert(&td->td_proc->p_sigacts->ps_mtx, MA_OWNED);
|
mtx_assert(&td->td_proc->p_sigacts->ps_mtx, MA_OWNED);
|
||||||
THREAD_LOCK_ASSERT(td, MA_NOTOWNED);
|
THREAD_LOCK_ASSERT(td, MA_NOTOWNED);
|
||||||
return (SIGPENDING(td) ? issignal(td) : 0);
|
return (SIGPENDING(td) ? issignal(td, stop_allowed) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1191,7 +1193,7 @@ restart:
|
|||||||
SIG_CANTMASK(td->td_sigmask);
|
SIG_CANTMASK(td->td_sigmask);
|
||||||
SIGDELSET(td->td_sigmask, i);
|
SIGDELSET(td->td_sigmask, i);
|
||||||
mtx_lock(&ps->ps_mtx);
|
mtx_lock(&ps->ps_mtx);
|
||||||
sig = cursig(td);
|
sig = cursig(td, SIG_STOP_ALLOWED);
|
||||||
mtx_unlock(&ps->ps_mtx);
|
mtx_unlock(&ps->ps_mtx);
|
||||||
if (sig)
|
if (sig)
|
||||||
goto out;
|
goto out;
|
||||||
@ -2310,18 +2312,28 @@ static void
|
|||||||
sig_suspend_threads(struct thread *td, struct proc *p, int sending)
|
sig_suspend_threads(struct thread *td, struct proc *p, int sending)
|
||||||
{
|
{
|
||||||
struct thread *td2;
|
struct thread *td2;
|
||||||
|
int wakeup_swapper;
|
||||||
|
|
||||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||||
PROC_SLOCK_ASSERT(p, MA_OWNED);
|
PROC_SLOCK_ASSERT(p, MA_OWNED);
|
||||||
|
|
||||||
|
wakeup_swapper = 0;
|
||||||
FOREACH_THREAD_IN_PROC(p, td2) {
|
FOREACH_THREAD_IN_PROC(p, td2) {
|
||||||
thread_lock(td2);
|
thread_lock(td2);
|
||||||
td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
|
td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
|
||||||
if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) &&
|
if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) &&
|
||||||
(td2->td_flags & TDF_SINTR) &&
|
(td2->td_flags & TDF_SINTR)) {
|
||||||
!TD_IS_SUSPENDED(td2)) {
|
if (td2->td_flags & TDF_SBDRY) {
|
||||||
thread_suspend_one(td2);
|
if (TD_IS_SUSPENDED(td2))
|
||||||
} else {
|
wakeup_swapper |=
|
||||||
|
thread_unsuspend_one(td2);
|
||||||
|
if (TD_ON_SLEEPQ(td2))
|
||||||
|
wakeup_swapper |=
|
||||||
|
sleepq_abort(td2, ERESTART);
|
||||||
|
} else if (!TD_IS_SUSPENDED(td2)) {
|
||||||
|
thread_suspend_one(td2);
|
||||||
|
}
|
||||||
|
} else if (!TD_IS_SUSPENDED(td2)) {
|
||||||
if (sending || td != td2)
|
if (sending || td != td2)
|
||||||
td2->td_flags |= TDF_ASTPENDING;
|
td2->td_flags |= TDF_ASTPENDING;
|
||||||
#ifdef SMP
|
#ifdef SMP
|
||||||
@ -2331,6 +2343,8 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending)
|
|||||||
}
|
}
|
||||||
thread_unlock(td2);
|
thread_unlock(td2);
|
||||||
}
|
}
|
||||||
|
if (wakeup_swapper)
|
||||||
|
kick_proc0();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -2387,8 +2401,7 @@ stopme:
|
|||||||
* postsig(sig);
|
* postsig(sig);
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
issignal(td)
|
issignal(struct thread *td, int stop_allowed)
|
||||||
struct thread *td;
|
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
struct sigacts *ps;
|
struct sigacts *ps;
|
||||||
@ -2506,6 +2519,10 @@ issignal(td)
|
|||||||
(p->p_pgrp->pg_jobc == 0 &&
|
(p->p_pgrp->pg_jobc == 0 &&
|
||||||
prop & SA_TTYSTOP))
|
prop & SA_TTYSTOP))
|
||||||
break; /* == ignore */
|
break; /* == ignore */
|
||||||
|
|
||||||
|
/* Ignore, but do not drop the stop signal. */
|
||||||
|
if (stop_allowed != SIG_STOP_ALLOWED)
|
||||||
|
return (sig);
|
||||||
mtx_unlock(&ps->ps_mtx);
|
mtx_unlock(&ps->ps_mtx);
|
||||||
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
|
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
|
||||||
&p->p_mtx.lock_object, "Catching SIGSTOP");
|
&p->p_mtx.lock_object, "Catching SIGSTOP");
|
||||||
|
@ -188,6 +188,8 @@ _sleep(void *ident, struct lock_object *lock, int priority,
|
|||||||
flags = SLEEPQ_SLEEP;
|
flags = SLEEPQ_SLEEP;
|
||||||
if (catch)
|
if (catch)
|
||||||
flags |= SLEEPQ_INTERRUPTIBLE;
|
flags |= SLEEPQ_INTERRUPTIBLE;
|
||||||
|
if (priority & PBDRY)
|
||||||
|
flags |= SLEEPQ_STOP_ON_BDRY;
|
||||||
|
|
||||||
sleepq_lock(ident);
|
sleepq_lock(ident);
|
||||||
CTR5(KTR_PROC, "sleep: thread %ld (pid %ld, %s) on %s (%p)",
|
CTR5(KTR_PROC, "sleep: thread %ld (pid %ld, %s) on %s (%p)",
|
||||||
|
@ -598,18 +598,17 @@ thread_single(int mode)
|
|||||||
wakeup_swapper |=
|
wakeup_swapper |=
|
||||||
sleepq_abort(td2, ERESTART);
|
sleepq_abort(td2, ERESTART);
|
||||||
break;
|
break;
|
||||||
|
case SINGLE_NO_EXIT:
|
||||||
|
if (TD_IS_SUSPENDED(td2) &&
|
||||||
|
!(td2->td_flags & TDF_BOUNDARY))
|
||||||
|
wakeup_swapper |=
|
||||||
|
thread_unsuspend_one(td2);
|
||||||
|
if (TD_ON_SLEEPQ(td2) &&
|
||||||
|
(td2->td_flags & TDF_SINTR))
|
||||||
|
wakeup_swapper |=
|
||||||
|
sleepq_abort(td2, ERESTART);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (TD_IS_SUSPENDED(td2)) {
|
|
||||||
thread_unlock(td2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* maybe other inhibited states too?
|
|
||||||
*/
|
|
||||||
if ((td2->td_flags & TDF_SINTR) &&
|
|
||||||
(td2->td_inhibitors &
|
|
||||||
(TDI_SLEEPING | TDI_SWAPPED)))
|
|
||||||
thread_suspend_one(td2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,6 +341,8 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags,
|
|||||||
if (flags & SLEEPQ_INTERRUPTIBLE) {
|
if (flags & SLEEPQ_INTERRUPTIBLE) {
|
||||||
td->td_flags |= TDF_SINTR;
|
td->td_flags |= TDF_SINTR;
|
||||||
td->td_flags &= ~TDF_SLEEPABORT;
|
td->td_flags &= ~TDF_SLEEPABORT;
|
||||||
|
if (flags & SLEEPQ_STOP_ON_BDRY)
|
||||||
|
td->td_flags |= TDF_SBDRY;
|
||||||
}
|
}
|
||||||
thread_unlock(td);
|
thread_unlock(td);
|
||||||
}
|
}
|
||||||
@ -378,7 +380,7 @@ sleepq_catch_signals(void *wchan, int pri)
|
|||||||
struct thread *td;
|
struct thread *td;
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
struct sigacts *ps;
|
struct sigacts *ps;
|
||||||
int sig, ret;
|
int sig, ret, stop_allowed;
|
||||||
|
|
||||||
td = curthread;
|
td = curthread;
|
||||||
p = curproc;
|
p = curproc;
|
||||||
@ -395,6 +397,8 @@ sleepq_catch_signals(void *wchan, int pri)
|
|||||||
sleepq_switch(wchan, pri);
|
sleepq_switch(wchan, pri);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
stop_allowed = (td->td_flags & TDF_SBDRY) ? SIG_STOP_NOT_ALLOWED :
|
||||||
|
SIG_STOP_ALLOWED;
|
||||||
thread_unlock(td);
|
thread_unlock(td);
|
||||||
mtx_unlock_spin(&sc->sc_lock);
|
mtx_unlock_spin(&sc->sc_lock);
|
||||||
CTR3(KTR_PROC, "sleepq catching signals: thread %p (pid %ld, %s)",
|
CTR3(KTR_PROC, "sleepq catching signals: thread %p (pid %ld, %s)",
|
||||||
@ -402,7 +406,7 @@ sleepq_catch_signals(void *wchan, int pri)
|
|||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
ps = p->p_sigacts;
|
ps = p->p_sigacts;
|
||||||
mtx_lock(&ps->ps_mtx);
|
mtx_lock(&ps->ps_mtx);
|
||||||
sig = cursig(td);
|
sig = cursig(td, stop_allowed);
|
||||||
if (sig == 0) {
|
if (sig == 0) {
|
||||||
mtx_unlock(&ps->ps_mtx);
|
mtx_unlock(&ps->ps_mtx);
|
||||||
ret = thread_suspend_check(1);
|
ret = thread_suspend_check(1);
|
||||||
@ -560,7 +564,7 @@ sleepq_check_signals(void)
|
|||||||
|
|
||||||
/* We are no longer in an interruptible sleep. */
|
/* We are no longer in an interruptible sleep. */
|
||||||
if (td->td_flags & TDF_SINTR)
|
if (td->td_flags & TDF_SINTR)
|
||||||
td->td_flags &= ~TDF_SINTR;
|
td->td_flags &= ~(TDF_SINTR | TDF_SBDRY);
|
||||||
|
|
||||||
if (td->td_flags & TDF_SLEEPABORT) {
|
if (td->td_flags & TDF_SLEEPABORT) {
|
||||||
td->td_flags &= ~TDF_SLEEPABORT;
|
td->td_flags &= ~TDF_SLEEPABORT;
|
||||||
@ -682,7 +686,7 @@ sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri)
|
|||||||
|
|
||||||
td->td_wmesg = NULL;
|
td->td_wmesg = NULL;
|
||||||
td->td_wchan = NULL;
|
td->td_wchan = NULL;
|
||||||
td->td_flags &= ~TDF_SINTR;
|
td->td_flags &= ~(TDF_SINTR | TDF_SBDRY);
|
||||||
|
|
||||||
CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)",
|
CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)",
|
||||||
(void *)td, (long)td->td_proc->p_pid, td->td_name);
|
(void *)td, (long)td->td_proc->p_pid, td->td_name);
|
||||||
|
@ -221,7 +221,7 @@ ast(struct trapframe *framep)
|
|||||||
if (flags & TDF_NEEDSIGCHK) {
|
if (flags & TDF_NEEDSIGCHK) {
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
mtx_lock(&p->p_sigacts->ps_mtx);
|
mtx_lock(&p->p_sigacts->ps_mtx);
|
||||||
while ((sig = cursig(td)) != 0)
|
while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0)
|
||||||
postsig(sig);
|
postsig(sig);
|
||||||
mtx_unlock(&p->p_sigacts->ps_mtx);
|
mtx_unlock(&p->p_sigacts->ps_mtx);
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
@ -187,6 +187,7 @@
|
|||||||
#define PRIMASK 0x0ff
|
#define PRIMASK 0x0ff
|
||||||
#define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */
|
#define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */
|
||||||
#define PDROP 0x200 /* OR'd with pri to stop re-entry of interlock mutex */
|
#define PDROP 0x200 /* OR'd with pri to stop re-entry of interlock mutex */
|
||||||
|
#define PBDRY 0x400 /* for PCATCH stop is done on the user boundary */
|
||||||
|
|
||||||
#define NZERO 0 /* default "nice" */
|
#define NZERO 0 /* default "nice" */
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ do { \
|
|||||||
#define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */
|
#define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */
|
||||||
#define TDF_ASTPENDING 0x00000800 /* Thread has some asynchronous events. */
|
#define TDF_ASTPENDING 0x00000800 /* Thread has some asynchronous events. */
|
||||||
#define TDF_TIMOFAIL 0x00001000 /* Timeout from sleep after we were awake. */
|
#define TDF_TIMOFAIL 0x00001000 /* Timeout from sleep after we were awake. */
|
||||||
#define TDF_UNUSED2000 0x00002000 /* --available-- */
|
#define TDF_SBDRY 0x00002000 /* Stop only on usermode boundary. */
|
||||||
#define TDF_UPIBLOCKED 0x00004000 /* Thread blocked on user PI mutex. */
|
#define TDF_UPIBLOCKED 0x00004000 /* Thread blocked on user PI mutex. */
|
||||||
#define TDF_NEEDSUSPCHK 0x00008000 /* Thread may need to suspend. */
|
#define TDF_NEEDSUSPCHK 0x00008000 /* Thread may need to suspend. */
|
||||||
#define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */
|
#define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */
|
||||||
|
@ -311,10 +311,14 @@ extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */
|
|||||||
#define SIGIO_LOCKED() mtx_owned(&sigio_lock)
|
#define SIGIO_LOCKED() mtx_owned(&sigio_lock)
|
||||||
#define SIGIO_ASSERT(type) mtx_assert(&sigio_lock, type)
|
#define SIGIO_ASSERT(type) mtx_assert(&sigio_lock, type)
|
||||||
|
|
||||||
|
/* stop_allowed parameter for cursig */
|
||||||
|
#define SIG_STOP_ALLOWED 100
|
||||||
|
#define SIG_STOP_NOT_ALLOWED 101
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Machine-independent functions:
|
* Machine-independent functions:
|
||||||
*/
|
*/
|
||||||
int cursig(struct thread *td);
|
int cursig(struct thread *td, int stop_allowed);
|
||||||
void execsigs(struct proc *p);
|
void execsigs(struct proc *p);
|
||||||
void gsignal(int pgid, int sig);
|
void gsignal(int pgid, int sig);
|
||||||
void killproc(struct proc *p, char *why);
|
void killproc(struct proc *p, char *why);
|
||||||
|
@ -93,6 +93,8 @@ struct thread;
|
|||||||
#define SLEEPQ_SX 0x03 /* Used by an sx lock. */
|
#define SLEEPQ_SX 0x03 /* Used by an sx lock. */
|
||||||
#define SLEEPQ_LK 0x04 /* Used by a lockmgr. */
|
#define SLEEPQ_LK 0x04 /* Used by a lockmgr. */
|
||||||
#define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */
|
#define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */
|
||||||
|
#define SLEEPQ_STOP_ON_BDRY 0x200 /* Stop sleeping thread on
|
||||||
|
user mode boundary */
|
||||||
|
|
||||||
void init_sleepqueues(void);
|
void init_sleepqueues(void);
|
||||||
int sleepq_abort(struct thread *td, int intrval);
|
int sleepq_abort(struct thread *td, int intrval);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user