On Wed, 28 Jul 2010, Andrew Doran wrote:
it seems to me the root problem is that module_mutex is held while
calling into the module startup routines.
thus, the right solution is to remove this requirement.
Yes, that's what is needed.
I'm far from convinced that's a good idea. First, it will probably
make the module code a nightmare -- what happens when you have multiple
interleaved loads, some of which fail at some point in their dependency
stack, and let's just throw in a manual modunload to mix up things
further. Second, and pretty much related to number one, it goes against
one of the most fundamental principles of robust code: atomic actions.
This: atomicity. The atomic behaviour is relied upon to give "all or
nothing" semantics upon load and unload, like transactions in a database.
Admittely some modules (not of my making) are sloppy about this and so
break that bit of the interface contract.
If modload-from-modcmd is found necessary, sounds more like a case for
the infamous recursive lock.
Recursive lock is the way to go. I think the same lock should also cover
all device configuration activites (i.e. autoconf) and any other
heavy lifting where we have chunks of the system coming and going.
Well, folks, here is a first pass recursive locks! The attached diffs
are against -current as of a few minutes ago.
Some caveats:
1. This has only been compile-tested for x86 (amd64 & i386).
2. Other architectures have not even been compiled yet. "It should
work" but you never know.
3. HPPA is an exceptional exception here, since it is the only in-tree
architecture I found that cannot use SIMPLE_LOCKS.
4. There is only one known use case for this so far: modules loading
other modules from within their xxx_modcmd() routine. The specific
use case we have involves loading the acpicpu driver/module which
eventually results in an attempt to load acpiverbose.
It would be really nice if the community could
A. Compile-test on additional architectures, especially HPPA
B. Test to see that existing mutex operations still work correctly
C. Exercise the known use case if possible
D. Identify additional use cases
There is one place in the code (marked with great big XXX) where I am
simply unsure if I need to use a CAS-type operation for updating the
reference count on the recursive mutex. I _think_ it is save to simply
auto-increment the field, but I am totally willing for any of you
experts to tell my why this might not be safe. :)
I will be updating one of my home machines (amd64) to use this code in
the next few days. I don't plan on making any commits until I've had
some positive testing feedback, and hopefully some expert commentary on
the XXX. (Some additional "concensus" that this is the "right thing to
do" would also be appreciated!)
-------------------------------------------------------------------------
| Paul Goyette | PGP Key fingerprint: | E-mail addresses: |
| Customer Service | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com |
| Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net |
| Kernel Developer | | pgoyette at netbsd.org |
-------------------------------------------------------------------------
Index: sys/arch/alpha/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/alpha/include/mutex.h,v
retrieving revision 1.4
diff -u -p -r1.4 mutex.h
--- sys/arch/alpha/include/mutex.h 28 Apr 2008 20:23:11 -0000 1.4
+++ sys/arch/alpha/include/mutex.h 31 Jul 2010 22:34:30 -0000
@@ -43,7 +43,11 @@ struct kmutex {
struct kmutex {
union {
- volatile uintptr_t mtxa_owner;
+ struct {
+ volatile uintptr_t mtxa_owner;
+ volatile uint8_t mtxa_recurse;
+ volatile uint8_t mtxa_unused[3];
+ } a;
struct {
volatile uint8_t mtxs_flags;
ipl_cookie_t mtxs_ipl;
@@ -53,7 +57,8 @@ struct kmutex {
__cpu_simple_lock_t mtx_lock;
};
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_flags u.s.mtxs_flags
#define mtx_ipl u.s.mtxs_ipl
Index: sys/arch/arm/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/include/mutex.h,v
retrieving revision 1.10
diff -u -p -r1.10 mutex.h
--- sys/arch/arm/include/mutex.h 28 Apr 2008 20:23:14 -0000 1.10
+++ sys/arch/arm/include/mutex.h 31 Jul 2010 22:34:31 -0000
@@ -57,7 +57,11 @@ struct kmutex {
struct kmutex {
union {
/* Adaptive mutex */
- volatile uintptr_t mtxa_owner; /* 0-3 */
+ struct {
+ volatile uintptr_t mtxa_owner; /* 0-3 */
+ volatile uint8_t mtxa_recurse;
+ volatile uint8_t mtxa_unused[3];
+ } a;
/* Spin mutex */
struct {
@@ -69,7 +73,8 @@ struct kmutex {
} u;
};
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/hppa/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/include/mutex.h,v
retrieving revision 1.9
diff -u -p -r1.9 mutex.h
--- sys/arch/hppa/include/mutex.h 28 Apr 2008 20:23:23 -0000 1.9
+++ sys/arch/hppa/include/mutex.h 31 Jul 2010 22:34:32 -0000
@@ -60,6 +60,10 @@ struct kmutex {
/* For LOCKDEBUG */
uint8_t mtxs_dodebug; /* 25 */
+
+ /* For recursive locks */
+ uint8_t mtxs_recurse; /* 26 */
+ uint8_t mtxs_recursive; /* 27 */
} s;
#endif
uint8_t mtxu_pad[32]; /* 0 - 32 */
@@ -73,6 +77,7 @@ struct kmutex {
#define mtx_lock u.s.mtxu_lock
#define mtx_owner u.s.mtxs_owner
+#define mtx_recurse u.s.mtxs_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_waiters u.s.mtxs_waiters
#define mtx_dodebug u.s.mtxs_dodebug
@@ -129,6 +134,12 @@ MUTEX_INITIALIZE_ADAPTIVE(kmutex_t *mtx,
}
static inline void
+MUTEX_INITIALIZE_RECURSIVE(kmutex_t *mtx)
+{
+ mtx->mtx_recursive = 1;
+}
+
+static inline void
MUTEX_DESTROY(kmutex_t *mtx)
{
mtx->mtx_owner = 0xffffffff;
@@ -147,6 +158,12 @@ MUTEX_SPIN_P(volatile kmutex_t *mtx)
}
static inline int
+MUTEX_RECURSIVE_P(volatile kmutex_t *mtx)
+{
+ return mtx->mtx_recursive != 0;
+}
+
+static inline int
MUTEX_ADAPTIVE_P(volatile kmutex_t *mtx)
{
return mtx->mtx_owner != MUTEX_SPIN_FLAG;
Index: sys/arch/ia64/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/ia64/include/mutex.h,v
retrieving revision 1.4
diff -u -p -r1.4 mutex.h
--- sys/arch/ia64/include/mutex.h 20 Jul 2009 04:41:37 -0000 1.4
+++ sys/arch/ia64/include/mutex.h 31 Jul 2010 22:34:32 -0000
@@ -36,7 +36,7 @@
struct kmutex {
uintptr_t mtx_pad1;
- uint32_t mtx_pad2[2];
+ uint32_t mtx_pad2[3];
};
#else
@@ -45,6 +45,8 @@ struct kmutex {
volatile uintptr_t mtx_owner;
ipl_cookie_t mtx_ipl;
__cpu_simple_lock_t mtx_lock;
+ volatile uint8_t mtx_recurse;
+ volatile unit8_t mtx_unused[3];
};
Index: sys/arch/m68k/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/m68k/include/mutex.h,v
retrieving revision 1.7
diff -u -p -r1.7 mutex.h
--- sys/arch/m68k/include/mutex.h 28 Apr 2008 20:23:26 -0000 1.7
+++ sys/arch/m68k/include/mutex.h 31 Jul 2010 22:34:33 -0000
@@ -45,17 +45,23 @@ struct kmutex {
struct kmutex {
union {
/* Adaptive mutex */
- volatile uintptr_t mtxu_owner; /* 0-3 */
+ struct {
+ volatile uintptr_t mtxa_owner; /* 0-3 */
+ volatile uint8_t mtxa_recurse; /* 4 */
+ volatile unit8_t mtxa_unused[3]; /* 5-7 */
+ } a;
+ /* Spin */
struct {
ipl_cookie_t mtxs_ipl; /* 0-1 */
- __cpu_simple_lock_t mtxs_lock; /* 2 */
- uint8_t mtxs_unused; /* 3 */
+ __cpu_simple_lock_t mtxs_lock; /* 2 */
+ uint8_t mtxs_unused[5]; /* 3-7 */
} s;
} u;
};
-#define mtx_owner u.mtxu_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/mips/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/include/mutex.h,v
retrieving revision 1.6
diff -u -p -r1.6 mutex.h
--- sys/arch/mips/include/mutex.h 28 Apr 2008 20:23:28 -0000 1.6
+++ sys/arch/mips/include/mutex.h 31 Jul 2010 22:34:34 -0000
@@ -49,6 +49,7 @@ struct kmutex {
volatile uintptr_t mtx_owner;
ipl_cookie_t mtx_ipl;
__cpu_simple_lock_t mtx_lock;
+ volatile uint8_t mtx_recurse;
};
#define __HAVE_SIMPLE_MUTEXES 1
Index: sys/arch/powerpc/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/powerpc/include/mutex.h,v
retrieving revision 1.4
diff -u -p -r1.4 mutex.h
--- sys/arch/powerpc/include/mutex.h 28 Apr 2008 20:23:32 -0000 1.4
+++ sys/arch/powerpc/include/mutex.h 31 Jul 2010 22:34:34 -0000
@@ -43,11 +43,13 @@ struct kmutex {
volatile uintptr_t mtxm_owner;
ipl_cookie_t mtxm_ipl;
__cpu_simple_lock_t mtxm_lock;
+ volatile uint8_t mtxm_recurse;
+ volatile uint8_t mtxm_unused[3];
} m;
#endif
struct {
uintptr_t mtxp_a;
- uint32_t mtxp_b[2];
+ uint32_t mtxp_b[3];
} p;
} u;
};
@@ -55,6 +57,7 @@ struct kmutex {
#ifdef __MUTEX_PRIVATE
#define mtx_owner u.m.mtxm_owner
+#define mtx_recurse u.m.mtxm_recurse
#define mtx_ipl u.m.mtxm_ipl
#define mtx_lock u.m.mtxm_lock
Index: sys/arch/sh3/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/include/mutex.h,v
retrieving revision 1.9
diff -u -p -r1.9 mutex.h
--- sys/arch/sh3/include/mutex.h 28 Apr 2008 20:23:35 -0000 1.9
+++ sys/arch/sh3/include/mutex.h 31 Jul 2010 22:34:35 -0000
@@ -43,19 +43,24 @@ struct kmutex {
struct kmutex {
union {
/* Adaptive mutex */
- volatile uintptr_t mtxa_owner; /* 0-3 */
+ struct {
+ volatile uintptr_t mtxa_owner; /* 0-3 */
+ volatile uint8_t mtxa_recurse; /* 4 */
+ volatile uint8_t mtxa_unused[3]; /* 5-7 */
+ } a;
/* Spin mutex */
struct {
volatile uint8_t mtxs_dummy;
ipl_cookie_t mtxs_ipl;
__cpu_simple_lock_t mtxs_lock;
- volatile uint8_t mtxs_unused;
+ volatile uint8_t mtxs_unused[5];
} s;
} u;
};
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/sparc/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/include/mutex.h,v
retrieving revision 1.10
diff -u -p -r1.10 mutex.h
--- sys/arch/sparc/include/mutex.h 28 Apr 2008 20:23:36 -0000 1.10
+++ sys/arch/sparc/include/mutex.h 31 Jul 2010 22:34:36 -0000
@@ -38,13 +38,18 @@
struct kmutex {
union {
- volatile uintptr_t mtxa_owner;
+ struct {
+ volatile uintptr_t mtxa_owner;
+ volatile uint8_t mtxa_recurse;
+ volatile uint8_t mtxa_unused[3];
+ } a;
+
#ifdef __MUTEX_PRIVATE
struct {
volatile uint8_t mtxs_dummy;
ipl_cookie_t mtxs_ipl;
__cpu_simple_lock_t mtxs_lock;
- volatile uint8_t mtxs_unused;
+ volatile uint8_t mtxs_unused[5];
} s;
#endif
} u;
@@ -52,7 +57,8 @@ struct kmutex {
#ifdef __MUTEX_PRIVATE
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/sparc64/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/include/mutex.h,v
retrieving revision 1.4
diff -u -p -r1.4 mutex.h
--- sys/arch/sparc64/include/mutex.h 28 Apr 2008 20:23:37 -0000 1.4
+++ sys/arch/sparc64/include/mutex.h 31 Jul 2010 22:34:36 -0000
@@ -34,13 +34,18 @@
struct kmutex {
union {
- volatile uintptr_t mtxa_owner;
+ struct {
+ volatile uintptr_t mtxa_owner;
+ volatile uint8_t mtxa_recurse;
+ volatile uint8_t mtxa_unused[3];
+ } a;
+
#ifdef __MUTEX_PRIVATE
struct {
uint8_t mtxs_unused;
__cpu_simple_lock_t mtxs_lock;
ipl_cookie_t mtxs_ipl;
- uint8_t mtxs_dummy;
+ uint8_t mtxs_dummy[5];
} s;
#endif
} u;
@@ -48,7 +53,8 @@ struct kmutex {
#ifdef __MUTEX_PRIVATE
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/usermode/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/usermode/include/mutex.h,v
retrieving revision 1.3
diff -u -p -r1.3 mutex.h
--- sys/arch/usermode/include/mutex.h 28 Apr 2008 20:23:39 -0000 1.3
+++ sys/arch/usermode/include/mutex.h 31 Jul 2010 22:34:37 -0000
@@ -34,13 +34,18 @@
struct kmutex {
union {
- volatile uintptr_t mtxa_owner;
+ struct {
+ volatile uintptr_t mtxa_owner;
+ volatile uint8_t mtxa_recurse;
+ volatile uint8_t mtxa_unused[3];
+ } a;
+
#ifdef __MUTEX_PRIVATE
struct {
volatile uint8_t mtxs_dummy;
ipl_cookie_t mtxs_ipl;
__cpu_simple_lock_t mtxs_lock;
- volatile uint8_t mtxs_unused;
+ volatile uint8_t mtxs_unused[5];
} s;
#endif
} u;
@@ -48,7 +53,8 @@ struct kmutex {
#ifdef __MUTEX_PRIVATE
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/vax/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/vax/include/mutex.h,v
retrieving revision 1.12
diff -u -p -r1.12 mutex.h
--- sys/arch/vax/include/mutex.h 28 Apr 2008 20:23:39 -0000 1.12
+++ sys/arch/vax/include/mutex.h 31 Jul 2010 22:34:38 -0000
@@ -44,6 +44,7 @@
struct kmutex {
uintptr_t mtx_pad1;
+ uint8_t mtx_pad2[4];
};
#else /* __MUTEX_PRIVATE */
@@ -51,19 +52,24 @@ struct kmutex {
struct kmutex {
union {
/* Adaptive mutex */
- volatile uintptr_t mtxa_owner; /* 0-3 */
+ struct {
+ volatile uintptr_t mtxa_owner; /* 0-3 */
+ volatile uint8_t mtxa_recurse; /* 4 */
+ volatile uint8_t mtxa_unused[3]; /* 5-7 */
+ } a;
/* Spin mutex */
struct {
volatile uint8_t mtxs_dummy;
ipl_cookie_t mtxs_ipl;
__cpu_simple_lock_t mtxs_lock;
- volatile uint8_t mtxs_unused;
+ volatile uint8_t mtxs_unused[5];
} s;
} u;
};
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/arch/x86/include/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/mutex.h,v
retrieving revision 1.6
diff -u -p -r1.6 mutex.h
--- sys/arch/x86/include/mutex.h 24 Apr 2009 17:49:51 -0000 1.6
+++ sys/arch/x86/include/mutex.h 31 Jul 2010 22:34:39 -0000
@@ -34,13 +34,17 @@
struct kmutex {
union {
- volatile uintptr_t mtxa_owner;
+ struct {
+ volatile uintptr_t mtxa_owner;
+ volatile uint8_t mtxa_recurse;
+ volatile uint8_t mtxa_unused[3];
+ } a;
#ifdef __MUTEX_PRIVATE
struct {
volatile uint8_t mtxs_dummy;
ipl_cookie_t mtxs_ipl;
__cpu_simple_lock_t mtxs_lock;
- volatile uint8_t mtxs_unused;
+ volatile uint8_t mtxs_unused[5];
} s;
#endif
} u;
@@ -48,7 +52,8 @@ struct kmutex {
#ifdef __MUTEX_PRIVATE
-#define mtx_owner u.mtxa_owner
+#define mtx_owner u.a.mtxa_owner
+#define mtx_recurse u.a.mtxa_recurse
#define mtx_ipl u.s.mtxs_ipl
#define mtx_lock u.s.mtxs_lock
Index: sys/sys/mutex.h
===================================================================
RCS file: /cvsroot/src/sys/sys/mutex.h,v
retrieving revision 1.20
diff -u -p -r1.20 mutex.h
--- sys/sys/mutex.h 8 Feb 2010 09:54:27 -0000 1.20
+++ sys/sys/mutex.h 31 Jul 2010 22:34:39 -0000
@@ -51,6 +51,7 @@
* be able to access the following members:
*
* uintptr_t mtx_owner
+ * uint8_t mtx_recurse
* ipl_cookie_t mtx_ipl
* __cpu_simple_lock_t mtx_lock
*
@@ -82,6 +83,9 @@
* MUTEX_INITIALIZE_ADAPTIVE(mtx, dodebug)
* Initialize an adaptive mutex.
*
+ * MUTEX_INITIALIZE_RECURSIVE(mtx)
+ * Finish initialization of a recursive mutex.
+ *
* MUTEX_DESTROY(mtx)
* Tear down a mutex.
*
@@ -91,6 +95,9 @@
* MUTEX_SPIN_P(mtx)
* Evaluates to true if the mutex is a spin mutex.
*
+ * MUTEX_RECURSIVE_P(mtx)
+ * Evaluates to true if the mutex is a recursive mutex.
+ *
* MUTEX_OWNER(owner)
* Returns the owner of the adaptive mutex (LWP address).
*
@@ -160,6 +167,7 @@ typedef struct kmutex kmutex_t;
#define MUTEX_BIT_SPIN 0x01
#define MUTEX_BIT_WAITERS 0x02
+#define MUTEX_BIT_RECURSIVE 0x08
#if defined(LOCKDEBUG)
#define MUTEX_BIT_NODEBUG 0x04 /* LOCKDEBUG disabled */
@@ -192,6 +200,7 @@ void mutex_wakeup(kmutex_t *);
#ifdef _KERNEL
+void mutex_init_recursive(kmutex_t *);
void mutex_init(kmutex_t *, kmutex_type_t, int);
void mutex_destroy(kmutex_t *);
Index: sys/kern/kern_mutex.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_mutex.c,v
retrieving revision 1.49
diff -u -p -r1.49 kern_mutex.c
--- sys/kern/kern_mutex.c 8 Feb 2010 09:54:27 -0000 1.49
+++ sys/kern/kern_mutex.c 31 Jul 2010 22:34:40 -0000
@@ -170,6 +170,11 @@ do {
\
__cpu_simple_lock_init(&(mtx)->mtx_lock); \
} while (/* CONSTCOND */ 0)
+#define MUTEX_INITIALIZE_RECURSIVE(mtx)
\
+do { \
+ (mtx)->mtx_owner |= MUTEX_BIT_RECURSIVE; \
+} while (/* CONSTCOND */ 0)
+
#define MUTEX_DESTROY(mtx)
\
do { \
(mtx)->mtx_owner = MUTEX_THREAD; \
@@ -179,6 +184,8 @@ do {
\
(((mtx)->mtx_owner & MUTEX_BIT_SPIN) != 0)
#define MUTEX_ADAPTIVE_P(mtx) \
(((mtx)->mtx_owner & MUTEX_BIT_SPIN) == 0)
+#define MUTEX_RECURSIVE_P(mtx) \
+ (((mtx)->mtx_owner & MUTEX_BIT_RECURSIVE) == 0)
#define MUTEX_DEBUG_P(mtx) (((mtx)->mtx_owner & MUTEX_BIT_NODEBUG)
== 0)
#if defined(LOCKDEBUG)
@@ -286,6 +293,8 @@ mutex_dump(volatile void *cookie)
printf_nolog("owner field : %#018lx wait/spin: %16d/%d\n",
(long)MUTEX_OWNER(mtx->mtx_owner), MUTEX_HAS_WAITERS(mtx),
MUTEX_SPIN_P(mtx));
+ if (MUTEX_RECURSIVE_P(mtx))
+ printf_nolog("recursion lvl : %16d\n", mtx->mtx_recurse);
}
/*
@@ -304,6 +313,21 @@ mutex_abort(kmutex_t *mtx, const char *f
}
/*
+ * mutex_init_recursive:
+ *
+ * Initialize a recursive mutex for use. These are just like
+ * adaptive mutexes, except that
+ * 1. They must be initialized at IPL_NONE
+ * 2. They may be acquired recursively
+ */
+void
+mutex_init_recursive(kmutex_t *mtx)
+{
+ mutex_init(mtx, MUTEX_DEFAULT, IPL_NONE);
+ MUTEX_INITIALIZE_RECURSIVE(mtx);
+}
+
+/*
* mutex_init:
*
* Initialize a mutex for use. Note that adaptive mutexes are in
@@ -532,8 +556,23 @@ mutex_vector_enter(kmutex_t *mtx)
if (__predict_false(panicstr != NULL))
return;
- if (__predict_false(MUTEX_OWNER(owner) == curthread))
+ if (__predict_false(MUTEX_OWNER(owner) == curthread)) {
+ /*
+ * Handle recursive mutexes
+ *
+ * XXX Does this need to be done atomically? The
+ * XXX curthread already owns the mutex and it cannot
+ * XXX possibly be running on another CPU, so there
+ * XXX really should not be any chance of conflicting
+ * XXX updates.
+ */
+ if (__predict_false(MUTEX_RECURSIVE_P(mtx))) {
+ mtx->mtx_recurse++;
+ MUTEX_ASSERT(mtx,mtx->mtx_recurse);
+ break;
+ }
MUTEX_ABORT(mtx, "locking against myself");
+ }
#ifdef MULTIPROCESSOR
/*
@@ -740,6 +779,17 @@ mutex_vector_exit(kmutex_t *mtx)
curthread = (uintptr_t)curlwp;
MUTEX_DASSERT(mtx, curthread != 0);
MUTEX_ASSERT(mtx, MUTEX_OWNER(mtx->mtx_owner) == curthread);
+
+ /*
+ * For recursive mutexes, decrement recursion count. If still
+ * non-zero, just exit since curthread still owns it.
+ */
+ if (__predict_false(MUTEX_RECURSIVE_P(mtx))) {
+ MUTEX_ASSERT(mtx, mtx->mtx_recurse);
+ if (--mtx->mtx_recurse)
+ return;
+ }
+
MUTEX_UNLOCKED(mtx);
#ifdef LOCKDEBUG
Index: sys/arch/amd64/amd64/genassym.cf
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/genassym.cf,v
retrieving revision 1.45
diff -u -p -r1.45 genassym.cf
--- sys/arch/amd64/amd64/genassym.cf 7 Jul 2010 01:14:52 -0000 1.45
+++ sys/arch/amd64/amd64/genassym.cf 31 Jul 2010 22:34:41 -0000
@@ -342,7 +342,8 @@ define PSL_MBO PSL_MBO
define MTX_IPL offsetof(struct kmutex, u.s.mtxs_ipl)
define MTX_LOCK offsetof(struct kmutex, u.s.mtxs_lock)
-define MTX_OWNER offsetof(struct kmutex, u.mtxa_owner)
+define MTX_OWNER offsetof(struct kmutex, u.a.mtxa_owner)
+define MTX_RECURSE offsetof(struct kmutex, u.a.mtxa_recurse)
define RW_OWNER offsetof(struct krwlock, rw_owner)
define RW_WRITE_LOCKED RW_WRITE_LOCKED
Index: sys/rump/librump/rumpkern/locks.c
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpkern/locks.c,v
retrieving revision 1.42
diff -u -p -r1.42 locks.c
--- sys/rump/librump/rumpkern/locks.c 9 Jun 2010 07:54:13 -0000 1.42
+++ sys/rump/librump/rumpkern/locks.c 31 Jul 2010 22:34:42 -0000
@@ -64,6 +64,15 @@ mutex_init(kmutex_t *mtx, kmutex_type_t
}
void
+mutex_init_recursive(kmutex_t *mtx)
+{
+
+ CTASSERT(sizeof(kmutex_t) >= sizeof(void *));
+
+ rumpuser_mutex_recursive_init((struct rumpuser_mtx **)mtx);
+}
+
+void
mutex_destroy(kmutex_t *mtx)
{
Index: sys/kern/kern_module.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_module.c,v
retrieving revision 1.70
diff -u -p -r1.70 kern_module.c
--- sys/kern/kern_module.c 26 Jun 2010 07:23:57 -0000 1.70
+++ sys/kern/kern_module.c 31 Jul 2010 22:34:42 -0000
@@ -332,7 +332,7 @@ module_init(void)
if (module_map == NULL) {
module_map = kernel_map;
}
- mutex_init(&module_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init_recursive(&module_lock);
cv_init(&module_thread_cv, "modunload");
mutex_init(&module_thread_lock, MUTEX_DEFAULT, IPL_NONE);