aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2007-03-09 16:27:11 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2007-03-09 16:27:11 +0000
commit6e21afd40ca27a1aaef83296fa1e46fbc5e48017 (patch)
tree71366da8c5df1e7210aad9d816166233c0107eff /sys
parentf9feee175baa10825785cf7f2e596170612ae15d (diff)
downloadsrc-6e21afd40ca27a1aaef83296fa1e46fbc5e48017.tar.gz
src-6e21afd40ca27a1aaef83296fa1e46fbc5e48017.zip
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.
Notes
Notes: svn path=/head/; revision=167368
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_lock.c22
-rw-r--r--sys/kern/kern_mutex.c40
-rw-r--r--sys/kern/kern_rwlock.c33
-rw-r--r--sys/kern/kern_sx.c33
-rw-r--r--sys/sys/lock.h9
5 files changed, 134 insertions, 3 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index 85338364399e..02254a48d27e 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 0fd5d7e88bc3..b327ef84ed18 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 59d6d8302a73..b043e3e724c5 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 d41f94ebdcf2..5499171cd3ff 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 a30a595f03c6..3a3b4d28a3b8 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. */