xref: /aosp_15_r20/external/jemalloc_new/include/jemalloc/internal/mutex.h (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_INTERNAL_MUTEX_H
2*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_INTERNAL_MUTEX_H
3*1208bc7eSAndroid Build Coastguard Worker 
4*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/atomic.h"
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex_prof.h"
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/tsd.h"
7*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/witness.h"
8*1208bc7eSAndroid Build Coastguard Worker 
9*1208bc7eSAndroid Build Coastguard Worker typedef enum {
10*1208bc7eSAndroid Build Coastguard Worker 	/* Can only acquire one mutex of a given witness rank at a time. */
11*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_rank_exclusive,
12*1208bc7eSAndroid Build Coastguard Worker 	/*
13*1208bc7eSAndroid Build Coastguard Worker 	 * Can acquire multiple mutexes of the same witness rank, but in
14*1208bc7eSAndroid Build Coastguard Worker 	 * address-ascending order only.
15*1208bc7eSAndroid Build Coastguard Worker 	 */
16*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_address_ordered
17*1208bc7eSAndroid Build Coastguard Worker } malloc_mutex_lock_order_t;
18*1208bc7eSAndroid Build Coastguard Worker 
19*1208bc7eSAndroid Build Coastguard Worker typedef struct malloc_mutex_s malloc_mutex_t;
20*1208bc7eSAndroid Build Coastguard Worker struct malloc_mutex_s {
21*1208bc7eSAndroid Build Coastguard Worker 	union {
22*1208bc7eSAndroid Build Coastguard Worker 		struct {
23*1208bc7eSAndroid Build Coastguard Worker 			/*
24*1208bc7eSAndroid Build Coastguard Worker 			 * prof_data is defined first to reduce cacheline
25*1208bc7eSAndroid Build Coastguard Worker 			 * bouncing: the data is not touched by the mutex holder
26*1208bc7eSAndroid Build Coastguard Worker 			 * during unlocking, while might be modified by
27*1208bc7eSAndroid Build Coastguard Worker 			 * contenders.  Having it before the mutex itself could
28*1208bc7eSAndroid Build Coastguard Worker 			 * avoid prefetching a modified cacheline (for the
29*1208bc7eSAndroid Build Coastguard Worker 			 * unlocking thread).
30*1208bc7eSAndroid Build Coastguard Worker 			 */
31*1208bc7eSAndroid Build Coastguard Worker 			mutex_prof_data_t	prof_data;
32*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
33*1208bc7eSAndroid Build Coastguard Worker #  if _WIN32_WINNT >= 0x0600
34*1208bc7eSAndroid Build Coastguard Worker 			SRWLOCK         	lock;
35*1208bc7eSAndroid Build Coastguard Worker #  else
36*1208bc7eSAndroid Build Coastguard Worker 			CRITICAL_SECTION	lock;
37*1208bc7eSAndroid Build Coastguard Worker #  endif
38*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
39*1208bc7eSAndroid Build Coastguard Worker 			os_unfair_lock		lock;
40*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_OSSPIN))
41*1208bc7eSAndroid Build Coastguard Worker 			OSSpinLock		lock;
42*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_MUTEX_INIT_CB))
43*1208bc7eSAndroid Build Coastguard Worker 			pthread_mutex_t		lock;
44*1208bc7eSAndroid Build Coastguard Worker 			malloc_mutex_t		*postponed_next;
45*1208bc7eSAndroid Build Coastguard Worker #else
46*1208bc7eSAndroid Build Coastguard Worker 			pthread_mutex_t		lock;
47*1208bc7eSAndroid Build Coastguard Worker #endif
48*1208bc7eSAndroid Build Coastguard Worker 		};
49*1208bc7eSAndroid Build Coastguard Worker 		/*
50*1208bc7eSAndroid Build Coastguard Worker 		 * We only touch witness when configured w/ debug.  However we
51*1208bc7eSAndroid Build Coastguard Worker 		 * keep the field in a union when !debug so that we don't have
52*1208bc7eSAndroid Build Coastguard Worker 		 * to pollute the code base with #ifdefs, while avoid paying the
53*1208bc7eSAndroid Build Coastguard Worker 		 * memory cost.
54*1208bc7eSAndroid Build Coastguard Worker 		 */
55*1208bc7eSAndroid Build Coastguard Worker #if !defined(JEMALLOC_DEBUG)
56*1208bc7eSAndroid Build Coastguard Worker 		witness_t			witness;
57*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_lock_order_t	lock_order;
58*1208bc7eSAndroid Build Coastguard Worker #endif
59*1208bc7eSAndroid Build Coastguard Worker 	};
60*1208bc7eSAndroid Build Coastguard Worker 
61*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_DEBUG)
62*1208bc7eSAndroid Build Coastguard Worker 	witness_t			witness;
63*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock_order_t	lock_order;
64*1208bc7eSAndroid Build Coastguard Worker #endif
65*1208bc7eSAndroid Build Coastguard Worker };
66*1208bc7eSAndroid Build Coastguard Worker 
67*1208bc7eSAndroid Build Coastguard Worker /*
68*1208bc7eSAndroid Build Coastguard Worker  * Based on benchmark results, a fixed spin with this amount of retries works
69*1208bc7eSAndroid Build Coastguard Worker  * well for our critical sections.
70*1208bc7eSAndroid Build Coastguard Worker  */
71*1208bc7eSAndroid Build Coastguard Worker #define MALLOC_MUTEX_MAX_SPIN 250
72*1208bc7eSAndroid Build Coastguard Worker 
73*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
74*1208bc7eSAndroid Build Coastguard Worker #  if _WIN32_WINNT >= 0x0600
75*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_LOCK(m)    AcquireSRWLockExclusive(&(m)->lock)
76*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_UNLOCK(m)  ReleaseSRWLockExclusive(&(m)->lock)
77*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_TRYLOCK(m) (!TryAcquireSRWLockExclusive(&(m)->lock))
78*1208bc7eSAndroid Build Coastguard Worker #  else
79*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_LOCK(m)    EnterCriticalSection(&(m)->lock)
80*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_UNLOCK(m)  LeaveCriticalSection(&(m)->lock)
81*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_TRYLOCK(m) (!TryEnterCriticalSection(&(m)->lock))
82*1208bc7eSAndroid Build Coastguard Worker #  endif
83*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
84*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_LOCK(m)    os_unfair_lock_lock(&(m)->lock)
85*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_UNLOCK(m)  os_unfair_lock_unlock(&(m)->lock)
86*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock))
87*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_OSSPIN))
88*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_LOCK(m)    OSSpinLockLock(&(m)->lock)
89*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_UNLOCK(m)  OSSpinLockUnlock(&(m)->lock)
90*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_TRYLOCK(m) (!OSSpinLockTry(&(m)->lock))
91*1208bc7eSAndroid Build Coastguard Worker #else
92*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_LOCK(m)    pthread_mutex_lock(&(m)->lock)
93*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_UNLOCK(m)  pthread_mutex_unlock(&(m)->lock)
94*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0)
95*1208bc7eSAndroid Build Coastguard Worker #endif
96*1208bc7eSAndroid Build Coastguard Worker 
97*1208bc7eSAndroid Build Coastguard Worker #define LOCK_PROF_DATA_INITIALIZER					\
98*1208bc7eSAndroid Build Coastguard Worker     {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0,		\
99*1208bc7eSAndroid Build Coastguard Worker 	    ATOMIC_INIT(0), 0, NULL, 0}
100*1208bc7eSAndroid Build Coastguard Worker 
101*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
102*1208bc7eSAndroid Build Coastguard Worker #  define MALLOC_MUTEX_INITIALIZER
103*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
104*1208bc7eSAndroid Build Coastguard Worker #  define MALLOC_MUTEX_INITIALIZER					\
105*1208bc7eSAndroid Build Coastguard Worker      {{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT}},		\
106*1208bc7eSAndroid Build Coastguard Worker       WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
107*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_OSSPIN))
108*1208bc7eSAndroid Build Coastguard Worker #  define MALLOC_MUTEX_INITIALIZER					\
109*1208bc7eSAndroid Build Coastguard Worker      {{{LOCK_PROF_DATA_INITIALIZER, 0}},				\
110*1208bc7eSAndroid Build Coastguard Worker       WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
111*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_MUTEX_INIT_CB))
112*1208bc7eSAndroid Build Coastguard Worker #  define MALLOC_MUTEX_INITIALIZER					\
113*1208bc7eSAndroid Build Coastguard Worker      {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL}},	\
114*1208bc7eSAndroid Build Coastguard Worker       WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
115*1208bc7eSAndroid Build Coastguard Worker #else
116*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
117*1208bc7eSAndroid Build Coastguard Worker #    define MALLOC_MUTEX_INITIALIZER					\
118*1208bc7eSAndroid Build Coastguard Worker        {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}},	\
119*1208bc7eSAndroid Build Coastguard Worker         WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
120*1208bc7eSAndroid Build Coastguard Worker #endif
121*1208bc7eSAndroid Build Coastguard Worker 
122*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_LAZY_LOCK
123*1208bc7eSAndroid Build Coastguard Worker extern bool isthreaded;
124*1208bc7eSAndroid Build Coastguard Worker #else
125*1208bc7eSAndroid Build Coastguard Worker #  undef isthreaded /* Undo private_namespace.h definition. */
126*1208bc7eSAndroid Build Coastguard Worker #  define isthreaded true
127*1208bc7eSAndroid Build Coastguard Worker #endif
128*1208bc7eSAndroid Build Coastguard Worker 
129*1208bc7eSAndroid Build Coastguard Worker bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name,
130*1208bc7eSAndroid Build Coastguard Worker     witness_rank_t rank, malloc_mutex_lock_order_t lock_order);
131*1208bc7eSAndroid Build Coastguard Worker void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex);
132*1208bc7eSAndroid Build Coastguard Worker void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex);
133*1208bc7eSAndroid Build Coastguard Worker void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex);
134*1208bc7eSAndroid Build Coastguard Worker bool malloc_mutex_boot(void);
135*1208bc7eSAndroid Build Coastguard Worker void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex);
136*1208bc7eSAndroid Build Coastguard Worker 
137*1208bc7eSAndroid Build Coastguard Worker void malloc_mutex_lock_slow(malloc_mutex_t *mutex);
138*1208bc7eSAndroid Build Coastguard Worker 
139*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_lock_final(malloc_mutex_t * mutex)140*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock_final(malloc_mutex_t *mutex) {
141*1208bc7eSAndroid Build Coastguard Worker 	MALLOC_MUTEX_LOCK(mutex);
142*1208bc7eSAndroid Build Coastguard Worker }
143*1208bc7eSAndroid Build Coastguard Worker 
144*1208bc7eSAndroid Build Coastguard Worker static inline bool
malloc_mutex_trylock_final(malloc_mutex_t * mutex)145*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_trylock_final(malloc_mutex_t *mutex) {
146*1208bc7eSAndroid Build Coastguard Worker 	return MALLOC_MUTEX_TRYLOCK(mutex);
147*1208bc7eSAndroid Build Coastguard Worker }
148*1208bc7eSAndroid Build Coastguard Worker 
149*1208bc7eSAndroid Build Coastguard Worker static inline void
mutex_owner_stats_update(tsdn_t * tsdn,malloc_mutex_t * mutex)150*1208bc7eSAndroid Build Coastguard Worker mutex_owner_stats_update(tsdn_t *tsdn, malloc_mutex_t *mutex) {
151*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
152*1208bc7eSAndroid Build Coastguard Worker 		mutex_prof_data_t *data = &mutex->prof_data;
153*1208bc7eSAndroid Build Coastguard Worker 		data->n_lock_ops++;
154*1208bc7eSAndroid Build Coastguard Worker 		if (data->prev_owner != tsdn) {
155*1208bc7eSAndroid Build Coastguard Worker 			data->prev_owner = tsdn;
156*1208bc7eSAndroid Build Coastguard Worker 			data->n_owner_switches++;
157*1208bc7eSAndroid Build Coastguard Worker 		}
158*1208bc7eSAndroid Build Coastguard Worker 	}
159*1208bc7eSAndroid Build Coastguard Worker }
160*1208bc7eSAndroid Build Coastguard Worker 
161*1208bc7eSAndroid Build Coastguard Worker /* Trylock: return false if the lock is successfully acquired. */
162*1208bc7eSAndroid Build Coastguard Worker static inline bool
malloc_mutex_trylock(tsdn_t * tsdn,malloc_mutex_t * mutex)163*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
164*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
165*1208bc7eSAndroid Build Coastguard Worker 	if (isthreaded) {
166*1208bc7eSAndroid Build Coastguard Worker 		if (malloc_mutex_trylock_final(mutex)) {
167*1208bc7eSAndroid Build Coastguard Worker 			return true;
168*1208bc7eSAndroid Build Coastguard Worker 		}
169*1208bc7eSAndroid Build Coastguard Worker 		mutex_owner_stats_update(tsdn, mutex);
170*1208bc7eSAndroid Build Coastguard Worker 	}
171*1208bc7eSAndroid Build Coastguard Worker 	witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
172*1208bc7eSAndroid Build Coastguard Worker 
173*1208bc7eSAndroid Build Coastguard Worker 	return false;
174*1208bc7eSAndroid Build Coastguard Worker }
175*1208bc7eSAndroid Build Coastguard Worker 
176*1208bc7eSAndroid Build Coastguard Worker /* Aggregate lock prof data. */
177*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_prof_merge(mutex_prof_data_t * sum,mutex_prof_data_t * data)178*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) {
179*1208bc7eSAndroid Build Coastguard Worker 	nstime_add(&sum->tot_wait_time, &data->tot_wait_time);
180*1208bc7eSAndroid Build Coastguard Worker 	if (nstime_compare(&sum->max_wait_time, &data->max_wait_time) < 0) {
181*1208bc7eSAndroid Build Coastguard Worker 		nstime_copy(&sum->max_wait_time, &data->max_wait_time);
182*1208bc7eSAndroid Build Coastguard Worker 	}
183*1208bc7eSAndroid Build Coastguard Worker 
184*1208bc7eSAndroid Build Coastguard Worker 	sum->n_wait_times += data->n_wait_times;
185*1208bc7eSAndroid Build Coastguard Worker 	sum->n_spin_acquired += data->n_spin_acquired;
186*1208bc7eSAndroid Build Coastguard Worker 
187*1208bc7eSAndroid Build Coastguard Worker 	if (sum->max_n_thds < data->max_n_thds) {
188*1208bc7eSAndroid Build Coastguard Worker 		sum->max_n_thds = data->max_n_thds;
189*1208bc7eSAndroid Build Coastguard Worker 	}
190*1208bc7eSAndroid Build Coastguard Worker 	uint32_t cur_n_waiting_thds = atomic_load_u32(&sum->n_waiting_thds,
191*1208bc7eSAndroid Build Coastguard Worker 	    ATOMIC_RELAXED);
192*1208bc7eSAndroid Build Coastguard Worker 	uint32_t new_n_waiting_thds = cur_n_waiting_thds + atomic_load_u32(
193*1208bc7eSAndroid Build Coastguard Worker 	    &data->n_waiting_thds, ATOMIC_RELAXED);
194*1208bc7eSAndroid Build Coastguard Worker 	atomic_store_u32(&sum->n_waiting_thds, new_n_waiting_thds,
195*1208bc7eSAndroid Build Coastguard Worker 	    ATOMIC_RELAXED);
196*1208bc7eSAndroid Build Coastguard Worker 	sum->n_owner_switches += data->n_owner_switches;
197*1208bc7eSAndroid Build Coastguard Worker 	sum->n_lock_ops += data->n_lock_ops;
198*1208bc7eSAndroid Build Coastguard Worker }
199*1208bc7eSAndroid Build Coastguard Worker 
200*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_lock(tsdn_t * tsdn,malloc_mutex_t * mutex)201*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
202*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
203*1208bc7eSAndroid Build Coastguard Worker 	if (isthreaded) {
204*1208bc7eSAndroid Build Coastguard Worker 		if (malloc_mutex_trylock_final(mutex)) {
205*1208bc7eSAndroid Build Coastguard Worker 			malloc_mutex_lock_slow(mutex);
206*1208bc7eSAndroid Build Coastguard Worker 		}
207*1208bc7eSAndroid Build Coastguard Worker 		mutex_owner_stats_update(tsdn, mutex);
208*1208bc7eSAndroid Build Coastguard Worker 	}
209*1208bc7eSAndroid Build Coastguard Worker 	witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
210*1208bc7eSAndroid Build Coastguard Worker }
211*1208bc7eSAndroid Build Coastguard Worker 
212*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_unlock(tsdn_t * tsdn,malloc_mutex_t * mutex)213*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
214*1208bc7eSAndroid Build Coastguard Worker 	witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
215*1208bc7eSAndroid Build Coastguard Worker 	if (isthreaded) {
216*1208bc7eSAndroid Build Coastguard Worker 		MALLOC_MUTEX_UNLOCK(mutex);
217*1208bc7eSAndroid Build Coastguard Worker 	}
218*1208bc7eSAndroid Build Coastguard Worker }
219*1208bc7eSAndroid Build Coastguard Worker 
220*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_assert_owner(tsdn_t * tsdn,malloc_mutex_t * mutex)221*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) {
222*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
223*1208bc7eSAndroid Build Coastguard Worker }
224*1208bc7eSAndroid Build Coastguard Worker 
225*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_assert_not_owner(tsdn_t * tsdn,malloc_mutex_t * mutex)226*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) {
227*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
228*1208bc7eSAndroid Build Coastguard Worker }
229*1208bc7eSAndroid Build Coastguard Worker 
230*1208bc7eSAndroid Build Coastguard Worker /* Copy the prof data from mutex for processing. */
231*1208bc7eSAndroid Build Coastguard Worker static inline void
malloc_mutex_prof_read(tsdn_t * tsdn,mutex_prof_data_t * data,malloc_mutex_t * mutex)232*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data,
233*1208bc7eSAndroid Build Coastguard Worker     malloc_mutex_t *mutex) {
234*1208bc7eSAndroid Build Coastguard Worker 	mutex_prof_data_t *source = &mutex->prof_data;
235*1208bc7eSAndroid Build Coastguard Worker 	/* Can only read holding the mutex. */
236*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_assert_owner(tsdn, mutex);
237*1208bc7eSAndroid Build Coastguard Worker 
238*1208bc7eSAndroid Build Coastguard Worker 	/*
239*1208bc7eSAndroid Build Coastguard Worker 	 * Not *really* allowed (we shouldn't be doing non-atomic loads of
240*1208bc7eSAndroid Build Coastguard Worker 	 * atomic data), but the mutex protection makes this safe, and writing
241*1208bc7eSAndroid Build Coastguard Worker 	 * a member-for-member copy is tedious for this situation.
242*1208bc7eSAndroid Build Coastguard Worker 	 */
243*1208bc7eSAndroid Build Coastguard Worker 	*data = *source;
244*1208bc7eSAndroid Build Coastguard Worker 	/* n_wait_thds is not reported (modified w/o locking). */
245*1208bc7eSAndroid Build Coastguard Worker 	atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED);
246*1208bc7eSAndroid Build Coastguard Worker }
247*1208bc7eSAndroid Build Coastguard Worker 
248*1208bc7eSAndroid Build Coastguard Worker #endif /* JEMALLOC_INTERNAL_MUTEX_H */
249