From bf7652876b1a585b2e56512cf16b9bfddaf092a1 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 27 May 2006 01:51:27 +0000 Subject: [PATCH] Implement msleep(). This function is similar to the FreeBSD msleep() except it interlocks with a spinlock instead of a mutex. The spinlock must be exclusively held on entry. msleep() will atomically sleep and release the spinlock, then reacquire the spinlock when it wakes up. A novel approach to the interlock is used. DragonFly's tsleep/wakeup mechanism is a per-cpu mechanism, with a local array of cpu masks, one entry per hash index. A wakeup simpy sends an IPI message to each target cpu whos bitmap bit is set in the ident's hash entry. This allows us to interlock simply by entering a critical section and setting our bit, then releasing the mutex, then tsleep()ing as per normal. No additional locks are required. The critical section will delay any wakeup race with us simply by delaying the IPI message that is potentially in-transit to our cpu. Requested-by: Numerous people, and its time has come now. --- sys/kern/kern_synch.c | 42 ++++++++++++++++++++++++++++++++++++++---- sys/sys/systm.h | 6 ++++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index cd602e6fbc..8d9bf1e2b0 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -37,7 +37,7 @@ * * @(#)kern_synch.c 8.9 (Berkeley) 5/19/95 * $FreeBSD: src/sys/kern/kern_synch.c,v 1.87.2.6 2002/10/13 07:29:53 kbyanc Exp $ - * $DragonFly: src/sys/kern/kern_synch.c,v 1.61 2006/05/25 07:36:34 dillon Exp $ + * $DragonFly: src/sys/kern/kern_synch.c,v 1.62 2006/05/27 01:51:26 dillon Exp $ */ #include "opt_ktrace.h" @@ -50,7 +50,6 @@ #include #include #include -#include #include #ifdef KTRACE #include @@ -59,6 +58,9 @@ #include #include +#include +#include + #include #include #include @@ -515,12 +517,44 @@ resume: * There isn't much of a point to this function unless you call it while * holding a critical section. */ +static __inline void +_tsleep_interlock(globaldata_t gd, void *ident) +{ + int id = LOOKUP(ident); + + atomic_set_int(&slpque_cpumasks[id], gd->gd_cpumask); +} + void tsleep_interlock(void *ident) { - int id = LOOKUP(ident); + _tsleep_interlock(mycpu, ident); +} - atomic_set_int(&slpque_cpumasks[id], mycpu->gd_cpumask); +/* + * Interlocked spinlock sleep. An exclusively held spinlock must + * be passed to msleep(). The function will atomically release the + * spinlock and tsleep on the ident, then reacquire the spinlock and + * return. + * + * This routine is fairly important along the critical path, so optimize it + * heavily. + */ +int +msleep(void *ident, struct spinlock *spin, int flags, + const char *wmesg, int timo) +{ + globaldata_t gd = mycpu; + int error; + + crit_enter_gd(gd); + _tsleep_interlock(gd, ident); + spin_unlock_wr_quick(gd, spin); + error = tsleep(ident, flags, wmesg, timo); + spin_lock_wr_quick(gd, spin); + crit_exit_gd(gd); + + return (error); } /* diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 88b18eff66..e0cfaba307 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -37,7 +37,7 @@ * * @(#)systm.h 8.7 (Berkeley) 3/29/95 * $FreeBSD: src/sys/sys/systm.h,v 1.111.2.18 2002/12/17 18:04:02 sam Exp $ - * $DragonFly: src/sys/sys/systm.h,v 1.37 2006/05/21 03:43:47 dillon Exp $ + * $DragonFly: src/sys/sys/systm.h,v 1.38 2006/05/27 01:51:27 dillon Exp $ */ #ifndef _SYS_SYSTM_H_ @@ -109,6 +109,7 @@ extern int clocks_running; /* timing/timeout subsystem is operational */ */ struct intrframe; +struct spinlock; struct malloc_type; struct proc; struct xwait; @@ -296,7 +297,8 @@ extern watchdog_tickle_fn wdog_tickler; * Common `proc' functions are declared here so that proc.h can be included * less often. */ -int tsleep (void *chan, int slpflags, const char *wmesg, int timo); +int tsleep (void *, int, const char *, int); +int msleep (void *, struct spinlock *, int, const char *, int); void tsleep_interlock (void *chan); void tstop (struct proc *); void wakeup (void *chan); -- 2.41.0