xref: /freebsd/sys/kern/kern_mtxpool.c (revision f28600390922dfcf1ccbe51a2c560b5f6cefa961)
1f2860039SMatthew Dillon /*-
2f2860039SMatthew Dillon  * Copyright (c) 2001 Matthew Dillon.  All Rights Reserved.  Copyright
3f2860039SMatthew Dillon  * terms are as specified in the COPYRIGHT file at the base of the source
4f2860039SMatthew Dillon  * tree.
5f2860039SMatthew Dillon  *
6f2860039SMatthew Dillon  * Mutex pool routines.  These routines are designed to be used as short
7f2860039SMatthew Dillon  * term leaf mutexes (e.g. the last mutex you might aquire other then
8f2860039SMatthew Dillon  * calling msleep()).  They operate using a shared pool.  A mutex is chosen
9f2860039SMatthew Dillon  * from the pool based on the supplied pointer (which may or may not be
10f2860039SMatthew Dillon  * valid).
11f2860039SMatthew Dillon  *
12f2860039SMatthew Dillon  * Advantages:
13f2860039SMatthew Dillon  *	- no structural overhead.  Mutexes can be associated with structures
14f2860039SMatthew Dillon  *	  without adding bloat to the structures.
15f2860039SMatthew Dillon  *	- mutexes can be obtained for invalid pointers, useful when uses
16f2860039SMatthew Dillon  *	  mutexes to interlock destructor ops.
17f2860039SMatthew Dillon  *	- no initialization/destructor overhead
18f2860039SMatthew Dillon  *	- can be used with msleep.
19f2860039SMatthew Dillon  *
20f2860039SMatthew Dillon  * Disadvantages:
21f2860039SMatthew Dillon  *	- should generally only be used as leaf mutexes
22f2860039SMatthew Dillon  *	- pool/pool dependancy ordering cannot be depended on.
23f2860039SMatthew Dillon  *	- possible L1 cache mastersip contention between cpus
24f2860039SMatthew Dillon  *
25f2860039SMatthew Dillon  * $FreeBSD$
26f2860039SMatthew Dillon  */
27f2860039SMatthew Dillon 
28f2860039SMatthew Dillon #include <sys/param.h>
29f2860039SMatthew Dillon #include <sys/proc.h>
30f2860039SMatthew Dillon #include <sys/kernel.h>
31f2860039SMatthew Dillon #include <sys/ktr.h>
32f2860039SMatthew Dillon #include <sys/lock.h>
33f2860039SMatthew Dillon #include <sys/malloc.h>
34f2860039SMatthew Dillon #include <sys/mutex.h>
35f2860039SMatthew Dillon #include <sys/systm.h>
36f2860039SMatthew Dillon 
37f2860039SMatthew Dillon #ifndef MTX_POOL_SIZE
38f2860039SMatthew Dillon #define MTX_POOL_SIZE	128
39f2860039SMatthew Dillon #endif
40f2860039SMatthew Dillon #define MTX_POOL_MASK	(MTX_POOL_SIZE-1)
41f2860039SMatthew Dillon 
42f2860039SMatthew Dillon static struct mtx mtx_pool_ary[MTX_POOL_SIZE];
43f2860039SMatthew Dillon 
44f2860039SMatthew Dillon int mtx_pool_valid = 0;
45f2860039SMatthew Dillon 
46f2860039SMatthew Dillon /*
47f2860039SMatthew Dillon  * Inline version of mtx_pool_find(), used to streamline our main API
48f2860039SMatthew Dillon  * function calls.
49f2860039SMatthew Dillon  */
50f2860039SMatthew Dillon static __inline
51f2860039SMatthew Dillon struct mtx *
52f2860039SMatthew Dillon _mtx_pool_find(void *ptr)
53f2860039SMatthew Dillon {
54f2860039SMatthew Dillon     return(&mtx_pool_ary[((int)ptr ^ ((int)ptr >> 6)) & MTX_POOL_MASK]);
55f2860039SMatthew Dillon }
56f2860039SMatthew Dillon 
57f2860039SMatthew Dillon static void
58f2860039SMatthew Dillon mtx_pool_setup(void *dummy __unused)
59f2860039SMatthew Dillon {
60f2860039SMatthew Dillon     int i;
61f2860039SMatthew Dillon 
62f2860039SMatthew Dillon     for (i = 0; i < MTX_POOL_SIZE; ++i)
63f2860039SMatthew Dillon 	mtx_init(&mtx_pool_ary[i], "pool mutex", MTX_DEF);
64f2860039SMatthew Dillon     mtx_pool_valid = 1;
65f2860039SMatthew Dillon }
66f2860039SMatthew Dillon 
67f2860039SMatthew Dillon /*
68f2860039SMatthew Dillon  * Obtain a (shared) mutex from the pool.  The returned mutex is a leaf
69f2860039SMatthew Dillon  * level mutex, meaning that if you obtain it you cannot obtain any other
70f2860039SMatthew Dillon  * mutexes until you release it.  You can legally msleep() on the mutex.
71f2860039SMatthew Dillon  */
72f2860039SMatthew Dillon struct mtx *
73f2860039SMatthew Dillon mtx_pool_alloc(void)
74f2860039SMatthew Dillon {
75f2860039SMatthew Dillon     static int si;
76f2860039SMatthew Dillon     return(&mtx_pool_ary[si++ & MTX_POOL_MASK]);
77f2860039SMatthew Dillon }
78f2860039SMatthew Dillon 
79f2860039SMatthew Dillon /*
80f2860039SMatthew Dillon  * Return the (shared) pool mutex associated with the specified address.
81f2860039SMatthew Dillon  * The returned mutex is a leaf level mutex, meaning that if you obtain it
82f2860039SMatthew Dillon  * you cannot obtain any other mutexes until you release it.  You can
83f2860039SMatthew Dillon  * legally msleep() on the mutex.
84f2860039SMatthew Dillon  */
85f2860039SMatthew Dillon struct mtx *
86f2860039SMatthew Dillon mtx_pool_find(void *ptr)
87f2860039SMatthew Dillon {
88f2860039SMatthew Dillon     return(_mtx_pool_find(ptr));
89f2860039SMatthew Dillon }
90f2860039SMatthew Dillon 
91f2860039SMatthew Dillon /*
92f2860039SMatthew Dillon  * Combined find/lock operation.  Lock the pool mutex associated with
93f2860039SMatthew Dillon  * the specified address.
94f2860039SMatthew Dillon  */
95f2860039SMatthew Dillon void
96f2860039SMatthew Dillon mtx_pool_lock(void *ptr)
97f2860039SMatthew Dillon {
98f2860039SMatthew Dillon     mtx_lock(_mtx_pool_find(ptr));
99f2860039SMatthew Dillon }
100f2860039SMatthew Dillon 
101f2860039SMatthew Dillon /*
102f2860039SMatthew Dillon  * Combined find/unlock operation.  Unlock the pool mutex associated with
103f2860039SMatthew Dillon  * the specified address.
104f2860039SMatthew Dillon  */
105f2860039SMatthew Dillon void
106f2860039SMatthew Dillon mtx_pool_unlock(void *ptr)
107f2860039SMatthew Dillon {
108f2860039SMatthew Dillon     mtx_unlock(_mtx_pool_find(ptr));
109f2860039SMatthew Dillon }
110f2860039SMatthew Dillon 
111f2860039SMatthew Dillon SYSINIT(mtxpooli, SI_SUB_MUTEX, SI_ORDER_FIRST, mtx_pool_setup, NULL)
112f2860039SMatthew Dillon 
113