xref: /aosp_15_r20/external/jemalloc_new/src/mutex.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
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