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.
This commit is contained in:
John Baldwin 2007-03-09 16:27:11 +00:00
parent f9feee175b
commit 6e21afd40c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167368
5 changed files with 134 additions and 3 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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,
};
/*
@ -80,6 +84,34 @@ struct lock_class lock_class_rw = {
#define _rw_assert(rw, what, file, line)
#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);

View File

@ -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,12 +63,42 @@ 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
#define _sx_assert(sx, what, file, line)
#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)
{
@ -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);

View File

@ -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. */