From: visa Date: Sun, 12 Jun 2022 10:36:04 +0000 (+0000) Subject: Allow sleeping while clearing a sleep timeout X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ef428a5ea72686171402e8ebffa1276567c0409e;p=openbsd Allow sleeping while clearing a sleep timeout Since sys/kern/kern_timeout.c r1.84, timeout_barrier() has used sleeping with soft-interrupt-driven timeouts. Adjust the sleep machinery so that the timeout clearing can block in sleep_finish(). This adds one step of recursion inside sleep_finish(). However, the sleep queue handling does not recurse because sleep_finish() completes it before calling timeout_del_barrier(). This fixes the following panic: panic: kernel diagnostic assertion "(p->p_flag & P_TIMEOUT) == 0" failed: file "sys/kern/kern_synch.c", line 373 Stopped at db_enter+0x10: popq %rbp db_enter() at db_enter+0x10 panic() at panic+0xbf __assert() at __assert+0x25 sleep_setup() at sleep_setup+0x1d8 cond_wait() at cond_wait+0x46 timeout_barrier() at timeout_barrier+0x109 timeout_del_barrier() at timeout_del_barrier+0xa2 sleep_finish() at sleep_finish+0x16d tsleep() at tsleep+0xb2 sys_nanosleep() at sys_nanosleep+0x12d syscall() at syscall+0x374 OK mpi@ dlg@ --- diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 5f3e8be3482..917b6047d82 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_synch.c,v 1.187 2022/05/13 15:32:00 claudio Exp $ */ +/* $OpenBSD: kern_synch.c,v 1.188 2022/06/12 10:36:04 visa Exp $ */ /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */ /* @@ -370,8 +370,8 @@ sleep_setup(struct sleep_state *sls, const volatile void *ident, int prio, p->p_slppri = prio & PRIMASK; TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_runq); - KASSERT((p->p_flag & P_TIMEOUT) == 0); if (timo) { + KASSERT((p->p_flag & P_TIMEOUT) == 0); sls->sls_timeout = 1; timeout_add(&p->p_sleep_to, timo); } @@ -432,13 +432,12 @@ sleep_finish(struct sleep_state *sls, int do_sleep) if (sls->sls_timeout) { if (p->p_flag & P_TIMEOUT) { - atomic_clearbits_int(&p->p_flag, P_TIMEOUT); error1 = EWOULDBLOCK; } else { - /* This must not sleep. */ + /* This can sleep. It must not use timeouts. */ timeout_del_barrier(&p->p_sleep_to); - KASSERT((p->p_flag & P_TIMEOUT) == 0); } + atomic_clearbits_int(&p->p_flag, P_TIMEOUT); } /* Check if thread was woken up because of a unwind or signal */