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