xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/mutex_pool.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_MUTEX_POOL_H
2*8e33eff8Schristos #define JEMALLOC_INTERNAL_MUTEX_POOL_H
3*8e33eff8Schristos 
4*8e33eff8Schristos #include "jemalloc/internal/hash.h"
5*8e33eff8Schristos #include "jemalloc/internal/mutex.h"
6*8e33eff8Schristos #include "jemalloc/internal/witness.h"
7*8e33eff8Schristos 
8*8e33eff8Schristos /* We do mod reductions by this value, so it should be kept a power of 2. */
9*8e33eff8Schristos #define MUTEX_POOL_SIZE 256
10*8e33eff8Schristos 
11*8e33eff8Schristos typedef struct mutex_pool_s mutex_pool_t;
12*8e33eff8Schristos struct mutex_pool_s {
13*8e33eff8Schristos 	malloc_mutex_t mutexes[MUTEX_POOL_SIZE];
14*8e33eff8Schristos };
15*8e33eff8Schristos 
16*8e33eff8Schristos bool mutex_pool_init(mutex_pool_t *pool, const char *name, witness_rank_t rank);
17*8e33eff8Schristos 
18*8e33eff8Schristos /* Internal helper - not meant to be called outside this module. */
19*8e33eff8Schristos static inline malloc_mutex_t *
20*8e33eff8Schristos mutex_pool_mutex(mutex_pool_t *pool, uintptr_t key) {
21*8e33eff8Schristos 	size_t hash_result[2];
22*8e33eff8Schristos 	hash(&key, sizeof(key), 0xd50dcc1b, hash_result);
23*8e33eff8Schristos 	return &pool->mutexes[hash_result[0] % MUTEX_POOL_SIZE];
24*8e33eff8Schristos }
25*8e33eff8Schristos 
26*8e33eff8Schristos static inline void
27*8e33eff8Schristos mutex_pool_assert_not_held(tsdn_t *tsdn, mutex_pool_t *pool) {
28*8e33eff8Schristos 	for (int i = 0; i < MUTEX_POOL_SIZE; i++) {
29*8e33eff8Schristos 		malloc_mutex_assert_not_owner(tsdn, &pool->mutexes[i]);
30*8e33eff8Schristos 	}
31*8e33eff8Schristos }
32*8e33eff8Schristos 
33*8e33eff8Schristos /*
34*8e33eff8Schristos  * Note that a mutex pool doesn't work exactly the way an embdedded mutex would.
35*8e33eff8Schristos  * You're not allowed to acquire mutexes in the pool one at a time.  You have to
36*8e33eff8Schristos  * acquire all the mutexes you'll need in a single function call, and then
37*8e33eff8Schristos  * release them all in a single function call.
38*8e33eff8Schristos  */
39*8e33eff8Schristos 
40*8e33eff8Schristos static inline void
41*8e33eff8Schristos mutex_pool_lock(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) {
42*8e33eff8Schristos 	mutex_pool_assert_not_held(tsdn, pool);
43*8e33eff8Schristos 
44*8e33eff8Schristos 	malloc_mutex_t *mutex = mutex_pool_mutex(pool, key);
45*8e33eff8Schristos 	malloc_mutex_lock(tsdn, mutex);
46*8e33eff8Schristos }
47*8e33eff8Schristos 
48*8e33eff8Schristos static inline void
49*8e33eff8Schristos mutex_pool_unlock(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) {
50*8e33eff8Schristos 	malloc_mutex_t *mutex = mutex_pool_mutex(pool, key);
51*8e33eff8Schristos 	malloc_mutex_unlock(tsdn, mutex);
52*8e33eff8Schristos 
53*8e33eff8Schristos 	mutex_pool_assert_not_held(tsdn, pool);
54*8e33eff8Schristos }
55*8e33eff8Schristos 
56*8e33eff8Schristos static inline void
57*8e33eff8Schristos mutex_pool_lock2(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key1,
58*8e33eff8Schristos     uintptr_t key2) {
59*8e33eff8Schristos 	mutex_pool_assert_not_held(tsdn, pool);
60*8e33eff8Schristos 
61*8e33eff8Schristos 	malloc_mutex_t *mutex1 = mutex_pool_mutex(pool, key1);
62*8e33eff8Schristos 	malloc_mutex_t *mutex2 = mutex_pool_mutex(pool, key2);
63*8e33eff8Schristos 	if ((uintptr_t)mutex1 < (uintptr_t)mutex2) {
64*8e33eff8Schristos 		malloc_mutex_lock(tsdn, mutex1);
65*8e33eff8Schristos 		malloc_mutex_lock(tsdn, mutex2);
66*8e33eff8Schristos 	} else if ((uintptr_t)mutex1 == (uintptr_t)mutex2) {
67*8e33eff8Schristos 		malloc_mutex_lock(tsdn, mutex1);
68*8e33eff8Schristos 	} else {
69*8e33eff8Schristos 		malloc_mutex_lock(tsdn, mutex2);
70*8e33eff8Schristos 		malloc_mutex_lock(tsdn, mutex1);
71*8e33eff8Schristos 	}
72*8e33eff8Schristos }
73*8e33eff8Schristos 
74*8e33eff8Schristos static inline void
75*8e33eff8Schristos mutex_pool_unlock2(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key1,
76*8e33eff8Schristos     uintptr_t key2) {
77*8e33eff8Schristos 	malloc_mutex_t *mutex1 = mutex_pool_mutex(pool, key1);
78*8e33eff8Schristos 	malloc_mutex_t *mutex2 = mutex_pool_mutex(pool, key2);
79*8e33eff8Schristos 	if (mutex1 == mutex2) {
80*8e33eff8Schristos 		malloc_mutex_unlock(tsdn, mutex1);
81*8e33eff8Schristos 	} else {
82*8e33eff8Schristos 		malloc_mutex_unlock(tsdn, mutex1);
83*8e33eff8Schristos 		malloc_mutex_unlock(tsdn, mutex2);
84*8e33eff8Schristos 	}
85*8e33eff8Schristos 
86*8e33eff8Schristos 	mutex_pool_assert_not_held(tsdn, pool);
87*8e33eff8Schristos }
88*8e33eff8Schristos 
89*8e33eff8Schristos static inline void
90*8e33eff8Schristos mutex_pool_assert_owner(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) {
91*8e33eff8Schristos 	malloc_mutex_assert_owner(tsdn, mutex_pool_mutex(pool, key));
92*8e33eff8Schristos }
93*8e33eff8Schristos 
94*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_MUTEX_POOL_H */
95