Home | History | Annotate | Download | only in internal
      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