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:
parent
f9feee175b
commit
6e21afd40c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167368
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user