1
0
mirror of https://github.com/openbsd/src.git synced 2026-04-25 06:35:46 +00:00

Move kernel locking inside the sleep machinery. This enables calling

rwsleep(9) with PCATCH and rw_enter(9) with RW_INTR without the kernel
lock. In addition, now tsleep(9) with PCATCH should be safe to use
without the kernel lock if the sleep is purely time-based.

Tested by anton@, cheloha@, chris@
OK anton@, cheloha@
This commit is contained in:
visa
2019-11-30 11:19:17 +00:00
parent 3db50d8956
commit de60e9182e
5 changed files with 50 additions and 23 deletions

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: drm_linux.c,v 1.50 2019/10/23 10:17:40 jsg Exp $ */
/* $OpenBSD: drm_linux.c,v 1.51 2019/11/30 11:19:17 visa Exp $ */
/*
* Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
* Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org>
@@ -91,7 +91,7 @@ schedule_timeout(long timeout)
sleep_setup(&sls, sch_ident, sch_priority, "schto");
if (timeout != MAX_SCHEDULE_TIMEOUT)
sleep_setup_timeout(&sls, timeout);
sleep_setup_signal(&sls, sch_priority);
sleep_setup_signal(&sls);
wait = (sch_proc == curproc && timeout > 0);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: kern_rwlock.c,v 1.43 2019/11/29 12:41:33 mpi Exp $ */
/* $OpenBSD: kern_rwlock.c,v 1.44 2019/11/30 11:19:17 visa Exp $ */
/*
* Copyright (c) 2002, 2003 Artur Grabowski <art@openbsd.org>
@@ -231,7 +231,7 @@ rw_enter(struct rwlock *rwl, int flags)
*/
unsigned int spin = (_kernel_lock_held()) ? 0 : RW_SPINS;
#endif
int error;
int error, prio;
#ifdef WITNESS
int lop_flags;
@@ -273,9 +273,12 @@ retry:
if (flags & RW_NOSLEEP)
return (EBUSY);
sleep_setup(&sls, rwl, op->wait_prio, rwl->rwl_name);
prio = op->wait_prio;
if (flags & RW_INTR)
sleep_setup_signal(&sls, op->wait_prio | PCATCH);
prio |= PCATCH;
sleep_setup(&sls, rwl, prio, rwl->rwl_name);
if (flags & RW_INTR)
sleep_setup_signal(&sls);
do_sleep = !rw_cas(&rwl->rwl_owner, o, set);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: kern_synch.c,v 1.154 2019/11/12 04:20:21 visa Exp $ */
/* $OpenBSD: kern_synch.c,v 1.155 2019/11/30 11:19:17 visa Exp $ */
/* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
/*
@@ -147,7 +147,7 @@ tsleep(const volatile void *ident, int priority, const char *wmesg, int timo)
sleep_setup(&sls, ident, priority, wmesg);
sleep_setup_timeout(&sls, timo);
sleep_setup_signal(&sls, priority);
sleep_setup_signal(&sls);
return sleep_finish_all(&sls, 1);
}
@@ -207,6 +207,9 @@ msleep(const volatile void *ident, struct mutex *mtx, int priority,
KASSERT((priority & ~(PRIMASK | PCATCH | PNORELOCK)) == 0);
KASSERT(mtx != NULL);
if (priority & PCATCH)
KERNEL_ASSERT_LOCKED();
if (cold || panicstr) {
/*
* After a panic, or during autoconfiguration,
@@ -233,7 +236,7 @@ msleep(const volatile void *ident, struct mutex *mtx, int priority,
sleep_setup(&sls, ident, priority, wmesg);
sleep_setup_timeout(&sls, timo);
sleep_setup_signal(&sls, priority);
sleep_setup_signal(&sls);
/* XXX - We need to make sure that the mutex doesn't
* unblock splsched. This can be made a bit more
@@ -293,7 +296,7 @@ rwsleep(const volatile void *ident, struct rwlock *rwl, int priority,
sleep_setup(&sls, ident, priority, wmesg);
sleep_setup_timeout(&sls, timo);
sleep_setup_signal(&sls, priority);
sleep_setup_signal(&sls);
rw_exit(rwl);
@@ -342,11 +345,22 @@ sleep_setup(struct sleep_state *sls, const volatile void *ident, int prio,
panic("tsleep: not SONPROC");
#endif
sls->sls_catch = 0;
sls->sls_catch = prio & PCATCH;
sls->sls_do_sleep = 1;
sls->sls_locked = 0;
sls->sls_sig = 1;
sls->sls_timeout = 0;
/*
* The kernel has to be locked for signal processing.
* This is done here and not in sleep_setup_signal() because
* KERNEL_LOCK() has to be taken before SCHED_LOCK().
*/
if (sls->sls_catch != 0) {
KERNEL_LOCK();
sls->sls_locked = 1;
}
SCHED_LOCK(sls->sls_s);
p->p_wchan = ident;
@@ -417,13 +431,16 @@ sleep_finish_timeout(struct sleep_state *sls)
}
void
sleep_setup_signal(struct sleep_state *sls, int prio)
sleep_setup_signal(struct sleep_state *sls)
{
struct proc *p = curproc;
if ((sls->sls_catch = (prio & PCATCH)) == 0)
if (sls->sls_catch == 0)
return;
/* sleep_setup() has locked the kernel. */
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
@@ -449,20 +466,26 @@ int
sleep_finish_signal(struct sleep_state *sls)
{
struct proc *p = curproc;
int error;
int error = 0;
if (sls->sls_catch != 0) {
if ((error = single_thread_check(p, 1)))
return (error);
if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) {
KERNEL_ASSERT_LOCKED();
error = single_thread_check(p, 1);
if (error == 0 &&
(sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0)) {
if (p->p_p->ps_sigacts->ps_sigintr &
sigmask(sls->sls_sig))
return (EINTR);
return (ERESTART);
error = EINTR;
else
error = ERESTART;
}
}
return (0);
if (sls->sls_locked)
KERNEL_UNLOCK();
return (error);
}
/*

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: proc.h,v 1.281 2019/11/29 21:32:04 guenther Exp $ */
/* $OpenBSD: proc.h,v 1.282 2019/11/30 11:19:17 visa Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -611,6 +611,7 @@ struct sleep_state {
int sls_s;
int sls_catch;
int sls_do_sleep;
int sls_locked;
int sls_sig;
int sls_timeout;
};

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: systm.h,v 1.143 2019/11/02 16:56:18 cheloha Exp $ */
/* $OpenBSD: systm.h,v 1.144 2019/11/30 11:19:17 visa Exp $ */
/* $NetBSD: systm.h,v 1.50 1996/06/09 04:55:09 briggs Exp $ */
/*-
@@ -246,7 +246,7 @@ struct sleep_state;
void sleep_setup(struct sleep_state *, const volatile void *, int,
const char *);
void sleep_setup_timeout(struct sleep_state *, int);
void sleep_setup_signal(struct sleep_state *, int);
void sleep_setup_signal(struct sleep_state *);
void sleep_finish(struct sleep_state *, int);
int sleep_finish_timeout(struct sleep_state *);
int sleep_finish_signal(struct sleep_state *);