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