summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2020-04-06 07:52:13 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2020-04-06 07:52:13 +0000
commit882157d3f7092a65304132f1e15950f974abb030 (patch)
treed848ae595daf4acf2b27038b646409b9ad5f32c3 /sys
parent2060ccf0a19bb2432fe57149c593f243cd14a32f (diff)
Fix single thread behaviour in sleep_setup_signal(). If a thread needs to
suspend (SINGLE_SUSPEND or SINGLE_PTRACE) it needs to do this in sleep_setup_signal(). This way the case where single_thread_clear() is called before the sleep gets its wakeup call can be correctly handled and the thread is put back to sleep in sleep_finish(). If the wakeup happens before unsuspend then p_wchan is 0 and the thread will not go to sleep again. In case of a unwind an error is returned causing the thread to return immediatly with that error. With and OK mpi@ kettenis@
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_synch.c33
-rw-r--r--sys/sys/proc.h3
2 files changed, 22 insertions, 14 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;
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index a7ac9db5229..a25cb52951d 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.293 2020/03/20 08:14:07 claudio Exp $ */
+/* $OpenBSD: proc.h,v 1.294 2020/04/06 07:52:12 claudio Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -610,6 +610,7 @@ struct sleep_state {
int sls_do_sleep;
int sls_locked;
int sls_sig;
+ int sls_unwind;
int sls_timeout;
};