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