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 * 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 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 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 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 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 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 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