summaryrefslogtreecommitdiff
path: root/sys/kern/kern_synch.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_synch.c')
-rw-r--r--sys/kern/kern_synch.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 928187e8e53..6d65d7fee19 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_synch.c,v 1.169 2020/03/31 09:34:19 claudio Exp $ */
+/* $OpenBSD: kern_synch.c,v 1.170 2020/04/06 07:52:12 claudio Exp $ */
/* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
/*
@@ -359,7 +359,8 @@ sleep_setup(struct sleep_state *sls, const volatile void *ident, int prio,
sls->sls_catch = prio & PCATCH;
sls->sls_do_sleep = 1;
sls->sls_locked = 0;
- sls->sls_sig = 1;
+ sls->sls_sig = 0;
+ sls->sls_unwind = 0;
sls->sls_timeout = 0;
/*
@@ -471,16 +472,20 @@ sleep_setup_signal(struct sleep_state *sls)
KERNEL_ASSERT_LOCKED();
/*
- * We put ourselves on the sleep queue and start our timeout
- * before calling CURSIG, as we could stop there, and a wakeup
- * or a SIGCONT (or both) could occur while we were stopped.
- * A SIGCONT would cause us to be marked as SSLEEP
- * without resuming us, thus we must be ready for sleep
- * when CURSIG is called. If the wakeup happens while we're
- * stopped, p->p_wchan will be 0 upon return from CURSIG.
+ * We put ourselves on the sleep queue and start our timeout before
+ * calling single_thread_check or CURSIG, as we could stop there, and
+ * a wakeup or a SIGCONT (or both) could occur while we were stopped.
+ * A SIGCONT would cause us to be marked as SSLEEP without resuming us,
+ * thus we must be ready for sleep when CURSIG is called. If the
+ * wakeup happens while we're stopped, p->p_wchan will be 0 upon
+ * return from single_thread_check or CURSIG. In that case we should
+ * not go to sleep. If single_thread_check returns an error we need
+ * to unwind immediately. That's achieved by saving the return value
+ * in sls->sl_unwind and checking it later in sleep_finish_signal.
*/
atomic_setbits_int(&p->p_flag, P_SINTR);
- if ((p->p_flag & P_SUSPSINGLE) || (sls->sls_sig = CURSIG(p)) != 0) {
+ if ((sls->sls_unwind = single_thread_check(p, 1)) != 0 ||
+ (sls->sls_sig = CURSIG(p)) != 0) {
unsleep(p);
p->p_stat = SONPROC;
sls->sls_do_sleep = 0;
@@ -499,9 +504,11 @@ sleep_finish_signal(struct sleep_state *sls)
if (sls->sls_catch != 0) {
KERNEL_ASSERT_LOCKED();
- error = single_thread_check(p, 1);
- if (error == 0 &&
- (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0)) {
+ if (sls->sls_unwind != 0 ||
+ (sls->sls_unwind = single_thread_check(p, 1)) != 0)
+ error = sls->sls_unwind;
+ else if (sls->sls_sig != 0 ||
+ (sls->sls_sig = CURSIG(p)) != 0) {
if (p->p_p->ps_sigacts->ps_sigintr &
sigmask(sls->sls_sig))
error = EINTR;