1*8e33eff8Schristos #define JEMALLOC_MUTEX_C_ 2*8e33eff8Schristos #include "jemalloc/internal/jemalloc_preamble.h" 3*8e33eff8Schristos #include "jemalloc/internal/jemalloc_internal_includes.h" 4*8e33eff8Schristos 5*8e33eff8Schristos #include "jemalloc/internal/assert.h" 6*8e33eff8Schristos #include "jemalloc/internal/malloc_io.h" 7*8e33eff8Schristos #include "jemalloc/internal/spin.h" 8*8e33eff8Schristos 9*8e33eff8Schristos #ifndef _CRT_SPINCOUNT 10*8e33eff8Schristos #define _CRT_SPINCOUNT 4000 11*8e33eff8Schristos #endif 12*8e33eff8Schristos 13*8e33eff8Schristos /******************************************************************************/ 14*8e33eff8Schristos /* Data. */ 15*8e33eff8Schristos 16*8e33eff8Schristos #ifdef JEMALLOC_LAZY_LOCK 17*8e33eff8Schristos bool isthreaded = false; 18*8e33eff8Schristos #endif 19*8e33eff8Schristos #ifdef JEMALLOC_MUTEX_INIT_CB 20*8e33eff8Schristos static bool postpone_init = true; 21*8e33eff8Schristos static malloc_mutex_t *postponed_mutexes = NULL; 22*8e33eff8Schristos #endif 23*8e33eff8Schristos 24*8e33eff8Schristos /******************************************************************************/ 25*8e33eff8Schristos /* 26*8e33eff8Schristos * We intercept pthread_create() calls in order to toggle isthreaded if the 27*8e33eff8Schristos * process goes multi-threaded. 28*8e33eff8Schristos */ 29*8e33eff8Schristos 30*8e33eff8Schristos #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) 31*8e33eff8Schristos JEMALLOC_EXPORT int 32*8e33eff8Schristos pthread_create(pthread_t *__restrict thread, 33*8e33eff8Schristos const pthread_attr_t *__restrict attr, void *(*start_routine)(void *), 34*8e33eff8Schristos void *__restrict arg) { 35*8e33eff8Schristos return pthread_create_wrapper(thread, attr, start_routine, arg); 36*8e33eff8Schristos } 37*8e33eff8Schristos #endif 38*8e33eff8Schristos 39*8e33eff8Schristos /******************************************************************************/ 40*8e33eff8Schristos 41*8e33eff8Schristos #ifdef JEMALLOC_MUTEX_INIT_CB 42*8e33eff8Schristos JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, 43*8e33eff8Schristos void *(calloc_cb)(size_t, size_t)); 44*8e33eff8Schristos #endif 45*8e33eff8Schristos 46*8e33eff8Schristos void 47*8e33eff8Schristos malloc_mutex_lock_slow(malloc_mutex_t *mutex) { 48*8e33eff8Schristos mutex_prof_data_t *data = &mutex->prof_data; 49*8e33eff8Schristos UNUSED nstime_t before = NSTIME_INITIALIZER; 50*8e33eff8Schristos 51*8e33eff8Schristos if (ncpus == 1) { 52*8e33eff8Schristos goto label_spin_done; 53*8e33eff8Schristos } 54*8e33eff8Schristos 55*8e33eff8Schristos int cnt = 0, max_cnt = MALLOC_MUTEX_MAX_SPIN; 56*8e33eff8Schristos do { 57*8e33eff8Schristos spin_cpu_spinwait(); 58*8e33eff8Schristos if (!malloc_mutex_trylock_final(mutex)) { 59*8e33eff8Schristos data->n_spin_acquired++; 60*8e33eff8Schristos return; 61*8e33eff8Schristos } 62*8e33eff8Schristos } while (cnt++ < max_cnt); 63*8e33eff8Schristos 64*8e33eff8Schristos if (!config_stats) { 65*8e33eff8Schristos /* Only spin is useful when stats is off. */ 66*8e33eff8Schristos malloc_mutex_lock_final(mutex); 67*8e33eff8Schristos return; 68*8e33eff8Schristos } 69*8e33eff8Schristos label_spin_done: 70*8e33eff8Schristos nstime_update(&before); 71*8e33eff8Schristos /* Copy before to after to avoid clock skews. */ 72*8e33eff8Schristos nstime_t after; 73*8e33eff8Schristos nstime_copy(&after, &before); 74*8e33eff8Schristos uint32_t n_thds = atomic_fetch_add_u32(&data->n_waiting_thds, 1, 75*8e33eff8Schristos ATOMIC_RELAXED) + 1; 76*8e33eff8Schristos /* One last try as above two calls may take quite some cycles. */ 77*8e33eff8Schristos if (!malloc_mutex_trylock_final(mutex)) { 78*8e33eff8Schristos atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED); 79*8e33eff8Schristos data->n_spin_acquired++; 80*8e33eff8Schristos return; 81*8e33eff8Schristos } 82*8e33eff8Schristos 83*8e33eff8Schristos /* True slow path. */ 84*8e33eff8Schristos malloc_mutex_lock_final(mutex); 85*8e33eff8Schristos /* Update more slow-path only counters. */ 86*8e33eff8Schristos atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED); 87*8e33eff8Schristos nstime_update(&after); 88*8e33eff8Schristos 89*8e33eff8Schristos nstime_t delta; 90*8e33eff8Schristos nstime_copy(&delta, &after); 91*8e33eff8Schristos nstime_subtract(&delta, &before); 92*8e33eff8Schristos 93*8e33eff8Schristos data->n_wait_times++; 94*8e33eff8Schristos nstime_add(&data->tot_wait_time, &delta); 95*8e33eff8Schristos if (nstime_compare(&data->max_wait_time, &delta) < 0) { 96*8e33eff8Schristos nstime_copy(&data->max_wait_time, &delta); 97*8e33eff8Schristos } 98*8e33eff8Schristos if (n_thds > data->max_n_thds) { 99*8e33eff8Schristos data->max_n_thds = n_thds; 100*8e33eff8Schristos } 101*8e33eff8Schristos } 102*8e33eff8Schristos 103*8e33eff8Schristos static void 104*8e33eff8Schristos mutex_prof_data_init(mutex_prof_data_t *data) { 105*8e33eff8Schristos memset(data, 0, sizeof(mutex_prof_data_t)); 106*8e33eff8Schristos nstime_init(&data->max_wait_time, 0); 107*8e33eff8Schristos nstime_init(&data->tot_wait_time, 0); 108*8e33eff8Schristos data->prev_owner = NULL; 109*8e33eff8Schristos } 110*8e33eff8Schristos 111*8e33eff8Schristos void 112*8e33eff8Schristos malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex) { 113*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, mutex); 114*8e33eff8Schristos mutex_prof_data_init(&mutex->prof_data); 115*8e33eff8Schristos } 116*8e33eff8Schristos 117*8e33eff8Schristos static int 118*8e33eff8Schristos mutex_addr_comp(const witness_t *witness1, void *mutex1, 119*8e33eff8Schristos const witness_t *witness2, void *mutex2) { 120*8e33eff8Schristos assert(mutex1 != NULL); 121*8e33eff8Schristos assert(mutex2 != NULL); 122*8e33eff8Schristos uintptr_t mu1int = (uintptr_t)mutex1; 123*8e33eff8Schristos uintptr_t mu2int = (uintptr_t)mutex2; 124*8e33eff8Schristos if (mu1int < mu2int) { 125*8e33eff8Schristos return -1; 126*8e33eff8Schristos } else if (mu1int == mu2int) { 127*8e33eff8Schristos return 0; 128*8e33eff8Schristos } else { 129*8e33eff8Schristos return 1; 130*8e33eff8Schristos } 131*8e33eff8Schristos } 132*8e33eff8Schristos 133*8e33eff8Schristos bool 134*8e33eff8Schristos malloc_mutex_init(malloc_mutex_t *mutex, const char *name, 135*8e33eff8Schristos witness_rank_t rank, malloc_mutex_lock_order_t lock_order) { 136*8e33eff8Schristos mutex_prof_data_init(&mutex->prof_data); 137*8e33eff8Schristos #ifdef _WIN32 138*8e33eff8Schristos # if _WIN32_WINNT >= 0x0600 139*8e33eff8Schristos InitializeSRWLock(&mutex->lock); 140*8e33eff8Schristos # else 141*8e33eff8Schristos if (!InitializeCriticalSectionAndSpinCount(&mutex->lock, 142*8e33eff8Schristos _CRT_SPINCOUNT)) { 143*8e33eff8Schristos return true; 144*8e33eff8Schristos } 145*8e33eff8Schristos # endif 146*8e33eff8Schristos #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) 147*8e33eff8Schristos mutex->lock = OS_UNFAIR_LOCK_INIT; 148*8e33eff8Schristos #elif (defined(JEMALLOC_OSSPIN)) 149*8e33eff8Schristos mutex->lock = 0; 150*8e33eff8Schristos #elif (defined(JEMALLOC_MUTEX_INIT_CB)) 151*8e33eff8Schristos if (postpone_init) { 152*8e33eff8Schristos mutex->postponed_next = postponed_mutexes; 153*8e33eff8Schristos postponed_mutexes = mutex; 154*8e33eff8Schristos } else { 155*8e33eff8Schristos if (_pthread_mutex_init_calloc_cb(&mutex->lock, 156*8e33eff8Schristos bootstrap_calloc) != 0) { 157*8e33eff8Schristos return true; 158*8e33eff8Schristos } 159*8e33eff8Schristos } 160*8e33eff8Schristos #elif MALLOC_MUTEX_TYPE == PTHREAD_MUTEX_DEFAULT 161*8e33eff8Schristos if (pthread_mutex_init(&mutex->lock, NULL) == -1) 162*8e33eff8Schristos return true; 163*8e33eff8Schristos #else 164*8e33eff8Schristos pthread_mutexattr_t attr; 165*8e33eff8Schristos 166*8e33eff8Schristos if (pthread_mutexattr_init(&attr) != 0) { 167*8e33eff8Schristos return true; 168*8e33eff8Schristos } 169*8e33eff8Schristos pthread_mutexattr_settype(&attr, MALLOC_MUTEX_TYPE); 170*8e33eff8Schristos if (pthread_mutex_init(&mutex->lock, &attr) != 0) { 171*8e33eff8Schristos pthread_mutexattr_destroy(&attr); 172*8e33eff8Schristos return true; 173*8e33eff8Schristos } 174*8e33eff8Schristos pthread_mutexattr_destroy(&attr); 175*8e33eff8Schristos #endif 176*8e33eff8Schristos if (config_debug) { 177*8e33eff8Schristos mutex->lock_order = lock_order; 178*8e33eff8Schristos if (lock_order == malloc_mutex_address_ordered) { 179*8e33eff8Schristos witness_init(&mutex->witness, name, rank, 180*8e33eff8Schristos mutex_addr_comp, mutex); 181*8e33eff8Schristos } else { 182*8e33eff8Schristos witness_init(&mutex->witness, name, rank, NULL, NULL); 183*8e33eff8Schristos } 184*8e33eff8Schristos } 185*8e33eff8Schristos return false; 186*8e33eff8Schristos } 187*8e33eff8Schristos 188*8e33eff8Schristos void 189*8e33eff8Schristos malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex) { 190*8e33eff8Schristos malloc_mutex_lock(tsdn, mutex); 191*8e33eff8Schristos } 192*8e33eff8Schristos 193*8e33eff8Schristos void 194*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex) { 195*8e33eff8Schristos malloc_mutex_unlock(tsdn, mutex); 196*8e33eff8Schristos } 197*8e33eff8Schristos 198*8e33eff8Schristos void 199*8e33eff8Schristos malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) { 200*8e33eff8Schristos #ifdef JEMALLOC_MUTEX_INIT_CB 201*8e33eff8Schristos malloc_mutex_unlock(tsdn, mutex); 202*8e33eff8Schristos #else 203*8e33eff8Schristos if (malloc_mutex_init(mutex, mutex->witness.name, 204*8e33eff8Schristos mutex->witness.rank, mutex->lock_order)) { 205*8e33eff8Schristos malloc_printf("<jemalloc>: Error re-initializing mutex in " 206*8e33eff8Schristos "child\n"); 207*8e33eff8Schristos if (opt_abort) { 208*8e33eff8Schristos abort(); 209*8e33eff8Schristos } 210*8e33eff8Schristos } 211*8e33eff8Schristos #endif 212*8e33eff8Schristos } 213*8e33eff8Schristos 214*8e33eff8Schristos bool 215*8e33eff8Schristos malloc_mutex_boot(void) { 216*8e33eff8Schristos #ifdef JEMALLOC_MUTEX_INIT_CB 217*8e33eff8Schristos postpone_init = false; 218*8e33eff8Schristos while (postponed_mutexes != NULL) { 219*8e33eff8Schristos if (_pthread_mutex_init_calloc_cb(&postponed_mutexes->lock, 220*8e33eff8Schristos bootstrap_calloc) != 0) { 221*8e33eff8Schristos return true; 222*8e33eff8Schristos } 223*8e33eff8Schristos postponed_mutexes = postponed_mutexes->postponed_next; 224*8e33eff8Schristos } 225*8e33eff8Schristos #endif 226*8e33eff8Schristos return false; 227*8e33eff8Schristos } 228