diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2020-04-06 07:52:13 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2020-04-06 07:52:13 +0000 |
commit | 882157d3f7092a65304132f1e15950f974abb030 (patch) | |
tree | d848ae595daf4acf2b27038b646409b9ad5f32c3 /sys | |
parent | 2060ccf0a19bb2432fe57149c593f243cd14a32f (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.c | 33 | ||||
-rw-r--r-- | sys/sys/proc.h | 3 |
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; }; |