summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sig.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r--sys/kern/kern_sig.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 9c52707..e28bdc4 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2364,6 +2364,13 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval)
}
/*
+ * Don't awaken a sleeping thread for SIGSTOP if the
+ * STOP signal is deferred.
+ */
+ if ((prop & SA_STOP) && (td->td_flags & TDF_SBDRY))
+ goto out;
+
+ /*
* Give low priority threads a better chance to run.
*/
if (td->td_priority > PUSER)
@@ -2404,12 +2411,13 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending)
if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) &&
(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);
+ /*
+ * Once a thread is asleep with
+ * TDF_SBDRY set, it should never
+ * become suspended due to this check.
+ */
+ KASSERT(!TD_IS_SUSPENDED(td2),
+ ("thread with deferred stops suspended"));
} else if (!TD_IS_SUSPENDED(td2)) {
thread_suspend_one(td2);
}
@@ -2529,6 +2537,34 @@ tdsigcleanup(struct thread *td)
}
+/* Defer the delivery of SIGSTOP for the current thread. */
+void
+sigdeferstop(struct thread *td)
+{
+
+ KASSERT(!(td->td_flags & TDF_SBDRY),
+ ("attempt to set TDF_SBDRY recursively"));
+ thread_lock(td);
+ td->td_flags |= TDF_SBDRY;
+ thread_unlock(td);
+}
+
+/*
+ * Permit the delivery of SIGSTOP for the current thread. This does
+ * not immediately suspend if a stop was posted. Instead, the thread
+ * will suspend either via ast() or a subsequent interruptible sleep.
+ */
+void
+sigallowstop(struct thread *td)
+{
+
+ KASSERT(td->td_flags & TDF_SBDRY,
+ ("attempt to clear already-cleared TDF_SBDRY"));
+ thread_lock(td);
+ td->td_flags &= ~TDF_SBDRY;
+ thread_unlock(td);
+}
+
/*
* If the current process has received a signal (should be caught or cause
* termination, should interrupt current syscall), return the signal number.
@@ -2561,7 +2597,7 @@ issignal(struct thread *td, int stop_allowed)
SIGSETOR(sigpending, p->p_sigqueue.sq_signals);
SIGSETNAND(sigpending, td->td_sigmask);
- if (p->p_flag & P_PPWAIT)
+ if (p->p_flag & P_PPWAIT || td->td_flags & TDF_SBDRY)
SIG_STOPSIGMASK(sigpending);
if (SIGISEMPTY(sigpending)) /* no signal to send */
return (0);
@@ -2677,10 +2713,6 @@ issignal(struct thread *td, int stop_allowed)
(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");
OpenPOWER on IntegriCloud