summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cddl/compat/opensolaris/sys/sig.h2
-rw-r--r--sys/kern/kern_sig.c37
-rw-r--r--sys/kern/kern_synch.c2
-rw-r--r--sys/kern/kern_thread.c21
-rw-r--r--sys/kern/subr_sleepqueue.c12
-rw-r--r--sys/kern/subr_trap.c2
-rw-r--r--sys/sys/param.h1
-rw-r--r--sys/sys/proc.h2
-rw-r--r--sys/sys/signalvar.h6
-rw-r--r--sys/sys/sleepqueue.h2
10 files changed, 58 insertions, 29 deletions
diff --git a/sys/cddl/compat/opensolaris/sys/sig.h b/sys/cddl/compat/opensolaris/sys/sig.h
index 985896e..5053797 100644
--- a/sys/cddl/compat/opensolaris/sys/sig.h
+++ b/sys/cddl/compat/opensolaris/sys/sig.h
@@ -55,7 +55,7 @@ issig(int why)
p = td->td_proc;
PROC_LOCK(p);
mtx_lock(&p->p_sigacts->ps_mtx);
- sig = cursig(td);
+ sig = cursig(td, SIG_STOP_ALLOWED);
mtx_unlock(&p->p_sigacts->ps_mtx);
PROC_UNLOCK(p);
if (sig != 0)
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 3225754..cdf757d 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -100,7 +100,7 @@ SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 2, "int");
static int coredump(struct thread *);
static char *expand_name(const char *, uid_t, pid_t);
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 void tdsigwakeup(struct thread *, int, sig_t, 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().
*/
int
-cursig(struct thread *td)
+cursig(struct thread *td, int stop_allowed)
{
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);
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);
SIGDELSET(td->td_sigmask, i);
mtx_lock(&ps->ps_mtx);
- sig = cursig(td);
+ sig = cursig(td, SIG_STOP_ALLOWED);
mtx_unlock(&ps->ps_mtx);
if (sig)
goto out;
@@ -2310,18 +2312,28 @@ static void
sig_suspend_threads(struct thread *td, struct proc *p, int sending)
{
struct thread *td2;
+ int wakeup_swapper;
PROC_LOCK_ASSERT(p, MA_OWNED);
PROC_SLOCK_ASSERT(p, MA_OWNED);
+ wakeup_swapper = 0;
FOREACH_THREAD_IN_PROC(p, td2) {
thread_lock(td2);
td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) &&
- (td2->td_flags & TDF_SINTR) &&
- !TD_IS_SUSPENDED(td2)) {
- thread_suspend_one(td2);
- } else {
+ (td2->td_flags & TDF_SINTR)) {
+ if (td2->td_flags & TDF_SBDRY) {
+ if (TD_IS_SUSPENDED(td2))
+ 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)
td2->td_flags |= TDF_ASTPENDING;
#ifdef SMP
@@ -2331,6 +2343,8 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending)
}
thread_unlock(td2);
}
+ if (wakeup_swapper)
+ kick_proc0();
}
int
@@ -2387,8 +2401,7 @@ stopme:
* postsig(sig);
*/
static int
-issignal(td)
- struct thread *td;
+issignal(struct thread *td, int stop_allowed)
{
struct proc *p;
struct sigacts *ps;
@@ -2506,6 +2519,10 @@ issignal(td)
(p->p_pgrp->pg_jobc == 0 &&
prop & SA_TTYSTOP))
break; /* == ignore */
+
+ /* Ignore, but do not drop the stop signal. */
+ if (stop_allowed != SIG_STOP_ALLOWED)
+ return (sig);
mtx_unlock(&ps->ps_mtx);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
&p->p_mtx.lock_object, "Catching SIGSTOP");
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index aad12b6..30a8bb3 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -188,6 +188,8 @@ _sleep(void *ident, struct lock_object *lock, int priority,
flags = SLEEPQ_SLEEP;
if (catch)
flags |= SLEEPQ_INTERRUPTIBLE;
+ if (priority & PBDRY)
+ flags |= SLEEPQ_STOP_ON_BDRY;
sleepq_lock(ident);
CTR5(KTR_PROC, "sleep: thread %ld (pid %ld, %s) on %s (%p)",
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index f04b2a6..d47bd8c 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -598,18 +598,17 @@ thread_single(int mode)
wakeup_swapper |=
sleepq_abort(td2, ERESTART);
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:
- 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;
}
}
diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c
index 01fcc73..b3ae6fd 100644
--- a/sys/kern/subr_sleepqueue.c
+++ b/sys/kern/subr_sleepqueue.c
@@ -341,6 +341,8 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags,
if (flags & SLEEPQ_INTERRUPTIBLE) {
td->td_flags |= TDF_SINTR;
td->td_flags &= ~TDF_SLEEPABORT;
+ if (flags & SLEEPQ_STOP_ON_BDRY)
+ td->td_flags |= TDF_SBDRY;
}
thread_unlock(td);
}
@@ -378,7 +380,7 @@ sleepq_catch_signals(void *wchan, int pri)
struct thread *td;
struct proc *p;
struct sigacts *ps;
- int sig, ret;
+ int sig, ret, stop_allowed;
td = curthread;
p = curproc;
@@ -395,6 +397,8 @@ sleepq_catch_signals(void *wchan, int pri)
sleepq_switch(wchan, pri);
return (0);
}
+ stop_allowed = (td->td_flags & TDF_SBDRY) ? SIG_STOP_NOT_ALLOWED :
+ SIG_STOP_ALLOWED;
thread_unlock(td);
mtx_unlock_spin(&sc->sc_lock);
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);
ps = p->p_sigacts;
mtx_lock(&ps->ps_mtx);
- sig = cursig(td);
+ sig = cursig(td, stop_allowed);
if (sig == 0) {
mtx_unlock(&ps->ps_mtx);
ret = thread_suspend_check(1);
@@ -560,7 +564,7 @@ sleepq_check_signals(void)
/* We are no longer in an interruptible sleep. */
if (td->td_flags & TDF_SINTR)
- td->td_flags &= ~TDF_SINTR;
+ td->td_flags &= ~(TDF_SINTR | TDF_SBDRY);
if (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_wchan = NULL;
- td->td_flags &= ~TDF_SINTR;
+ td->td_flags &= ~(TDF_SINTR | TDF_SBDRY);
CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)",
(void *)td, (long)td->td_proc->p_pid, td->td_name);
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index 0f4636e..6d60ddb 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -221,7 +221,7 @@ ast(struct trapframe *framep)
if (flags & TDF_NEEDSIGCHK) {
PROC_LOCK(p);
mtx_lock(&p->p_sigacts->ps_mtx);
- while ((sig = cursig(td)) != 0)
+ while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0)
postsig(sig);
mtx_unlock(&p->p_sigacts->ps_mtx);
PROC_UNLOCK(p);
diff --git a/sys/sys/param.h b/sys/sys/param.h
index c2c5e28..a7b59d3 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -187,6 +187,7 @@
#define PRIMASK 0x0ff
#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 PBDRY 0x400 /* for PCATCH stop is done on the user boundary */
#define NZERO 0 /* default "nice" */
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 0a4b79c..b65db62 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -320,7 +320,7 @@ do { \
#define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */
#define TDF_ASTPENDING 0x00000800 /* Thread has some asynchronous events. */
#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_NEEDSUSPCHK 0x00008000 /* Thread may need to suspend. */
#define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */
diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h
index dc09226..89b40f0 100644
--- a/sys/sys/signalvar.h
+++ b/sys/sys/signalvar.h
@@ -311,10 +311,14 @@ extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */
#define SIGIO_LOCKED() mtx_owned(&sigio_lock)
#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:
*/
-int cursig(struct thread *td);
+int cursig(struct thread *td, int stop_allowed);
void execsigs(struct proc *p);
void gsignal(int pgid, int sig);
void killproc(struct proc *p, char *why);
diff --git a/sys/sys/sleepqueue.h b/sys/sys/sleepqueue.h
index 0d1f361..362945a 100644
--- a/sys/sys/sleepqueue.h
+++ b/sys/sys/sleepqueue.h
@@ -93,6 +93,8 @@ struct thread;
#define SLEEPQ_SX 0x03 /* Used by an sx lock. */
#define SLEEPQ_LK 0x04 /* Used by a lockmgr. */
#define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */
+#define SLEEPQ_STOP_ON_BDRY 0x200 /* Stop sleeping thread on
+ user mode boundary */
void init_sleepqueues(void);
int sleepq_abort(struct thread *td, int intrval);
OpenPOWER on IntegriCloud