diff options
author | jhb <jhb@FreeBSD.org> | 2007-03-09 16:27:11 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-03-09 16:27:11 +0000 |
commit | 60ad130f466f4ce8bb90b4d47775516afbfb2e48 (patch) | |
tree | 71366da8c5df1e7210aad9d816166233c0107eff /sys | |
parent | b03e9e93edda2ff558f1eb141e812c32a2931dc2 (diff) | |
download | FreeBSD-src-60ad130f466f4ce8bb90b4d47775516afbfb2e48.zip FreeBSD-src-60ad130f466f4ce8bb90b4d47775516afbfb2e48.tar.gz |
Add two new function pointers 'lc_lock' and 'lc_unlock' to lock classes.
These functions are intended to be used to drop a lock and then reacquire
it when doing an sleep such as msleep(9). Both functions accept a
'struct lock_object *' as their first parameter. The 'lc_unlock' function
returns an integer that is then passed as the second paramter to the
subsequent 'lc_lock' function. This can be used to communicate state.
For example, sx locks and rwlocks use this to indicate if the lock was
share/read locked vs exclusive/write locked.
Currently, spin mutexes and lockmgr locks do not provide working lc_lock
and lc_unlock functions.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_lock.c | 22 | ||||
-rw-r--r-- | sys/kern/kern_mutex.c | 40 | ||||
-rw-r--r-- | sys/kern/kern_rwlock.c | 33 | ||||
-rw-r--r-- | sys/kern/kern_sx.c | 33 | ||||
-rw-r--r-- | sys/sys/lock.h | 9 |
5 files changed, 134 insertions, 3 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 8533836..02254a4 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -64,22 +64,38 @@ __FBSDID("$FreeBSD$"); #include <ddb/ddb.h> static void db_show_lockmgr(struct lock_object *lock); #endif - +static void lock_lockmgr(struct lock_object *lock, int how); +static int unlock_lockmgr(struct lock_object *lock); struct lock_class lock_class_lockmgr = { .lc_name = "lockmgr", .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE, #ifdef DDB - .lc_ddb_show = db_show_lockmgr + .lc_ddb_show = db_show_lockmgr, #endif + .lc_lock = lock_lockmgr, + .lc_unlock = unlock_lockmgr, }; - /* * Locking primitives implementation. * Locks provide shared/exclusive sychronization. */ +void +lock_lockmgr(struct lock_object *lock, int how) +{ + + panic("lockmgr locks do not support sleep interlocking"); +} + +int +unlock_lockmgr(struct lock_object *lock) +{ + + panic("lockmgr locks do not support sleep interlocking"); +} + #define COUNT(td, x) if ((td)) (td)->td_locks += (x) #define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \ LK_SHARE_NONZERO | LK_WAIT_NONZERO) diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c index 0fd5d7e..b327ef8 100644 --- a/sys/kern/kern_mutex.c +++ b/sys/kern/kern_mutex.c @@ -91,6 +91,10 @@ __FBSDID("$FreeBSD$"); #ifdef DDB static void db_show_mtx(struct lock_object *lock); #endif +static void lock_mtx(struct lock_object *lock, int how); +static void lock_spin(struct lock_object *lock, int how); +static int unlock_mtx(struct lock_object *lock); +static int unlock_spin(struct lock_object *lock); /* * Lock classes for sleep and spin mutexes. @@ -101,6 +105,8 @@ struct lock_class lock_class_mtx_sleep = { #ifdef DDB .lc_ddb_show = db_show_mtx, #endif + .lc_lock = lock_mtx, + .lc_unlock = unlock_mtx, }; struct lock_class lock_class_mtx_spin = { .lc_name = "spin mutex", @@ -108,6 +114,8 @@ struct lock_class lock_class_mtx_spin = { #ifdef DDB .lc_ddb_show = db_show_mtx, #endif + .lc_lock = lock_spin, + .lc_unlock = unlock_spin, }; /* @@ -130,6 +138,38 @@ static inline void lock_profile_init(void) static inline void lock_profile_init(void) {;} #endif +void +lock_mtx(struct lock_object *lock, int how) +{ + + mtx_lock((struct mtx *)lock); +} + +void +lock_spin(struct lock_object *lock, int how) +{ + + panic("spin locks can only use msleep_spin"); +} + +int +unlock_mtx(struct lock_object *lock) +{ + struct mtx *m; + + m = (struct mtx *)lock; + mtx_assert(m, MA_OWNED | MA_NOTRECURSED); + mtx_unlock(m); + return (0); +} + +int +unlock_spin(struct lock_object *lock) +{ + + panic("spin locks can only use msleep_spin"); +} + /* * Function versions of the inlined __mtx_* macros. These are used by * modules and can also be called from assembly language if needed. diff --git a/sys/kern/kern_rwlock.c b/sys/kern/kern_rwlock.c index 59d6d83..b043e3e 100644 --- a/sys/kern/kern_rwlock.c +++ b/sys/kern/kern_rwlock.c @@ -52,6 +52,8 @@ __FBSDID("$FreeBSD$"); static void db_show_rwlock(struct lock_object *lock); #endif +static void lock_rw(struct lock_object *lock, int how); +static int unlock_rw(struct lock_object *lock); struct lock_class lock_class_rw = { .lc_name = "rw", @@ -59,6 +61,8 @@ struct lock_class lock_class_rw = { #ifdef DDB .lc_ddb_show = db_show_rwlock, #endif + .lc_lock = lock_rw, + .lc_unlock = unlock_rw, }; /* @@ -81,6 +85,34 @@ struct lock_class lock_class_rw = { #endif void +lock_rw(struct lock_object *lock, int how) +{ + struct rwlock *rw; + + rw = (struct rwlock *)lock; + if (how) + rw_wlock(rw); + else + rw_rlock(rw); +} + +int +unlock_rw(struct lock_object *lock) +{ + struct rwlock *rw; + + rw = (struct rwlock *)lock; + rw_assert(rw, RA_LOCKED | LA_NOTRECURSED); + if (rw->rw_lock & RW_LOCK_READ) { + rw_runlock(rw); + return (0); + } else { + rw_wunlock(rw); + return (1); + } +} + +void rw_init(struct rwlock *rw, const char *name) { @@ -758,6 +790,7 @@ _rw_assert(struct rwlock *rw, int what, const char *file, int line) return; switch (what) { case RA_LOCKED: + case RA_LOCKED | LA_NOTRECURSED: case RA_RLOCKED: #ifdef WITNESS witness_assert(&rw->rw_object, what, file, line); diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c index d41f94e..5499171 100644 --- a/sys/kern/kern_sx.c +++ b/sys/kern/kern_sx.c @@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$"); static void db_show_sx(struct lock_object *lock); #endif +static void lock_sx(struct lock_object *lock, int how); +static int unlock_sx(struct lock_object *lock); struct lock_class lock_class_sx = { .lc_name = "sx", @@ -61,6 +63,8 @@ struct lock_class lock_class_sx = { #ifdef DDB .lc_ddb_show = db_show_sx, #endif + .lc_lock = lock_sx, + .lc_unlock = unlock_sx, }; #ifndef INVARIANTS @@ -68,6 +72,34 @@ struct lock_class lock_class_sx = { #endif void +lock_sx(struct lock_object *lock, int how) +{ + struct sx *sx; + + sx = (struct sx *)lock; + if (how) + sx_xlock(sx); + else + sx_slock(sx); +} + +int +unlock_sx(struct lock_object *lock) +{ + struct sx *sx; + + sx = (struct sx *)lock; + sx_assert(sx, SX_LOCKED | LA_NOTRECURSED); + if (sx_xlocked(sx)) { + sx_xunlock(sx); + return (1); + } else { + sx_sunlock(sx); + return (0); + } +} + +void sx_sysinit(void *arg) { struct sx_args *sargs = arg; @@ -348,6 +380,7 @@ _sx_assert(struct sx *sx, int what, const char *file, int line) return; switch (what) { case SX_LOCKED: + case SX_LOCKED | LA_NOTRECURSED: case SX_SLOCKED: #ifdef WITNESS witness_assert(&sx->sx_object, what, file, line); diff --git a/sys/sys/lock.h b/sys/sys/lock.h index a30a595..3a3b4d2 100644 --- a/sys/sys/lock.h +++ b/sys/sys/lock.h @@ -45,12 +45,21 @@ struct thread; * an error to perform any type of context switch while holding a spin lock. * Also, for an individual lock to be recursable, its class must allow * recursion and the lock itself must explicitly allow recursion. + * + * The 'lc_ddb_show' function pointer is used to dump class-specific + * data for the 'show lock' DDB command. The 'lc_lock' and + * 'lc_unlock' function pointers are used in sleep(9) and cv_wait(9) + * to lock and unlock locks while blocking on a sleep queue. The + * return value of 'lc_unlock' will be passed to 'lc_lock' on resume + * to allow communication of state between the two routines. */ struct lock_class { const char *lc_name; u_int lc_flags; void (*lc_ddb_show)(struct lock_object *lock); + void (*lc_lock)(struct lock_object *lock, int how); + int (*lc_unlock)(struct lock_object *lock); }; #define LC_SLEEPLOCK 0x00000001 /* Sleep lock. */ |