xref: /freebsd/contrib/jemalloc/src/ctl.c (revision 8b2f5aaf29ae826dffe22285cd20d4c8bc007533)
1a4bd5210SJason Evans #define JEMALLOC_CTL_C_
2b7eaed25SJason Evans #include "jemalloc/internal/jemalloc_preamble.h"
3b7eaed25SJason Evans #include "jemalloc/internal/jemalloc_internal_includes.h"
4b7eaed25SJason Evans 
5b7eaed25SJason Evans #include "jemalloc/internal/assert.h"
6b7eaed25SJason Evans #include "jemalloc/internal/ctl.h"
7b7eaed25SJason Evans #include "jemalloc/internal/extent_dss.h"
8b7eaed25SJason Evans #include "jemalloc/internal/extent_mmap.h"
9b7eaed25SJason Evans #include "jemalloc/internal/mutex.h"
10b7eaed25SJason Evans #include "jemalloc/internal/nstime.h"
11b7eaed25SJason Evans #include "jemalloc/internal/size_classes.h"
12b7eaed25SJason Evans #include "jemalloc/internal/util.h"
13a4bd5210SJason Evans 
14a4bd5210SJason Evans /******************************************************************************/
15a4bd5210SJason Evans /* Data. */
16a4bd5210SJason Evans 
17a4bd5210SJason Evans /*
18a4bd5210SJason Evans  * ctl_mtx protects the following:
19b7eaed25SJason Evans  * - ctl_stats->*
20a4bd5210SJason Evans  */
21a4bd5210SJason Evans static malloc_mutex_t	ctl_mtx;
22a4bd5210SJason Evans static bool		ctl_initialized;
23b7eaed25SJason Evans static ctl_stats_t	*ctl_stats;
24b7eaed25SJason Evans static ctl_arenas_t	*ctl_arenas;
25a4bd5210SJason Evans 
26a4bd5210SJason Evans /******************************************************************************/
27e722f8f8SJason Evans /* Helpers for named and indexed nodes. */
28e722f8f8SJason Evans 
29b7eaed25SJason Evans static const ctl_named_node_t *
30b7eaed25SJason Evans ctl_named_node(const ctl_node_t *node) {
31e722f8f8SJason Evans 	return ((node->named) ? (const ctl_named_node_t *)node : NULL);
32e722f8f8SJason Evans }
33e722f8f8SJason Evans 
34b7eaed25SJason Evans static const ctl_named_node_t *
35b7eaed25SJason Evans ctl_named_children(const ctl_named_node_t *node, size_t index) {
36e722f8f8SJason Evans 	const ctl_named_node_t *children = ctl_named_node(node->children);
37e722f8f8SJason Evans 
38e722f8f8SJason Evans 	return (children ? &children[index] : NULL);
39e722f8f8SJason Evans }
40e722f8f8SJason Evans 
41b7eaed25SJason Evans static const ctl_indexed_node_t *
42b7eaed25SJason Evans ctl_indexed_node(const ctl_node_t *node) {
43d0e79aa3SJason Evans 	return (!node->named ? (const ctl_indexed_node_t *)node : NULL);
44e722f8f8SJason Evans }
45e722f8f8SJason Evans 
46e722f8f8SJason Evans /******************************************************************************/
47a4bd5210SJason Evans /* Function prototypes for non-inline static functions. */
48a4bd5210SJason Evans 
49a4bd5210SJason Evans #define CTL_PROTO(n)							\
501f0a49e8SJason Evans static int	n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,	\
511f0a49e8SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen);
52a4bd5210SJason Evans 
53a4bd5210SJason Evans #define INDEX_PROTO(n)							\
541f0a49e8SJason Evans static const ctl_named_node_t	*n##_index(tsdn_t *tsdn,		\
551f0a49e8SJason Evans     const size_t *mib, size_t miblen, size_t i);
56a4bd5210SJason Evans 
57a4bd5210SJason Evans CTL_PROTO(version)
58a4bd5210SJason Evans CTL_PROTO(epoch)
59b7eaed25SJason Evans CTL_PROTO(background_thread)
60a4bd5210SJason Evans CTL_PROTO(thread_tcache_enabled)
61a4bd5210SJason Evans CTL_PROTO(thread_tcache_flush)
62d0e79aa3SJason Evans CTL_PROTO(thread_prof_name)
63d0e79aa3SJason Evans CTL_PROTO(thread_prof_active)
64a4bd5210SJason Evans CTL_PROTO(thread_arena)
65a4bd5210SJason Evans CTL_PROTO(thread_allocated)
66a4bd5210SJason Evans CTL_PROTO(thread_allocatedp)
67a4bd5210SJason Evans CTL_PROTO(thread_deallocated)
68a4bd5210SJason Evans CTL_PROTO(thread_deallocatedp)
69d0e79aa3SJason Evans CTL_PROTO(config_cache_oblivious)
70a4bd5210SJason Evans CTL_PROTO(config_debug)
71a4bd5210SJason Evans CTL_PROTO(config_fill)
72a4bd5210SJason Evans CTL_PROTO(config_lazy_lock)
73df0d881dSJason Evans CTL_PROTO(config_malloc_conf)
74a4bd5210SJason Evans CTL_PROTO(config_prof)
75a4bd5210SJason Evans CTL_PROTO(config_prof_libgcc)
76a4bd5210SJason Evans CTL_PROTO(config_prof_libunwind)
77a4bd5210SJason Evans CTL_PROTO(config_stats)
788244f2aaSJason Evans CTL_PROTO(config_thp)
79a4bd5210SJason Evans CTL_PROTO(config_utrace)
80a4bd5210SJason Evans CTL_PROTO(config_xmalloc)
81a4bd5210SJason Evans CTL_PROTO(opt_abort)
82b7eaed25SJason Evans CTL_PROTO(opt_abort_conf)
83b7eaed25SJason Evans CTL_PROTO(opt_retain)
8482872ac0SJason Evans CTL_PROTO(opt_dss)
85a4bd5210SJason Evans CTL_PROTO(opt_narenas)
86b7eaed25SJason Evans CTL_PROTO(opt_percpu_arena)
87b7eaed25SJason Evans CTL_PROTO(opt_background_thread)
88b7eaed25SJason Evans CTL_PROTO(opt_dirty_decay_ms)
89b7eaed25SJason Evans CTL_PROTO(opt_muzzy_decay_ms)
90a4bd5210SJason Evans CTL_PROTO(opt_stats_print)
91b7eaed25SJason Evans CTL_PROTO(opt_stats_print_opts)
92a4bd5210SJason Evans CTL_PROTO(opt_junk)
93a4bd5210SJason Evans CTL_PROTO(opt_zero)
94a4bd5210SJason Evans CTL_PROTO(opt_utrace)
95a4bd5210SJason Evans CTL_PROTO(opt_xmalloc)
96a4bd5210SJason Evans CTL_PROTO(opt_tcache)
97a4bd5210SJason Evans CTL_PROTO(opt_lg_tcache_max)
98a4bd5210SJason Evans CTL_PROTO(opt_prof)
99a4bd5210SJason Evans CTL_PROTO(opt_prof_prefix)
100a4bd5210SJason Evans CTL_PROTO(opt_prof_active)
101d0e79aa3SJason Evans CTL_PROTO(opt_prof_thread_active_init)
102a4bd5210SJason Evans CTL_PROTO(opt_lg_prof_sample)
103a4bd5210SJason Evans CTL_PROTO(opt_lg_prof_interval)
104a4bd5210SJason Evans CTL_PROTO(opt_prof_gdump)
1058ed34ab0SJason Evans CTL_PROTO(opt_prof_final)
106a4bd5210SJason Evans CTL_PROTO(opt_prof_leak)
107a4bd5210SJason Evans CTL_PROTO(opt_prof_accum)
108d0e79aa3SJason Evans CTL_PROTO(tcache_create)
109d0e79aa3SJason Evans CTL_PROTO(tcache_flush)
110d0e79aa3SJason Evans CTL_PROTO(tcache_destroy)
111b7eaed25SJason Evans CTL_PROTO(arena_i_initialized)
112df0d881dSJason Evans CTL_PROTO(arena_i_decay)
113b7eaed25SJason Evans CTL_PROTO(arena_i_purge)
1141f0a49e8SJason Evans CTL_PROTO(arena_i_reset)
115b7eaed25SJason Evans CTL_PROTO(arena_i_destroy)
11682872ac0SJason Evans CTL_PROTO(arena_i_dss)
117b7eaed25SJason Evans CTL_PROTO(arena_i_dirty_decay_ms)
118b7eaed25SJason Evans CTL_PROTO(arena_i_muzzy_decay_ms)
119b7eaed25SJason Evans CTL_PROTO(arena_i_extent_hooks)
12082872ac0SJason Evans INDEX_PROTO(arena_i)
121a4bd5210SJason Evans CTL_PROTO(arenas_bin_i_size)
122a4bd5210SJason Evans CTL_PROTO(arenas_bin_i_nregs)
123b7eaed25SJason Evans CTL_PROTO(arenas_bin_i_slab_size)
124a4bd5210SJason Evans INDEX_PROTO(arenas_bin_i)
125b7eaed25SJason Evans CTL_PROTO(arenas_lextent_i_size)
126b7eaed25SJason Evans INDEX_PROTO(arenas_lextent_i)
127a4bd5210SJason Evans CTL_PROTO(arenas_narenas)
128b7eaed25SJason Evans CTL_PROTO(arenas_dirty_decay_ms)
129b7eaed25SJason Evans CTL_PROTO(arenas_muzzy_decay_ms)
130a4bd5210SJason Evans CTL_PROTO(arenas_quantum)
131a4bd5210SJason Evans CTL_PROTO(arenas_page)
132a4bd5210SJason Evans CTL_PROTO(arenas_tcache_max)
133a4bd5210SJason Evans CTL_PROTO(arenas_nbins)
134a4bd5210SJason Evans CTL_PROTO(arenas_nhbins)
135b7eaed25SJason Evans CTL_PROTO(arenas_nlextents)
136b7eaed25SJason Evans CTL_PROTO(arenas_create)
137d0e79aa3SJason Evans CTL_PROTO(prof_thread_active_init)
138a4bd5210SJason Evans CTL_PROTO(prof_active)
139a4bd5210SJason Evans CTL_PROTO(prof_dump)
140d0e79aa3SJason Evans CTL_PROTO(prof_gdump)
141d0e79aa3SJason Evans CTL_PROTO(prof_reset)
142a4bd5210SJason Evans CTL_PROTO(prof_interval)
143d0e79aa3SJason Evans CTL_PROTO(lg_prof_sample)
144a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_small_allocated)
145a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_small_nmalloc)
146a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_small_ndalloc)
147a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_small_nrequests)
148a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_large_allocated)
149a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_large_nmalloc)
150a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_large_ndalloc)
151a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_large_nrequests)
152a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_bins_j_nmalloc)
153a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_bins_j_ndalloc)
154a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_bins_j_nrequests)
155d0e79aa3SJason Evans CTL_PROTO(stats_arenas_i_bins_j_curregs)
156a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_bins_j_nfills)
157a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_bins_j_nflushes)
158b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_bins_j_nslabs)
159b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_bins_j_nreslabs)
160b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_bins_j_curslabs)
161a4bd5210SJason Evans INDEX_PROTO(stats_arenas_i_bins_j)
162b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_lextents_j_nmalloc)
163b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_lextents_j_ndalloc)
164b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_lextents_j_nrequests)
165b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_lextents_j_curlextents)
166b7eaed25SJason Evans INDEX_PROTO(stats_arenas_i_lextents_j)
167a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_nthreads)
168b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_uptime)
16982872ac0SJason Evans CTL_PROTO(stats_arenas_i_dss)
170b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_dirty_decay_ms)
171b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_muzzy_decay_ms)
172a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_pactive)
173a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_pdirty)
174b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_pmuzzy)
175a4bd5210SJason Evans CTL_PROTO(stats_arenas_i_mapped)
1761f0a49e8SJason Evans CTL_PROTO(stats_arenas_i_retained)
177b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_dirty_npurge)
178b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_dirty_nmadvise)
179b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_dirty_purged)
180b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_muzzy_npurge)
181b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_muzzy_nmadvise)
182b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_muzzy_purged)
183b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_base)
184b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_internal)
185b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_tcache_bytes)
186b7eaed25SJason Evans CTL_PROTO(stats_arenas_i_resident)
187a4bd5210SJason Evans INDEX_PROTO(stats_arenas_i)
188a4bd5210SJason Evans CTL_PROTO(stats_allocated)
189a4bd5210SJason Evans CTL_PROTO(stats_active)
190b7eaed25SJason Evans CTL_PROTO(stats_background_thread_num_threads)
191b7eaed25SJason Evans CTL_PROTO(stats_background_thread_num_runs)
192b7eaed25SJason Evans CTL_PROTO(stats_background_thread_run_interval)
193d0e79aa3SJason Evans CTL_PROTO(stats_metadata)
194d0e79aa3SJason Evans CTL_PROTO(stats_resident)
195a4bd5210SJason Evans CTL_PROTO(stats_mapped)
1961f0a49e8SJason Evans CTL_PROTO(stats_retained)
197a4bd5210SJason Evans 
198b7eaed25SJason Evans #define MUTEX_STATS_CTL_PROTO_GEN(n)					\
199b7eaed25SJason Evans CTL_PROTO(stats_##n##_num_ops)						\
200b7eaed25SJason Evans CTL_PROTO(stats_##n##_num_wait)						\
201b7eaed25SJason Evans CTL_PROTO(stats_##n##_num_spin_acq)					\
202b7eaed25SJason Evans CTL_PROTO(stats_##n##_num_owner_switch)					\
203b7eaed25SJason Evans CTL_PROTO(stats_##n##_total_wait_time)					\
204b7eaed25SJason Evans CTL_PROTO(stats_##n##_max_wait_time)					\
205b7eaed25SJason Evans CTL_PROTO(stats_##n##_max_num_thds)
206b7eaed25SJason Evans 
207b7eaed25SJason Evans /* Global mutexes. */
208b7eaed25SJason Evans #define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(mutexes_##mtx)
209b7eaed25SJason Evans MUTEX_PROF_GLOBAL_MUTEXES
210b7eaed25SJason Evans #undef OP
211b7eaed25SJason Evans 
212b7eaed25SJason Evans /* Per arena mutexes. */
213b7eaed25SJason Evans #define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##mtx)
214b7eaed25SJason Evans MUTEX_PROF_ARENA_MUTEXES
215b7eaed25SJason Evans #undef OP
216b7eaed25SJason Evans 
217b7eaed25SJason Evans /* Arena bin mutexes. */
218b7eaed25SJason Evans MUTEX_STATS_CTL_PROTO_GEN(arenas_i_bins_j_mutex)
219b7eaed25SJason Evans #undef MUTEX_STATS_CTL_PROTO_GEN
220b7eaed25SJason Evans 
221b7eaed25SJason Evans CTL_PROTO(stats_mutexes_reset)
222b7eaed25SJason Evans 
223a4bd5210SJason Evans /******************************************************************************/
224a4bd5210SJason Evans /* mallctl tree. */
225a4bd5210SJason Evans 
226e722f8f8SJason Evans #define NAME(n)	{true},	n
227e722f8f8SJason Evans #define CHILD(t, c)							\
228e722f8f8SJason Evans 	sizeof(c##_node) / sizeof(ctl_##t##_node_t),			\
229e722f8f8SJason Evans 	(ctl_node_t *)c##_node,						\
230e722f8f8SJason Evans 	NULL
231e722f8f8SJason Evans #define CTL(c)	0, NULL, c##_ctl
232a4bd5210SJason Evans 
233a4bd5210SJason Evans /*
234a4bd5210SJason Evans  * Only handles internal indexed nodes, since there are currently no external
235a4bd5210SJason Evans  * ones.
236a4bd5210SJason Evans  */
237e722f8f8SJason Evans #define INDEX(i)	{false},	i##_index
238a4bd5210SJason Evans 
239d0e79aa3SJason Evans static const ctl_named_node_t	thread_tcache_node[] = {
240a4bd5210SJason Evans 	{NAME("enabled"),	CTL(thread_tcache_enabled)},
241a4bd5210SJason Evans 	{NAME("flush"),		CTL(thread_tcache_flush)}
242a4bd5210SJason Evans };
243a4bd5210SJason Evans 
244d0e79aa3SJason Evans static const ctl_named_node_t	thread_prof_node[] = {
245d0e79aa3SJason Evans 	{NAME("name"),		CTL(thread_prof_name)},
246d0e79aa3SJason Evans 	{NAME("active"),	CTL(thread_prof_active)}
247d0e79aa3SJason Evans };
248d0e79aa3SJason Evans 
249e722f8f8SJason Evans static const ctl_named_node_t	thread_node[] = {
250a4bd5210SJason Evans 	{NAME("arena"),		CTL(thread_arena)},
251a4bd5210SJason Evans 	{NAME("allocated"),	CTL(thread_allocated)},
252a4bd5210SJason Evans 	{NAME("allocatedp"),	CTL(thread_allocatedp)},
253a4bd5210SJason Evans 	{NAME("deallocated"),	CTL(thread_deallocated)},
254a4bd5210SJason Evans 	{NAME("deallocatedp"),	CTL(thread_deallocatedp)},
255d0e79aa3SJason Evans 	{NAME("tcache"),	CHILD(named, thread_tcache)},
256d0e79aa3SJason Evans 	{NAME("prof"),		CHILD(named, thread_prof)}
257a4bd5210SJason Evans };
258a4bd5210SJason Evans 
259e722f8f8SJason Evans static const ctl_named_node_t	config_node[] = {
260d0e79aa3SJason Evans 	{NAME("cache_oblivious"), CTL(config_cache_oblivious)},
261a4bd5210SJason Evans 	{NAME("debug"),		CTL(config_debug)},
262a4bd5210SJason Evans 	{NAME("fill"),		CTL(config_fill)},
263a4bd5210SJason Evans 	{NAME("lazy_lock"),	CTL(config_lazy_lock)},
264df0d881dSJason Evans 	{NAME("malloc_conf"),	CTL(config_malloc_conf)},
265a4bd5210SJason Evans 	{NAME("prof"),		CTL(config_prof)},
266a4bd5210SJason Evans 	{NAME("prof_libgcc"),	CTL(config_prof_libgcc)},
267a4bd5210SJason Evans 	{NAME("prof_libunwind"), CTL(config_prof_libunwind)},
268a4bd5210SJason Evans 	{NAME("stats"),		CTL(config_stats)},
2698244f2aaSJason Evans 	{NAME("thp"),		CTL(config_thp)},
270a4bd5210SJason Evans 	{NAME("utrace"),	CTL(config_utrace)},
271a4bd5210SJason Evans 	{NAME("xmalloc"),	CTL(config_xmalloc)}
272a4bd5210SJason Evans };
273a4bd5210SJason Evans 
274e722f8f8SJason Evans static const ctl_named_node_t opt_node[] = {
275a4bd5210SJason Evans 	{NAME("abort"),		CTL(opt_abort)},
276b7eaed25SJason Evans 	{NAME("abort_conf"),	CTL(opt_abort_conf)},
277b7eaed25SJason Evans 	{NAME("retain"),	CTL(opt_retain)},
27882872ac0SJason Evans 	{NAME("dss"),		CTL(opt_dss)},
279a4bd5210SJason Evans 	{NAME("narenas"),	CTL(opt_narenas)},
280b7eaed25SJason Evans 	{NAME("percpu_arena"),	CTL(opt_percpu_arena)},
281b7eaed25SJason Evans 	{NAME("background_thread"),	CTL(opt_background_thread)},
282b7eaed25SJason Evans 	{NAME("dirty_decay_ms"), CTL(opt_dirty_decay_ms)},
283b7eaed25SJason Evans 	{NAME("muzzy_decay_ms"), CTL(opt_muzzy_decay_ms)},
284a4bd5210SJason Evans 	{NAME("stats_print"),	CTL(opt_stats_print)},
285b7eaed25SJason Evans 	{NAME("stats_print_opts"),	CTL(opt_stats_print_opts)},
286a4bd5210SJason Evans 	{NAME("junk"),		CTL(opt_junk)},
287a4bd5210SJason Evans 	{NAME("zero"),		CTL(opt_zero)},
288a4bd5210SJason Evans 	{NAME("utrace"),	CTL(opt_utrace)},
289a4bd5210SJason Evans 	{NAME("xmalloc"),	CTL(opt_xmalloc)},
290a4bd5210SJason Evans 	{NAME("tcache"),	CTL(opt_tcache)},
291a4bd5210SJason Evans 	{NAME("lg_tcache_max"),	CTL(opt_lg_tcache_max)},
292a4bd5210SJason Evans 	{NAME("prof"),		CTL(opt_prof)},
293a4bd5210SJason Evans 	{NAME("prof_prefix"),	CTL(opt_prof_prefix)},
294a4bd5210SJason Evans 	{NAME("prof_active"),	CTL(opt_prof_active)},
295d0e79aa3SJason Evans 	{NAME("prof_thread_active_init"), CTL(opt_prof_thread_active_init)},
296a4bd5210SJason Evans 	{NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)},
297a4bd5210SJason Evans 	{NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)},
298a4bd5210SJason Evans 	{NAME("prof_gdump"),	CTL(opt_prof_gdump)},
2998ed34ab0SJason Evans 	{NAME("prof_final"),	CTL(opt_prof_final)},
300a4bd5210SJason Evans 	{NAME("prof_leak"),	CTL(opt_prof_leak)},
301a4bd5210SJason Evans 	{NAME("prof_accum"),	CTL(opt_prof_accum)}
302a4bd5210SJason Evans };
303a4bd5210SJason Evans 
304d0e79aa3SJason Evans static const ctl_named_node_t	tcache_node[] = {
305d0e79aa3SJason Evans 	{NAME("create"),	CTL(tcache_create)},
306d0e79aa3SJason Evans 	{NAME("flush"),		CTL(tcache_flush)},
307d0e79aa3SJason Evans 	{NAME("destroy"),	CTL(tcache_destroy)}
308d0e79aa3SJason Evans };
309d0e79aa3SJason Evans 
31082872ac0SJason Evans static const ctl_named_node_t arena_i_node[] = {
311b7eaed25SJason Evans 	{NAME("initialized"),	CTL(arena_i_initialized)},
312df0d881dSJason Evans 	{NAME("decay"),		CTL(arena_i_decay)},
313b7eaed25SJason Evans 	{NAME("purge"),		CTL(arena_i_purge)},
3141f0a49e8SJason Evans 	{NAME("reset"),		CTL(arena_i_reset)},
315b7eaed25SJason Evans 	{NAME("destroy"),	CTL(arena_i_destroy)},
316d0e79aa3SJason Evans 	{NAME("dss"),		CTL(arena_i_dss)},
317b7eaed25SJason Evans 	{NAME("dirty_decay_ms"), CTL(arena_i_dirty_decay_ms)},
318b7eaed25SJason Evans 	{NAME("muzzy_decay_ms"), CTL(arena_i_muzzy_decay_ms)},
319b7eaed25SJason Evans 	{NAME("extent_hooks"),	CTL(arena_i_extent_hooks)}
32082872ac0SJason Evans };
32182872ac0SJason Evans static const ctl_named_node_t super_arena_i_node[] = {
32282872ac0SJason Evans 	{NAME(""),		CHILD(named, arena_i)}
32382872ac0SJason Evans };
32482872ac0SJason Evans 
32582872ac0SJason Evans static const ctl_indexed_node_t arena_node[] = {
32682872ac0SJason Evans 	{INDEX(arena_i)}
32782872ac0SJason Evans };
32882872ac0SJason Evans 
329e722f8f8SJason Evans static const ctl_named_node_t arenas_bin_i_node[] = {
330a4bd5210SJason Evans 	{NAME("size"),		CTL(arenas_bin_i_size)},
331a4bd5210SJason Evans 	{NAME("nregs"),		CTL(arenas_bin_i_nregs)},
332b7eaed25SJason Evans 	{NAME("slab_size"),	CTL(arenas_bin_i_slab_size)}
333a4bd5210SJason Evans };
334e722f8f8SJason Evans static const ctl_named_node_t super_arenas_bin_i_node[] = {
335e722f8f8SJason Evans 	{NAME(""),		CHILD(named, arenas_bin_i)}
336a4bd5210SJason Evans };
337a4bd5210SJason Evans 
338e722f8f8SJason Evans static const ctl_indexed_node_t arenas_bin_node[] = {
339a4bd5210SJason Evans 	{INDEX(arenas_bin_i)}
340a4bd5210SJason Evans };
341a4bd5210SJason Evans 
342b7eaed25SJason Evans static const ctl_named_node_t arenas_lextent_i_node[] = {
343b7eaed25SJason Evans 	{NAME("size"),		CTL(arenas_lextent_i_size)}
344a4bd5210SJason Evans };
345b7eaed25SJason Evans static const ctl_named_node_t super_arenas_lextent_i_node[] = {
346b7eaed25SJason Evans 	{NAME(""),		CHILD(named, arenas_lextent_i)}
347a4bd5210SJason Evans };
348a4bd5210SJason Evans 
349b7eaed25SJason Evans static const ctl_indexed_node_t arenas_lextent_node[] = {
350b7eaed25SJason Evans 	{INDEX(arenas_lextent_i)}
351d0e79aa3SJason Evans };
352d0e79aa3SJason Evans 
353e722f8f8SJason Evans static const ctl_named_node_t arenas_node[] = {
354a4bd5210SJason Evans 	{NAME("narenas"),	CTL(arenas_narenas)},
355b7eaed25SJason Evans 	{NAME("dirty_decay_ms"), CTL(arenas_dirty_decay_ms)},
356b7eaed25SJason Evans 	{NAME("muzzy_decay_ms"), CTL(arenas_muzzy_decay_ms)},
357a4bd5210SJason Evans 	{NAME("quantum"),	CTL(arenas_quantum)},
358a4bd5210SJason Evans 	{NAME("page"),		CTL(arenas_page)},
359a4bd5210SJason Evans 	{NAME("tcache_max"),	CTL(arenas_tcache_max)},
360a4bd5210SJason Evans 	{NAME("nbins"),		CTL(arenas_nbins)},
361a4bd5210SJason Evans 	{NAME("nhbins"),	CTL(arenas_nhbins)},
362e722f8f8SJason Evans 	{NAME("bin"),		CHILD(indexed, arenas_bin)},
363b7eaed25SJason Evans 	{NAME("nlextents"),	CTL(arenas_nlextents)},
364b7eaed25SJason Evans 	{NAME("lextent"),	CHILD(indexed, arenas_lextent)},
365b7eaed25SJason Evans 	{NAME("create"),	CTL(arenas_create)}
366a4bd5210SJason Evans };
367a4bd5210SJason Evans 
368e722f8f8SJason Evans static const ctl_named_node_t	prof_node[] = {
369d0e79aa3SJason Evans 	{NAME("thread_active_init"), CTL(prof_thread_active_init)},
370a4bd5210SJason Evans 	{NAME("active"),	CTL(prof_active)},
371a4bd5210SJason Evans 	{NAME("dump"),		CTL(prof_dump)},
372d0e79aa3SJason Evans 	{NAME("gdump"),		CTL(prof_gdump)},
373d0e79aa3SJason Evans 	{NAME("reset"),		CTL(prof_reset)},
374d0e79aa3SJason Evans 	{NAME("interval"),	CTL(prof_interval)},
375d0e79aa3SJason Evans 	{NAME("lg_sample"),	CTL(lg_prof_sample)}
376a4bd5210SJason Evans };
377a4bd5210SJason Evans 
378e722f8f8SJason Evans static const ctl_named_node_t stats_arenas_i_small_node[] = {
379a4bd5210SJason Evans 	{NAME("allocated"),	CTL(stats_arenas_i_small_allocated)},
380a4bd5210SJason Evans 	{NAME("nmalloc"),	CTL(stats_arenas_i_small_nmalloc)},
381a4bd5210SJason Evans 	{NAME("ndalloc"),	CTL(stats_arenas_i_small_ndalloc)},
382a4bd5210SJason Evans 	{NAME("nrequests"),	CTL(stats_arenas_i_small_nrequests)}
383a4bd5210SJason Evans };
384a4bd5210SJason Evans 
385e722f8f8SJason Evans static const ctl_named_node_t stats_arenas_i_large_node[] = {
386a4bd5210SJason Evans 	{NAME("allocated"),	CTL(stats_arenas_i_large_allocated)},
387a4bd5210SJason Evans 	{NAME("nmalloc"),	CTL(stats_arenas_i_large_nmalloc)},
388a4bd5210SJason Evans 	{NAME("ndalloc"),	CTL(stats_arenas_i_large_ndalloc)},
389a4bd5210SJason Evans 	{NAME("nrequests"),	CTL(stats_arenas_i_large_nrequests)}
390a4bd5210SJason Evans };
391a4bd5210SJason Evans 
392b7eaed25SJason Evans #define MUTEX_PROF_DATA_NODE(prefix)					\
393b7eaed25SJason Evans static const ctl_named_node_t stats_##prefix##_node[] = {		\
394b7eaed25SJason Evans 	{NAME("num_ops"),						\
395b7eaed25SJason Evans 	 CTL(stats_##prefix##_num_ops)},				\
396b7eaed25SJason Evans 	{NAME("num_wait"),						\
397b7eaed25SJason Evans 	 CTL(stats_##prefix##_num_wait)},				\
398b7eaed25SJason Evans 	{NAME("num_spin_acq"),						\
399b7eaed25SJason Evans 	 CTL(stats_##prefix##_num_spin_acq)},				\
400b7eaed25SJason Evans 	{NAME("num_owner_switch"),					\
401b7eaed25SJason Evans 	 CTL(stats_##prefix##_num_owner_switch)},			\
402b7eaed25SJason Evans 	{NAME("total_wait_time"),					\
403b7eaed25SJason Evans 	 CTL(stats_##prefix##_total_wait_time)},			\
404b7eaed25SJason Evans 	{NAME("max_wait_time"),						\
405b7eaed25SJason Evans 	 CTL(stats_##prefix##_max_wait_time)},				\
406b7eaed25SJason Evans 	{NAME("max_num_thds"),						\
407b7eaed25SJason Evans 	 CTL(stats_##prefix##_max_num_thds)}				\
408b7eaed25SJason Evans 	/* Note that # of current waiting thread not provided. */	\
409d0e79aa3SJason Evans };
410d0e79aa3SJason Evans 
411b7eaed25SJason Evans MUTEX_PROF_DATA_NODE(arenas_i_bins_j_mutex)
412b7eaed25SJason Evans 
413e722f8f8SJason Evans static const ctl_named_node_t stats_arenas_i_bins_j_node[] = {
414a4bd5210SJason Evans 	{NAME("nmalloc"),	CTL(stats_arenas_i_bins_j_nmalloc)},
415a4bd5210SJason Evans 	{NAME("ndalloc"),	CTL(stats_arenas_i_bins_j_ndalloc)},
416a4bd5210SJason Evans 	{NAME("nrequests"),	CTL(stats_arenas_i_bins_j_nrequests)},
417d0e79aa3SJason Evans 	{NAME("curregs"),	CTL(stats_arenas_i_bins_j_curregs)},
418a4bd5210SJason Evans 	{NAME("nfills"),	CTL(stats_arenas_i_bins_j_nfills)},
419a4bd5210SJason Evans 	{NAME("nflushes"),	CTL(stats_arenas_i_bins_j_nflushes)},
420b7eaed25SJason Evans 	{NAME("nslabs"),	CTL(stats_arenas_i_bins_j_nslabs)},
421b7eaed25SJason Evans 	{NAME("nreslabs"),	CTL(stats_arenas_i_bins_j_nreslabs)},
422b7eaed25SJason Evans 	{NAME("curslabs"),	CTL(stats_arenas_i_bins_j_curslabs)},
423b7eaed25SJason Evans 	{NAME("mutex"),		CHILD(named, stats_arenas_i_bins_j_mutex)}
424a4bd5210SJason Evans };
425b7eaed25SJason Evans 
426e722f8f8SJason Evans static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = {
427e722f8f8SJason Evans 	{NAME(""),		CHILD(named, stats_arenas_i_bins_j)}
428a4bd5210SJason Evans };
429a4bd5210SJason Evans 
430e722f8f8SJason Evans static const ctl_indexed_node_t stats_arenas_i_bins_node[] = {
431a4bd5210SJason Evans 	{INDEX(stats_arenas_i_bins_j)}
432a4bd5210SJason Evans };
433a4bd5210SJason Evans 
434b7eaed25SJason Evans static const ctl_named_node_t stats_arenas_i_lextents_j_node[] = {
435b7eaed25SJason Evans 	{NAME("nmalloc"),	CTL(stats_arenas_i_lextents_j_nmalloc)},
436b7eaed25SJason Evans 	{NAME("ndalloc"),	CTL(stats_arenas_i_lextents_j_ndalloc)},
437b7eaed25SJason Evans 	{NAME("nrequests"),	CTL(stats_arenas_i_lextents_j_nrequests)},
438b7eaed25SJason Evans 	{NAME("curlextents"),	CTL(stats_arenas_i_lextents_j_curlextents)}
439a4bd5210SJason Evans };
440b7eaed25SJason Evans static const ctl_named_node_t super_stats_arenas_i_lextents_j_node[] = {
441b7eaed25SJason Evans 	{NAME(""),		CHILD(named, stats_arenas_i_lextents_j)}
442a4bd5210SJason Evans };
443a4bd5210SJason Evans 
444b7eaed25SJason Evans static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = {
445b7eaed25SJason Evans 	{INDEX(stats_arenas_i_lextents_j)}
446a4bd5210SJason Evans };
447a4bd5210SJason Evans 
448b7eaed25SJason Evans #define OP(mtx)  MUTEX_PROF_DATA_NODE(arenas_i_mutexes_##mtx)
449b7eaed25SJason Evans MUTEX_PROF_ARENA_MUTEXES
450b7eaed25SJason Evans #undef OP
451d0e79aa3SJason Evans 
452b7eaed25SJason Evans static const ctl_named_node_t stats_arenas_i_mutexes_node[] = {
453b7eaed25SJason Evans #define OP(mtx) {NAME(#mtx), CHILD(named, stats_arenas_i_mutexes_##mtx)},
454b7eaed25SJason Evans MUTEX_PROF_ARENA_MUTEXES
455b7eaed25SJason Evans #undef OP
456d0e79aa3SJason Evans };
457d0e79aa3SJason Evans 
458e722f8f8SJason Evans static const ctl_named_node_t stats_arenas_i_node[] = {
459a4bd5210SJason Evans 	{NAME("nthreads"),	CTL(stats_arenas_i_nthreads)},
460b7eaed25SJason Evans 	{NAME("uptime"),	CTL(stats_arenas_i_uptime)},
46182872ac0SJason Evans 	{NAME("dss"),		CTL(stats_arenas_i_dss)},
462b7eaed25SJason Evans 	{NAME("dirty_decay_ms"), CTL(stats_arenas_i_dirty_decay_ms)},
463b7eaed25SJason Evans 	{NAME("muzzy_decay_ms"), CTL(stats_arenas_i_muzzy_decay_ms)},
464a4bd5210SJason Evans 	{NAME("pactive"),	CTL(stats_arenas_i_pactive)},
465a4bd5210SJason Evans 	{NAME("pdirty"),	CTL(stats_arenas_i_pdirty)},
466b7eaed25SJason Evans 	{NAME("pmuzzy"),	CTL(stats_arenas_i_pmuzzy)},
467a4bd5210SJason Evans 	{NAME("mapped"),	CTL(stats_arenas_i_mapped)},
4681f0a49e8SJason Evans 	{NAME("retained"),	CTL(stats_arenas_i_retained)},
469b7eaed25SJason Evans 	{NAME("dirty_npurge"),	CTL(stats_arenas_i_dirty_npurge)},
470b7eaed25SJason Evans 	{NAME("dirty_nmadvise"), CTL(stats_arenas_i_dirty_nmadvise)},
471b7eaed25SJason Evans 	{NAME("dirty_purged"),	CTL(stats_arenas_i_dirty_purged)},
472b7eaed25SJason Evans 	{NAME("muzzy_npurge"),	CTL(stats_arenas_i_muzzy_npurge)},
473b7eaed25SJason Evans 	{NAME("muzzy_nmadvise"), CTL(stats_arenas_i_muzzy_nmadvise)},
474b7eaed25SJason Evans 	{NAME("muzzy_purged"),	CTL(stats_arenas_i_muzzy_purged)},
475b7eaed25SJason Evans 	{NAME("base"),		CTL(stats_arenas_i_base)},
476b7eaed25SJason Evans 	{NAME("internal"),	CTL(stats_arenas_i_internal)},
477b7eaed25SJason Evans 	{NAME("tcache_bytes"),	CTL(stats_arenas_i_tcache_bytes)},
478b7eaed25SJason Evans 	{NAME("resident"),	CTL(stats_arenas_i_resident)},
479e722f8f8SJason Evans 	{NAME("small"),		CHILD(named, stats_arenas_i_small)},
480e722f8f8SJason Evans 	{NAME("large"),		CHILD(named, stats_arenas_i_large)},
481e722f8f8SJason Evans 	{NAME("bins"),		CHILD(indexed, stats_arenas_i_bins)},
482b7eaed25SJason Evans 	{NAME("lextents"),	CHILD(indexed, stats_arenas_i_lextents)},
483b7eaed25SJason Evans 	{NAME("mutexes"),	CHILD(named, stats_arenas_i_mutexes)}
484a4bd5210SJason Evans };
485e722f8f8SJason Evans static const ctl_named_node_t super_stats_arenas_i_node[] = {
486e722f8f8SJason Evans 	{NAME(""),		CHILD(named, stats_arenas_i)}
487a4bd5210SJason Evans };
488a4bd5210SJason Evans 
489e722f8f8SJason Evans static const ctl_indexed_node_t stats_arenas_node[] = {
490a4bd5210SJason Evans 	{INDEX(stats_arenas_i)}
491a4bd5210SJason Evans };
492a4bd5210SJason Evans 
493b7eaed25SJason Evans static const ctl_named_node_t stats_background_thread_node[] = {
494b7eaed25SJason Evans 	{NAME("num_threads"),	CTL(stats_background_thread_num_threads)},
495b7eaed25SJason Evans 	{NAME("num_runs"),	CTL(stats_background_thread_num_runs)},
496b7eaed25SJason Evans 	{NAME("run_interval"),	CTL(stats_background_thread_run_interval)}
497b7eaed25SJason Evans };
498b7eaed25SJason Evans 
499b7eaed25SJason Evans #define OP(mtx) MUTEX_PROF_DATA_NODE(mutexes_##mtx)
500b7eaed25SJason Evans MUTEX_PROF_GLOBAL_MUTEXES
501b7eaed25SJason Evans #undef OP
502b7eaed25SJason Evans 
503b7eaed25SJason Evans static const ctl_named_node_t stats_mutexes_node[] = {
504b7eaed25SJason Evans #define OP(mtx) {NAME(#mtx), CHILD(named, stats_mutexes_##mtx)},
505b7eaed25SJason Evans MUTEX_PROF_GLOBAL_MUTEXES
506b7eaed25SJason Evans #undef OP
507b7eaed25SJason Evans 	{NAME("reset"),		CTL(stats_mutexes_reset)}
508b7eaed25SJason Evans };
509b7eaed25SJason Evans #undef MUTEX_PROF_DATA_NODE
510b7eaed25SJason Evans 
511e722f8f8SJason Evans static const ctl_named_node_t stats_node[] = {
512a4bd5210SJason Evans 	{NAME("allocated"),	CTL(stats_allocated)},
513a4bd5210SJason Evans 	{NAME("active"),	CTL(stats_active)},
514d0e79aa3SJason Evans 	{NAME("metadata"),	CTL(stats_metadata)},
515d0e79aa3SJason Evans 	{NAME("resident"),	CTL(stats_resident)},
516a4bd5210SJason Evans 	{NAME("mapped"),	CTL(stats_mapped)},
5171f0a49e8SJason Evans 	{NAME("retained"),	CTL(stats_retained)},
518b7eaed25SJason Evans 	{NAME("background_thread"),
519b7eaed25SJason Evans 	 CHILD(named, stats_background_thread)},
520b7eaed25SJason Evans 	{NAME("mutexes"),	CHILD(named, stats_mutexes)},
521e722f8f8SJason Evans 	{NAME("arenas"),	CHILD(indexed, stats_arenas)}
522a4bd5210SJason Evans };
523a4bd5210SJason Evans 
524e722f8f8SJason Evans static const ctl_named_node_t	root_node[] = {
525a4bd5210SJason Evans 	{NAME("version"),	CTL(version)},
526a4bd5210SJason Evans 	{NAME("epoch"),		CTL(epoch)},
527b7eaed25SJason Evans 	{NAME("background_thread"),	CTL(background_thread)},
528e722f8f8SJason Evans 	{NAME("thread"),	CHILD(named, thread)},
529e722f8f8SJason Evans 	{NAME("config"),	CHILD(named, config)},
530e722f8f8SJason Evans 	{NAME("opt"),		CHILD(named, opt)},
531d0e79aa3SJason Evans 	{NAME("tcache"),	CHILD(named, tcache)},
53282872ac0SJason Evans 	{NAME("arena"),		CHILD(indexed, arena)},
533e722f8f8SJason Evans 	{NAME("arenas"),	CHILD(named, arenas)},
534e722f8f8SJason Evans 	{NAME("prof"),		CHILD(named, prof)},
535e722f8f8SJason Evans 	{NAME("stats"),		CHILD(named, stats)}
536a4bd5210SJason Evans };
537e722f8f8SJason Evans static const ctl_named_node_t super_root_node[] = {
538e722f8f8SJason Evans 	{NAME(""),		CHILD(named, root)}
539a4bd5210SJason Evans };
540a4bd5210SJason Evans 
541a4bd5210SJason Evans #undef NAME
542a4bd5210SJason Evans #undef CHILD
543a4bd5210SJason Evans #undef CTL
544a4bd5210SJason Evans #undef INDEX
545a4bd5210SJason Evans 
546a4bd5210SJason Evans /******************************************************************************/
547a4bd5210SJason Evans 
548b7eaed25SJason Evans /*
549b7eaed25SJason Evans  * Sets *dst + *src non-atomically.  This is safe, since everything is
550b7eaed25SJason Evans  * synchronized by the ctl mutex.
551b7eaed25SJason Evans  */
552a4bd5210SJason Evans static void
553b7eaed25SJason Evans accum_arena_stats_u64(arena_stats_u64_t *dst, arena_stats_u64_t *src) {
554b7eaed25SJason Evans #ifdef JEMALLOC_ATOMIC_U64
555b7eaed25SJason Evans 	uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED);
556b7eaed25SJason Evans 	uint64_t cur_src = atomic_load_u64(src, ATOMIC_RELAXED);
557b7eaed25SJason Evans 	atomic_store_u64(dst, cur_dst + cur_src, ATOMIC_RELAXED);
558b7eaed25SJason Evans #else
559b7eaed25SJason Evans 	*dst += *src;
560b7eaed25SJason Evans #endif
561b7eaed25SJason Evans }
562a4bd5210SJason Evans 
563b7eaed25SJason Evans /* Likewise: with ctl mutex synchronization, reading is simple. */
564b7eaed25SJason Evans static uint64_t
565b7eaed25SJason Evans arena_stats_read_u64(arena_stats_u64_t *p) {
566b7eaed25SJason Evans #ifdef JEMALLOC_ATOMIC_U64
567b7eaed25SJason Evans 	return atomic_load_u64(p, ATOMIC_RELAXED);
568b7eaed25SJason Evans #else
569b7eaed25SJason Evans 	return *p;
570b7eaed25SJason Evans #endif
571b7eaed25SJason Evans }
572b7eaed25SJason Evans 
573b7eaed25SJason Evans static void accum_atomic_zu(atomic_zu_t *dst, atomic_zu_t *src) {
574b7eaed25SJason Evans 	size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED);
575b7eaed25SJason Evans 	size_t cur_src = atomic_load_zu(src, ATOMIC_RELAXED);
576b7eaed25SJason Evans 	atomic_store_zu(dst, cur_dst + cur_src, ATOMIC_RELAXED);
577b7eaed25SJason Evans }
578b7eaed25SJason Evans 
579b7eaed25SJason Evans /******************************************************************************/
580b7eaed25SJason Evans 
581b7eaed25SJason Evans static unsigned
582b7eaed25SJason Evans arenas_i2a_impl(size_t i, bool compat, bool validate) {
583b7eaed25SJason Evans 	unsigned a;
584b7eaed25SJason Evans 
585b7eaed25SJason Evans 	switch (i) {
586b7eaed25SJason Evans 	case MALLCTL_ARENAS_ALL:
587b7eaed25SJason Evans 		a = 0;
588b7eaed25SJason Evans 		break;
589b7eaed25SJason Evans 	case MALLCTL_ARENAS_DESTROYED:
590b7eaed25SJason Evans 		a = 1;
591b7eaed25SJason Evans 		break;
592b7eaed25SJason Evans 	default:
593b7eaed25SJason Evans 		if (compat && i == ctl_arenas->narenas) {
594b7eaed25SJason Evans 			/*
595b7eaed25SJason Evans 			 * Provide deprecated backward compatibility for
596b7eaed25SJason Evans 			 * accessing the merged stats at index narenas rather
597b7eaed25SJason Evans 			 * than via MALLCTL_ARENAS_ALL.  This is scheduled for
598b7eaed25SJason Evans 			 * removal in 6.0.0.
599b7eaed25SJason Evans 			 */
600b7eaed25SJason Evans 			a = 0;
601b7eaed25SJason Evans 		} else if (validate && i >= ctl_arenas->narenas) {
602b7eaed25SJason Evans 			a = UINT_MAX;
603b7eaed25SJason Evans 		} else {
604b7eaed25SJason Evans 			/*
605b7eaed25SJason Evans 			 * This function should never be called for an index
606b7eaed25SJason Evans 			 * more than one past the range of indices that have
607b7eaed25SJason Evans 			 * initialized ctl data.
608b7eaed25SJason Evans 			 */
609b7eaed25SJason Evans 			assert(i < ctl_arenas->narenas || (!validate && i ==
610b7eaed25SJason Evans 			    ctl_arenas->narenas));
611b7eaed25SJason Evans 			a = (unsigned)i + 2;
612b7eaed25SJason Evans 		}
613b7eaed25SJason Evans 		break;
614b7eaed25SJason Evans 	}
615b7eaed25SJason Evans 
616b7eaed25SJason Evans 	return a;
617b7eaed25SJason Evans }
618b7eaed25SJason Evans 
619b7eaed25SJason Evans static unsigned
620b7eaed25SJason Evans arenas_i2a(size_t i) {
621b7eaed25SJason Evans 	return arenas_i2a_impl(i, true, false);
622b7eaed25SJason Evans }
623b7eaed25SJason Evans 
624b7eaed25SJason Evans static ctl_arena_t *
625*8b2f5aafSJason Evans arenas_i_impl(tsd_t *tsd, size_t i, bool compat, bool init) {
626b7eaed25SJason Evans 	ctl_arena_t *ret;
627b7eaed25SJason Evans 
628b7eaed25SJason Evans 	assert(!compat || !init);
629b7eaed25SJason Evans 
630b7eaed25SJason Evans 	ret = ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)];
631b7eaed25SJason Evans 	if (init && ret == NULL) {
632a4bd5210SJason Evans 		if (config_stats) {
633b7eaed25SJason Evans 			struct container_s {
634b7eaed25SJason Evans 				ctl_arena_t		ctl_arena;
635b7eaed25SJason Evans 				ctl_arena_stats_t	astats;
636b7eaed25SJason Evans 			};
637b7eaed25SJason Evans 			struct container_s *cont =
638*8b2f5aafSJason Evans 			    (struct container_s *)base_alloc(tsd_tsdn(tsd),
639*8b2f5aafSJason Evans 			    b0get(), sizeof(struct container_s), QUANTUM);
640b7eaed25SJason Evans 			if (cont == NULL) {
641b7eaed25SJason Evans 				return NULL;
642b7eaed25SJason Evans 			}
643b7eaed25SJason Evans 			ret = &cont->ctl_arena;
644b7eaed25SJason Evans 			ret->astats = &cont->astats;
645b7eaed25SJason Evans 		} else {
646*8b2f5aafSJason Evans 			ret = (ctl_arena_t *)base_alloc(tsd_tsdn(tsd), b0get(),
647b7eaed25SJason Evans 			    sizeof(ctl_arena_t), QUANTUM);
648b7eaed25SJason Evans 			if (ret == NULL) {
649b7eaed25SJason Evans 				return NULL;
650b7eaed25SJason Evans 			}
651b7eaed25SJason Evans 		}
652b7eaed25SJason Evans 		ret->arena_ind = (unsigned)i;
653b7eaed25SJason Evans 		ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)] = ret;
654b7eaed25SJason Evans 	}
655b7eaed25SJason Evans 
656b7eaed25SJason Evans 	assert(ret == NULL || arenas_i2a(ret->arena_ind) == arenas_i2a(i));
657b7eaed25SJason Evans 	return ret;
658b7eaed25SJason Evans }
659b7eaed25SJason Evans 
660b7eaed25SJason Evans static ctl_arena_t *
661b7eaed25SJason Evans arenas_i(size_t i) {
662*8b2f5aafSJason Evans 	ctl_arena_t *ret = arenas_i_impl(tsd_fetch(), i, true, false);
663b7eaed25SJason Evans 	assert(ret != NULL);
664b7eaed25SJason Evans 	return ret;
665b7eaed25SJason Evans }
666b7eaed25SJason Evans 
667b7eaed25SJason Evans static void
668b7eaed25SJason Evans ctl_arena_clear(ctl_arena_t *ctl_arena) {
669b7eaed25SJason Evans 	ctl_arena->nthreads = 0;
670b7eaed25SJason Evans 	ctl_arena->dss = dss_prec_names[dss_prec_limit];
671b7eaed25SJason Evans 	ctl_arena->dirty_decay_ms = -1;
672b7eaed25SJason Evans 	ctl_arena->muzzy_decay_ms = -1;
673b7eaed25SJason Evans 	ctl_arena->pactive = 0;
674b7eaed25SJason Evans 	ctl_arena->pdirty = 0;
675b7eaed25SJason Evans 	ctl_arena->pmuzzy = 0;
676b7eaed25SJason Evans 	if (config_stats) {
677b7eaed25SJason Evans 		memset(&ctl_arena->astats->astats, 0, sizeof(arena_stats_t));
678b7eaed25SJason Evans 		ctl_arena->astats->allocated_small = 0;
679b7eaed25SJason Evans 		ctl_arena->astats->nmalloc_small = 0;
680b7eaed25SJason Evans 		ctl_arena->astats->ndalloc_small = 0;
681b7eaed25SJason Evans 		ctl_arena->astats->nrequests_small = 0;
682b7eaed25SJason Evans 		memset(ctl_arena->astats->bstats, 0, NBINS *
683b7eaed25SJason Evans 		    sizeof(malloc_bin_stats_t));
684b7eaed25SJason Evans 		memset(ctl_arena->astats->lstats, 0, (NSIZES - NBINS) *
685a4bd5210SJason Evans 		    sizeof(malloc_large_stats_t));
686a4bd5210SJason Evans 	}
687a4bd5210SJason Evans }
688a4bd5210SJason Evans 
689a4bd5210SJason Evans static void
690b7eaed25SJason Evans ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) {
691a4bd5210SJason Evans 	unsigned i;
692a4bd5210SJason Evans 
693df0d881dSJason Evans 	if (config_stats) {
694b7eaed25SJason Evans 		arena_stats_merge(tsdn, arena, &ctl_arena->nthreads,
695b7eaed25SJason Evans 		    &ctl_arena->dss, &ctl_arena->dirty_decay_ms,
696b7eaed25SJason Evans 		    &ctl_arena->muzzy_decay_ms, &ctl_arena->pactive,
697b7eaed25SJason Evans 		    &ctl_arena->pdirty, &ctl_arena->pmuzzy,
698b7eaed25SJason Evans 		    &ctl_arena->astats->astats, ctl_arena->astats->bstats,
699b7eaed25SJason Evans 		    ctl_arena->astats->lstats);
700a4bd5210SJason Evans 
701a4bd5210SJason Evans 		for (i = 0; i < NBINS; i++) {
702b7eaed25SJason Evans 			ctl_arena->astats->allocated_small +=
703b7eaed25SJason Evans 			    ctl_arena->astats->bstats[i].curregs *
704b7eaed25SJason Evans 			    sz_index2size(i);
705b7eaed25SJason Evans 			ctl_arena->astats->nmalloc_small +=
706b7eaed25SJason Evans 			    ctl_arena->astats->bstats[i].nmalloc;
707b7eaed25SJason Evans 			ctl_arena->astats->ndalloc_small +=
708b7eaed25SJason Evans 			    ctl_arena->astats->bstats[i].ndalloc;
709b7eaed25SJason Evans 			ctl_arena->astats->nrequests_small +=
710b7eaed25SJason Evans 			    ctl_arena->astats->bstats[i].nrequests;
711a4bd5210SJason Evans 		}
712df0d881dSJason Evans 	} else {
713b7eaed25SJason Evans 		arena_basic_stats_merge(tsdn, arena, &ctl_arena->nthreads,
714b7eaed25SJason Evans 		    &ctl_arena->dss, &ctl_arena->dirty_decay_ms,
715b7eaed25SJason Evans 		    &ctl_arena->muzzy_decay_ms, &ctl_arena->pactive,
716b7eaed25SJason Evans 		    &ctl_arena->pdirty, &ctl_arena->pmuzzy);
717df0d881dSJason Evans 	}
718a4bd5210SJason Evans }
719a4bd5210SJason Evans 
720a4bd5210SJason Evans static void
721b7eaed25SJason Evans ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena,
722b7eaed25SJason Evans     bool destroyed) {
723a4bd5210SJason Evans 	unsigned i;
724a4bd5210SJason Evans 
725b7eaed25SJason Evans 	if (!destroyed) {
726b7eaed25SJason Evans 		ctl_sdarena->nthreads += ctl_arena->nthreads;
727b7eaed25SJason Evans 		ctl_sdarena->pactive += ctl_arena->pactive;
728b7eaed25SJason Evans 		ctl_sdarena->pdirty += ctl_arena->pdirty;
729b7eaed25SJason Evans 		ctl_sdarena->pmuzzy += ctl_arena->pmuzzy;
730b7eaed25SJason Evans 	} else {
731b7eaed25SJason Evans 		assert(ctl_arena->nthreads == 0);
732b7eaed25SJason Evans 		assert(ctl_arena->pactive == 0);
733b7eaed25SJason Evans 		assert(ctl_arena->pdirty == 0);
734b7eaed25SJason Evans 		assert(ctl_arena->pmuzzy == 0);
735b7eaed25SJason Evans 	}
736a4bd5210SJason Evans 
737df0d881dSJason Evans 	if (config_stats) {
738b7eaed25SJason Evans 		ctl_arena_stats_t *sdstats = ctl_sdarena->astats;
739b7eaed25SJason Evans 		ctl_arena_stats_t *astats = ctl_arena->astats;
740a4bd5210SJason Evans 
741b7eaed25SJason Evans 		if (!destroyed) {
742b7eaed25SJason Evans 			accum_atomic_zu(&sdstats->astats.mapped,
743b7eaed25SJason Evans 			    &astats->astats.mapped);
744b7eaed25SJason Evans 			accum_atomic_zu(&sdstats->astats.retained,
745b7eaed25SJason Evans 			    &astats->astats.retained);
746b7eaed25SJason Evans 		}
747d0e79aa3SJason Evans 
748b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.decay_dirty.npurge,
749b7eaed25SJason Evans 		    &astats->astats.decay_dirty.npurge);
750b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.decay_dirty.nmadvise,
751b7eaed25SJason Evans 		    &astats->astats.decay_dirty.nmadvise);
752b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.decay_dirty.purged,
753b7eaed25SJason Evans 		    &astats->astats.decay_dirty.purged);
754a4bd5210SJason Evans 
755b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.decay_muzzy.npurge,
756b7eaed25SJason Evans 		    &astats->astats.decay_muzzy.npurge);
757b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.decay_muzzy.nmadvise,
758b7eaed25SJason Evans 		    &astats->astats.decay_muzzy.nmadvise);
759b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.decay_muzzy.purged,
760b7eaed25SJason Evans 		    &astats->astats.decay_muzzy.purged);
761a4bd5210SJason Evans 
762b7eaed25SJason Evans #define OP(mtx) malloc_mutex_prof_merge(				\
763b7eaed25SJason Evans 		    &(sdstats->astats.mutex_prof_data[			\
764b7eaed25SJason Evans 		        arena_prof_mutex_##mtx]),			\
765b7eaed25SJason Evans 		    &(astats->astats.mutex_prof_data[			\
766b7eaed25SJason Evans 		        arena_prof_mutex_##mtx]));
767b7eaed25SJason Evans MUTEX_PROF_ARENA_MUTEXES
768b7eaed25SJason Evans #undef OP
769b7eaed25SJason Evans 		if (!destroyed) {
770b7eaed25SJason Evans 			accum_atomic_zu(&sdstats->astats.base,
771b7eaed25SJason Evans 			    &astats->astats.base);
772b7eaed25SJason Evans 			accum_atomic_zu(&sdstats->astats.internal,
773b7eaed25SJason Evans 			    &astats->astats.internal);
774b7eaed25SJason Evans 			accum_atomic_zu(&sdstats->astats.resident,
775b7eaed25SJason Evans 			    &astats->astats.resident);
776b7eaed25SJason Evans 		} else {
777b7eaed25SJason Evans 			assert(atomic_load_zu(
778b7eaed25SJason Evans 			    &astats->astats.internal, ATOMIC_RELAXED) == 0);
779b7eaed25SJason Evans 		}
780b7eaed25SJason Evans 
781b7eaed25SJason Evans 		if (!destroyed) {
782b7eaed25SJason Evans 			sdstats->allocated_small += astats->allocated_small;
783b7eaed25SJason Evans 		} else {
784b7eaed25SJason Evans 			assert(astats->allocated_small == 0);
785b7eaed25SJason Evans 		}
786b7eaed25SJason Evans 		sdstats->nmalloc_small += astats->nmalloc_small;
787b7eaed25SJason Evans 		sdstats->ndalloc_small += astats->ndalloc_small;
788b7eaed25SJason Evans 		sdstats->nrequests_small += astats->nrequests_small;
789b7eaed25SJason Evans 
790b7eaed25SJason Evans 		if (!destroyed) {
791b7eaed25SJason Evans 			accum_atomic_zu(&sdstats->astats.allocated_large,
792b7eaed25SJason Evans 			    &astats->astats.allocated_large);
793b7eaed25SJason Evans 		} else {
794b7eaed25SJason Evans 			assert(atomic_load_zu(&astats->astats.allocated_large,
795b7eaed25SJason Evans 			    ATOMIC_RELAXED) == 0);
796b7eaed25SJason Evans 		}
797b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.nmalloc_large,
798b7eaed25SJason Evans 		    &astats->astats.nmalloc_large);
799b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.ndalloc_large,
800b7eaed25SJason Evans 		    &astats->astats.ndalloc_large);
801b7eaed25SJason Evans 		accum_arena_stats_u64(&sdstats->astats.nrequests_large,
802b7eaed25SJason Evans 		    &astats->astats.nrequests_large);
803b7eaed25SJason Evans 
804b7eaed25SJason Evans 		accum_atomic_zu(&sdstats->astats.tcache_bytes,
805b7eaed25SJason Evans 		    &astats->astats.tcache_bytes);
806b7eaed25SJason Evans 
807b7eaed25SJason Evans 		if (ctl_arena->arena_ind == 0) {
808b7eaed25SJason Evans 			sdstats->astats.uptime = astats->astats.uptime;
809b7eaed25SJason Evans 		}
810a4bd5210SJason Evans 
811a4bd5210SJason Evans 		for (i = 0; i < NBINS; i++) {
812b7eaed25SJason Evans 			sdstats->bstats[i].nmalloc += astats->bstats[i].nmalloc;
813b7eaed25SJason Evans 			sdstats->bstats[i].ndalloc += astats->bstats[i].ndalloc;
814b7eaed25SJason Evans 			sdstats->bstats[i].nrequests +=
815df0d881dSJason Evans 			    astats->bstats[i].nrequests;
816b7eaed25SJason Evans 			if (!destroyed) {
817b7eaed25SJason Evans 				sdstats->bstats[i].curregs +=
818b7eaed25SJason Evans 				    astats->bstats[i].curregs;
819b7eaed25SJason Evans 			} else {
820b7eaed25SJason Evans 				assert(astats->bstats[i].curregs == 0);
821b7eaed25SJason Evans 			}
822b7eaed25SJason Evans 			sdstats->bstats[i].nfills += astats->bstats[i].nfills;
823b7eaed25SJason Evans 			sdstats->bstats[i].nflushes +=
824a4bd5210SJason Evans 			    astats->bstats[i].nflushes;
825b7eaed25SJason Evans 			sdstats->bstats[i].nslabs += astats->bstats[i].nslabs;
826b7eaed25SJason Evans 			sdstats->bstats[i].reslabs += astats->bstats[i].reslabs;
827b7eaed25SJason Evans 			if (!destroyed) {
828b7eaed25SJason Evans 				sdstats->bstats[i].curslabs +=
829b7eaed25SJason Evans 				    astats->bstats[i].curslabs;
830b7eaed25SJason Evans 			} else {
831b7eaed25SJason Evans 				assert(astats->bstats[i].curslabs == 0);
832a4bd5210SJason Evans 			}
833b7eaed25SJason Evans 			malloc_mutex_prof_merge(&sdstats->bstats[i].mutex_data,
834b7eaed25SJason Evans 			    &astats->bstats[i].mutex_data);
835a4bd5210SJason Evans 		}
836d0e79aa3SJason Evans 
837b7eaed25SJason Evans 		for (i = 0; i < NSIZES - NBINS; i++) {
838b7eaed25SJason Evans 			accum_arena_stats_u64(&sdstats->lstats[i].nmalloc,
839b7eaed25SJason Evans 			    &astats->lstats[i].nmalloc);
840b7eaed25SJason Evans 			accum_arena_stats_u64(&sdstats->lstats[i].ndalloc,
841b7eaed25SJason Evans 			    &astats->lstats[i].ndalloc);
842b7eaed25SJason Evans 			accum_arena_stats_u64(&sdstats->lstats[i].nrequests,
843b7eaed25SJason Evans 			    &astats->lstats[i].nrequests);
844b7eaed25SJason Evans 			if (!destroyed) {
845b7eaed25SJason Evans 				sdstats->lstats[i].curlextents +=
846b7eaed25SJason Evans 				    astats->lstats[i].curlextents;
847b7eaed25SJason Evans 			} else {
848b7eaed25SJason Evans 				assert(astats->lstats[i].curlextents == 0);
849d0e79aa3SJason Evans 			}
850df0d881dSJason Evans 		}
851d0e79aa3SJason Evans 	}
852a4bd5210SJason Evans }
853a4bd5210SJason Evans 
854a4bd5210SJason Evans static void
855b7eaed25SJason Evans ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_t *ctl_sdarena,
856b7eaed25SJason Evans     unsigned i, bool destroyed) {
857b7eaed25SJason Evans 	ctl_arena_t *ctl_arena = arenas_i(i);
858a4bd5210SJason Evans 
859b7eaed25SJason Evans 	ctl_arena_clear(ctl_arena);
860b7eaed25SJason Evans 	ctl_arena_stats_amerge(tsdn, ctl_arena, arena);
861a4bd5210SJason Evans 	/* Merge into sum stats as well. */
862b7eaed25SJason Evans 	ctl_arena_stats_sdmerge(ctl_sdarena, ctl_arena, destroyed);
863a4bd5210SJason Evans }
864a4bd5210SJason Evans 
865b7eaed25SJason Evans static unsigned
866*8b2f5aafSJason Evans ctl_arena_init(tsd_t *tsd, extent_hooks_t *extent_hooks) {
867b7eaed25SJason Evans 	unsigned arena_ind;
868b7eaed25SJason Evans 	ctl_arena_t *ctl_arena;
869b7eaed25SJason Evans 
870b7eaed25SJason Evans 	if ((ctl_arena = ql_last(&ctl_arenas->destroyed, destroyed_link)) !=
871b7eaed25SJason Evans 	    NULL) {
872b7eaed25SJason Evans 		ql_remove(&ctl_arenas->destroyed, ctl_arena, destroyed_link);
873b7eaed25SJason Evans 		arena_ind = ctl_arena->arena_ind;
874b7eaed25SJason Evans 	} else {
875b7eaed25SJason Evans 		arena_ind = ctl_arenas->narenas;
876b7eaed25SJason Evans 	}
877b7eaed25SJason Evans 
878b7eaed25SJason Evans 	/* Trigger stats allocation. */
879*8b2f5aafSJason Evans 	if (arenas_i_impl(tsd, arena_ind, false, true) == NULL) {
880b7eaed25SJason Evans 		return UINT_MAX;
881b7eaed25SJason Evans 	}
88282872ac0SJason Evans 
883d0e79aa3SJason Evans 	/* Initialize new arena. */
884*8b2f5aafSJason Evans 	if (arena_init(tsd_tsdn(tsd), arena_ind, extent_hooks) == NULL) {
885b7eaed25SJason Evans 		return UINT_MAX;
88682872ac0SJason Evans 	}
88782872ac0SJason Evans 
888b7eaed25SJason Evans 	if (arena_ind == ctl_arenas->narenas) {
889b7eaed25SJason Evans 		ctl_arenas->narenas++;
890b7eaed25SJason Evans 	}
891b7eaed25SJason Evans 
892b7eaed25SJason Evans 	return arena_ind;
89382872ac0SJason Evans }
89482872ac0SJason Evans 
895a4bd5210SJason Evans static void
896b7eaed25SJason Evans ctl_background_thread_stats_read(tsdn_t *tsdn) {
897b7eaed25SJason Evans 	background_thread_stats_t *stats = &ctl_stats->background_thread;
898b7eaed25SJason Evans 	if (!have_background_thread ||
899b7eaed25SJason Evans 	    background_thread_stats_read(tsdn, stats)) {
900b7eaed25SJason Evans 		memset(stats, 0, sizeof(background_thread_stats_t));
901b7eaed25SJason Evans 		nstime_init(&stats->run_interval, 0);
902b7eaed25SJason Evans 	}
903b7eaed25SJason Evans }
904b7eaed25SJason Evans 
905b7eaed25SJason Evans static void
906b7eaed25SJason Evans ctl_refresh(tsdn_t *tsdn) {
907a4bd5210SJason Evans 	unsigned i;
908b7eaed25SJason Evans 	ctl_arena_t *ctl_sarena = arenas_i(MALLCTL_ARENAS_ALL);
909b7eaed25SJason Evans 	VARIABLE_ARRAY(arena_t *, tarenas, ctl_arenas->narenas);
910a4bd5210SJason Evans 
911a4bd5210SJason Evans 	/*
912a4bd5210SJason Evans 	 * Clear sum stats, since they will be merged into by
913a4bd5210SJason Evans 	 * ctl_arena_refresh().
914a4bd5210SJason Evans 	 */
915b7eaed25SJason Evans 	ctl_arena_clear(ctl_sarena);
916a4bd5210SJason Evans 
917b7eaed25SJason Evans 	for (i = 0; i < ctl_arenas->narenas; i++) {
9181f0a49e8SJason Evans 		tarenas[i] = arena_get(tsdn, i, false);
919b7eaed25SJason Evans 	}
920d0e79aa3SJason Evans 
921b7eaed25SJason Evans 	for (i = 0; i < ctl_arenas->narenas; i++) {
922b7eaed25SJason Evans 		ctl_arena_t *ctl_arena = arenas_i(i);
923a4bd5210SJason Evans 		bool initialized = (tarenas[i] != NULL);
924a4bd5210SJason Evans 
925b7eaed25SJason Evans 		ctl_arena->initialized = initialized;
926b7eaed25SJason Evans 		if (initialized) {
927b7eaed25SJason Evans 			ctl_arena_refresh(tsdn, tarenas[i], ctl_sarena, i,
928b7eaed25SJason Evans 			    false);
929b7eaed25SJason Evans 		}
930a4bd5210SJason Evans 	}
931a4bd5210SJason Evans 
932a4bd5210SJason Evans 	if (config_stats) {
933b7eaed25SJason Evans 		ctl_stats->allocated = ctl_sarena->astats->allocated_small +
934b7eaed25SJason Evans 		    atomic_load_zu(&ctl_sarena->astats->astats.allocated_large,
935b7eaed25SJason Evans 			ATOMIC_RELAXED);
936b7eaed25SJason Evans 		ctl_stats->active = (ctl_sarena->pactive << LG_PAGE);
937b7eaed25SJason Evans 		ctl_stats->metadata = atomic_load_zu(
938b7eaed25SJason Evans 		    &ctl_sarena->astats->astats.base, ATOMIC_RELAXED) +
939b7eaed25SJason Evans 		    atomic_load_zu(&ctl_sarena->astats->astats.internal,
940b7eaed25SJason Evans 			ATOMIC_RELAXED);
941b7eaed25SJason Evans 		ctl_stats->resident = atomic_load_zu(
942b7eaed25SJason Evans 		    &ctl_sarena->astats->astats.resident, ATOMIC_RELAXED);
943b7eaed25SJason Evans 		ctl_stats->mapped = atomic_load_zu(
944b7eaed25SJason Evans 		    &ctl_sarena->astats->astats.mapped, ATOMIC_RELAXED);
945b7eaed25SJason Evans 		ctl_stats->retained = atomic_load_zu(
946b7eaed25SJason Evans 		    &ctl_sarena->astats->astats.retained, ATOMIC_RELAXED);
947a4bd5210SJason Evans 
948b7eaed25SJason Evans 		ctl_background_thread_stats_read(tsdn);
949b7eaed25SJason Evans 
950b7eaed25SJason Evans #define READ_GLOBAL_MUTEX_PROF_DATA(i, mtx)				\
951b7eaed25SJason Evans     malloc_mutex_lock(tsdn, &mtx);					\
952b7eaed25SJason Evans     malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[i], &mtx);	\
953b7eaed25SJason Evans     malloc_mutex_unlock(tsdn, &mtx);
954b7eaed25SJason Evans 
955b7eaed25SJason Evans 		if (config_prof && opt_prof) {
956b7eaed25SJason Evans 			READ_GLOBAL_MUTEX_PROF_DATA(global_prof_mutex_prof,
957b7eaed25SJason Evans 			    bt2gctx_mtx);
958b7eaed25SJason Evans 		}
959b7eaed25SJason Evans 		if (have_background_thread) {
960b7eaed25SJason Evans 			READ_GLOBAL_MUTEX_PROF_DATA(
961b7eaed25SJason Evans 			    global_prof_mutex_background_thread,
962b7eaed25SJason Evans 			    background_thread_lock);
963b7eaed25SJason Evans 		} else {
964b7eaed25SJason Evans 			memset(&ctl_stats->mutex_prof_data[
965b7eaed25SJason Evans 			    global_prof_mutex_background_thread], 0,
966b7eaed25SJason Evans 			    sizeof(mutex_prof_data_t));
967b7eaed25SJason Evans 		}
968b7eaed25SJason Evans 		/* We own ctl mutex already. */
969b7eaed25SJason Evans 		malloc_mutex_prof_read(tsdn,
970b7eaed25SJason Evans 		    &ctl_stats->mutex_prof_data[global_prof_mutex_ctl],
971b7eaed25SJason Evans 		    &ctl_mtx);
972b7eaed25SJason Evans #undef READ_GLOBAL_MUTEX_PROF_DATA
973b7eaed25SJason Evans 	}
974b7eaed25SJason Evans 	ctl_arenas->epoch++;
975a4bd5210SJason Evans }
976a4bd5210SJason Evans 
977a4bd5210SJason Evans static bool
978*8b2f5aafSJason Evans ctl_init(tsd_t *tsd) {
979a4bd5210SJason Evans 	bool ret;
980*8b2f5aafSJason Evans 	tsdn_t *tsdn = tsd_tsdn(tsd);
981a4bd5210SJason Evans 
9821f0a49e8SJason Evans 	malloc_mutex_lock(tsdn, &ctl_mtx);
983d0e79aa3SJason Evans 	if (!ctl_initialized) {
984b7eaed25SJason Evans 		ctl_arena_t *ctl_sarena, *ctl_darena;
985a4bd5210SJason Evans 		unsigned i;
986b7eaed25SJason Evans 
987b7eaed25SJason Evans 		/*
988b7eaed25SJason Evans 		 * Allocate demand-zeroed space for pointers to the full
989b7eaed25SJason Evans 		 * range of supported arena indices.
990b7eaed25SJason Evans 		 */
991b7eaed25SJason Evans 		if (ctl_arenas == NULL) {
992b7eaed25SJason Evans 			ctl_arenas = (ctl_arenas_t *)base_alloc(tsdn,
993b7eaed25SJason Evans 			    b0get(), sizeof(ctl_arenas_t), QUANTUM);
994b7eaed25SJason Evans 			if (ctl_arenas == NULL) {
995a4bd5210SJason Evans 				ret = true;
996a4bd5210SJason Evans 				goto label_return;
997a4bd5210SJason Evans 			}
998a4bd5210SJason Evans 		}
999a4bd5210SJason Evans 
1000b7eaed25SJason Evans 		if (config_stats && ctl_stats == NULL) {
1001b7eaed25SJason Evans 			ctl_stats = (ctl_stats_t *)base_alloc(tsdn, b0get(),
1002b7eaed25SJason Evans 			    sizeof(ctl_stats_t), QUANTUM);
1003b7eaed25SJason Evans 			if (ctl_stats == NULL) {
1004b7eaed25SJason Evans 				ret = true;
1005b7eaed25SJason Evans 				goto label_return;
1006b7eaed25SJason Evans 			}
1007b7eaed25SJason Evans 		}
1008b7eaed25SJason Evans 
1009b7eaed25SJason Evans 		/*
1010b7eaed25SJason Evans 		 * Allocate space for the current full range of arenas
1011b7eaed25SJason Evans 		 * here rather than doing it lazily elsewhere, in order
1012b7eaed25SJason Evans 		 * to limit when OOM-caused errors can occur.
1013b7eaed25SJason Evans 		 */
1014*8b2f5aafSJason Evans 		if ((ctl_sarena = arenas_i_impl(tsd, MALLCTL_ARENAS_ALL, false,
1015b7eaed25SJason Evans 		    true)) == NULL) {
1016b7eaed25SJason Evans 			ret = true;
1017b7eaed25SJason Evans 			goto label_return;
1018b7eaed25SJason Evans 		}
1019b7eaed25SJason Evans 		ctl_sarena->initialized = true;
1020b7eaed25SJason Evans 
1021*8b2f5aafSJason Evans 		if ((ctl_darena = arenas_i_impl(tsd, MALLCTL_ARENAS_DESTROYED,
1022b7eaed25SJason Evans 		    false, true)) == NULL) {
1023b7eaed25SJason Evans 			ret = true;
1024b7eaed25SJason Evans 			goto label_return;
1025b7eaed25SJason Evans 		}
1026b7eaed25SJason Evans 		ctl_arena_clear(ctl_darena);
1027b7eaed25SJason Evans 		/*
1028b7eaed25SJason Evans 		 * Don't toggle ctl_darena to initialized until an arena is
1029b7eaed25SJason Evans 		 * actually destroyed, so that arena.<i>.initialized can be used
1030b7eaed25SJason Evans 		 * to query whether the stats are relevant.
1031b7eaed25SJason Evans 		 */
1032b7eaed25SJason Evans 
1033b7eaed25SJason Evans 		ctl_arenas->narenas = narenas_total_get();
1034b7eaed25SJason Evans 		for (i = 0; i < ctl_arenas->narenas; i++) {
1035*8b2f5aafSJason Evans 			if (arenas_i_impl(tsd, i, false, true) == NULL) {
1036b7eaed25SJason Evans 				ret = true;
1037b7eaed25SJason Evans 				goto label_return;
1038b7eaed25SJason Evans 			}
1039b7eaed25SJason Evans 		}
1040b7eaed25SJason Evans 
1041b7eaed25SJason Evans 		ql_new(&ctl_arenas->destroyed);
10421f0a49e8SJason Evans 		ctl_refresh(tsdn);
1043b7eaed25SJason Evans 
1044a4bd5210SJason Evans 		ctl_initialized = true;
1045a4bd5210SJason Evans 	}
1046a4bd5210SJason Evans 
1047a4bd5210SJason Evans 	ret = false;
1048a4bd5210SJason Evans label_return:
10491f0a49e8SJason Evans 	malloc_mutex_unlock(tsdn, &ctl_mtx);
1050b7eaed25SJason Evans 	return ret;
1051a4bd5210SJason Evans }
1052a4bd5210SJason Evans 
1053a4bd5210SJason Evans static int
10541f0a49e8SJason Evans ctl_lookup(tsdn_t *tsdn, const char *name, ctl_node_t const **nodesp,
1055b7eaed25SJason Evans     size_t *mibp, size_t *depthp) {
1056a4bd5210SJason Evans 	int ret;
1057a4bd5210SJason Evans 	const char *elm, *tdot, *dot;
1058a4bd5210SJason Evans 	size_t elen, i, j;
1059e722f8f8SJason Evans 	const ctl_named_node_t *node;
1060a4bd5210SJason Evans 
1061a4bd5210SJason Evans 	elm = name;
1062a4bd5210SJason Evans 	/* Equivalent to strchrnul(). */
1063a4bd5210SJason Evans 	dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0');
1064a4bd5210SJason Evans 	elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
1065a4bd5210SJason Evans 	if (elen == 0) {
1066a4bd5210SJason Evans 		ret = ENOENT;
1067a4bd5210SJason Evans 		goto label_return;
1068a4bd5210SJason Evans 	}
1069a4bd5210SJason Evans 	node = super_root_node;
1070a4bd5210SJason Evans 	for (i = 0; i < *depthp; i++) {
1071e722f8f8SJason Evans 		assert(node);
1072e722f8f8SJason Evans 		assert(node->nchildren > 0);
1073e722f8f8SJason Evans 		if (ctl_named_node(node->children) != NULL) {
1074e722f8f8SJason Evans 			const ctl_named_node_t *pnode = node;
1075a4bd5210SJason Evans 
1076a4bd5210SJason Evans 			/* Children are named. */
1077e722f8f8SJason Evans 			for (j = 0; j < node->nchildren; j++) {
1078e722f8f8SJason Evans 				const ctl_named_node_t *child =
1079e722f8f8SJason Evans 				    ctl_named_children(node, j);
1080e722f8f8SJason Evans 				if (strlen(child->name) == elen &&
1081e722f8f8SJason Evans 				    strncmp(elm, child->name, elen) == 0) {
1082a4bd5210SJason Evans 					node = child;
1083b7eaed25SJason Evans 					if (nodesp != NULL) {
1084e722f8f8SJason Evans 						nodesp[i] =
1085e722f8f8SJason Evans 						    (const ctl_node_t *)node;
1086b7eaed25SJason Evans 					}
1087a4bd5210SJason Evans 					mibp[i] = j;
1088a4bd5210SJason Evans 					break;
1089a4bd5210SJason Evans 				}
1090a4bd5210SJason Evans 			}
1091a4bd5210SJason Evans 			if (node == pnode) {
1092a4bd5210SJason Evans 				ret = ENOENT;
1093a4bd5210SJason Evans 				goto label_return;
1094a4bd5210SJason Evans 			}
1095a4bd5210SJason Evans 		} else {
1096a4bd5210SJason Evans 			uintmax_t index;
1097e722f8f8SJason Evans 			const ctl_indexed_node_t *inode;
1098a4bd5210SJason Evans 
1099a4bd5210SJason Evans 			/* Children are indexed. */
1100a4bd5210SJason Evans 			index = malloc_strtoumax(elm, NULL, 10);
1101a4bd5210SJason Evans 			if (index == UINTMAX_MAX || index > SIZE_T_MAX) {
1102a4bd5210SJason Evans 				ret = ENOENT;
1103a4bd5210SJason Evans 				goto label_return;
1104a4bd5210SJason Evans 			}
1105a4bd5210SJason Evans 
1106e722f8f8SJason Evans 			inode = ctl_indexed_node(node->children);
11071f0a49e8SJason Evans 			node = inode->index(tsdn, mibp, *depthp, (size_t)index);
1108a4bd5210SJason Evans 			if (node == NULL) {
1109a4bd5210SJason Evans 				ret = ENOENT;
1110a4bd5210SJason Evans 				goto label_return;
1111a4bd5210SJason Evans 			}
1112a4bd5210SJason Evans 
1113b7eaed25SJason Evans 			if (nodesp != NULL) {
1114e722f8f8SJason Evans 				nodesp[i] = (const ctl_node_t *)node;
1115b7eaed25SJason Evans 			}
1116a4bd5210SJason Evans 			mibp[i] = (size_t)index;
1117a4bd5210SJason Evans 		}
1118a4bd5210SJason Evans 
1119a4bd5210SJason Evans 		if (node->ctl != NULL) {
1120a4bd5210SJason Evans 			/* Terminal node. */
1121a4bd5210SJason Evans 			if (*dot != '\0') {
1122a4bd5210SJason Evans 				/*
1123a4bd5210SJason Evans 				 * The name contains more elements than are
1124a4bd5210SJason Evans 				 * in this path through the tree.
1125a4bd5210SJason Evans 				 */
1126a4bd5210SJason Evans 				ret = ENOENT;
1127a4bd5210SJason Evans 				goto label_return;
1128a4bd5210SJason Evans 			}
1129a4bd5210SJason Evans 			/* Complete lookup successful. */
1130a4bd5210SJason Evans 			*depthp = i + 1;
1131a4bd5210SJason Evans 			break;
1132a4bd5210SJason Evans 		}
1133a4bd5210SJason Evans 
1134a4bd5210SJason Evans 		/* Update elm. */
1135a4bd5210SJason Evans 		if (*dot == '\0') {
1136a4bd5210SJason Evans 			/* No more elements. */
1137a4bd5210SJason Evans 			ret = ENOENT;
1138a4bd5210SJason Evans 			goto label_return;
1139a4bd5210SJason Evans 		}
1140a4bd5210SJason Evans 		elm = &dot[1];
1141a4bd5210SJason Evans 		dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot :
1142a4bd5210SJason Evans 		    strchr(elm, '\0');
1143a4bd5210SJason Evans 		elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
1144a4bd5210SJason Evans 	}
1145a4bd5210SJason Evans 
1146a4bd5210SJason Evans 	ret = 0;
1147a4bd5210SJason Evans label_return:
1148b7eaed25SJason Evans 	return ret;
1149a4bd5210SJason Evans }
1150a4bd5210SJason Evans 
1151a4bd5210SJason Evans int
11521f0a49e8SJason Evans ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp,
1153b7eaed25SJason Evans     void *newp, size_t newlen) {
1154a4bd5210SJason Evans 	int ret;
1155a4bd5210SJason Evans 	size_t depth;
1156a4bd5210SJason Evans 	ctl_node_t const *nodes[CTL_MAX_DEPTH];
1157a4bd5210SJason Evans 	size_t mib[CTL_MAX_DEPTH];
1158e722f8f8SJason Evans 	const ctl_named_node_t *node;
1159a4bd5210SJason Evans 
1160*8b2f5aafSJason Evans 	if (!ctl_initialized && ctl_init(tsd)) {
1161a4bd5210SJason Evans 		ret = EAGAIN;
1162a4bd5210SJason Evans 		goto label_return;
1163a4bd5210SJason Evans 	}
1164a4bd5210SJason Evans 
1165a4bd5210SJason Evans 	depth = CTL_MAX_DEPTH;
11661f0a49e8SJason Evans 	ret = ctl_lookup(tsd_tsdn(tsd), name, nodes, mib, &depth);
1167b7eaed25SJason Evans 	if (ret != 0) {
1168a4bd5210SJason Evans 		goto label_return;
1169b7eaed25SJason Evans 	}
1170a4bd5210SJason Evans 
1171e722f8f8SJason Evans 	node = ctl_named_node(nodes[depth-1]);
1172b7eaed25SJason Evans 	if (node != NULL && node->ctl) {
11731f0a49e8SJason Evans 		ret = node->ctl(tsd, mib, depth, oldp, oldlenp, newp, newlen);
1174b7eaed25SJason Evans 	} else {
1175a4bd5210SJason Evans 		/* The name refers to a partial path through the ctl tree. */
1176a4bd5210SJason Evans 		ret = ENOENT;
1177a4bd5210SJason Evans 	}
1178a4bd5210SJason Evans 
1179a4bd5210SJason Evans label_return:
1180a4bd5210SJason Evans 	return(ret);
1181a4bd5210SJason Evans }
1182a4bd5210SJason Evans 
1183a4bd5210SJason Evans int
1184*8b2f5aafSJason Evans ctl_nametomib(tsd_t *tsd, const char *name, size_t *mibp, size_t *miblenp) {
1185a4bd5210SJason Evans 	int ret;
1186a4bd5210SJason Evans 
1187*8b2f5aafSJason Evans 	if (!ctl_initialized && ctl_init(tsd)) {
1188a4bd5210SJason Evans 		ret = EAGAIN;
1189a4bd5210SJason Evans 		goto label_return;
1190a4bd5210SJason Evans 	}
1191a4bd5210SJason Evans 
1192*8b2f5aafSJason Evans 	ret = ctl_lookup(tsd_tsdn(tsd), name, NULL, mibp, miblenp);
1193a4bd5210SJason Evans label_return:
1194a4bd5210SJason Evans 	return(ret);
1195a4bd5210SJason Evans }
1196a4bd5210SJason Evans 
1197a4bd5210SJason Evans int
11981f0a49e8SJason Evans ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1199b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1200a4bd5210SJason Evans 	int ret;
1201e722f8f8SJason Evans 	const ctl_named_node_t *node;
1202a4bd5210SJason Evans 	size_t i;
1203a4bd5210SJason Evans 
1204*8b2f5aafSJason Evans 	if (!ctl_initialized && ctl_init(tsd)) {
1205a4bd5210SJason Evans 		ret = EAGAIN;
1206a4bd5210SJason Evans 		goto label_return;
1207a4bd5210SJason Evans 	}
1208a4bd5210SJason Evans 
1209a4bd5210SJason Evans 	/* Iterate down the tree. */
1210a4bd5210SJason Evans 	node = super_root_node;
1211a4bd5210SJason Evans 	for (i = 0; i < miblen; i++) {
1212e722f8f8SJason Evans 		assert(node);
1213e722f8f8SJason Evans 		assert(node->nchildren > 0);
1214e722f8f8SJason Evans 		if (ctl_named_node(node->children) != NULL) {
1215a4bd5210SJason Evans 			/* Children are named. */
1216b7eaed25SJason Evans 			if (node->nchildren <= mib[i]) {
1217a4bd5210SJason Evans 				ret = ENOENT;
1218a4bd5210SJason Evans 				goto label_return;
1219a4bd5210SJason Evans 			}
1220e722f8f8SJason Evans 			node = ctl_named_children(node, mib[i]);
1221a4bd5210SJason Evans 		} else {
1222e722f8f8SJason Evans 			const ctl_indexed_node_t *inode;
1223a4bd5210SJason Evans 
1224a4bd5210SJason Evans 			/* Indexed element. */
1225e722f8f8SJason Evans 			inode = ctl_indexed_node(node->children);
12261f0a49e8SJason Evans 			node = inode->index(tsd_tsdn(tsd), mib, miblen, mib[i]);
1227a4bd5210SJason Evans 			if (node == NULL) {
1228a4bd5210SJason Evans 				ret = ENOENT;
1229a4bd5210SJason Evans 				goto label_return;
1230a4bd5210SJason Evans 			}
1231a4bd5210SJason Evans 		}
1232a4bd5210SJason Evans 	}
1233a4bd5210SJason Evans 
1234a4bd5210SJason Evans 	/* Call the ctl function. */
1235b7eaed25SJason Evans 	if (node && node->ctl) {
12361f0a49e8SJason Evans 		ret = node->ctl(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
1237b7eaed25SJason Evans 	} else {
1238a4bd5210SJason Evans 		/* Partial MIB. */
1239a4bd5210SJason Evans 		ret = ENOENT;
1240a4bd5210SJason Evans 	}
1241a4bd5210SJason Evans 
1242a4bd5210SJason Evans label_return:
1243a4bd5210SJason Evans 	return(ret);
1244a4bd5210SJason Evans }
1245a4bd5210SJason Evans 
1246a4bd5210SJason Evans bool
1247b7eaed25SJason Evans ctl_boot(void) {
1248b7eaed25SJason Evans 	if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL,
1249b7eaed25SJason Evans 	    malloc_mutex_rank_exclusive)) {
1250b7eaed25SJason Evans 		return true;
1251b7eaed25SJason Evans 	}
1252a4bd5210SJason Evans 
1253a4bd5210SJason Evans 	ctl_initialized = false;
1254a4bd5210SJason Evans 
1255b7eaed25SJason Evans 	return false;
1256a4bd5210SJason Evans }
1257a4bd5210SJason Evans 
125882872ac0SJason Evans void
1259b7eaed25SJason Evans ctl_prefork(tsdn_t *tsdn) {
12601f0a49e8SJason Evans 	malloc_mutex_prefork(tsdn, &ctl_mtx);
126182872ac0SJason Evans }
126282872ac0SJason Evans 
126382872ac0SJason Evans void
1264b7eaed25SJason Evans ctl_postfork_parent(tsdn_t *tsdn) {
12651f0a49e8SJason Evans 	malloc_mutex_postfork_parent(tsdn, &ctl_mtx);
126682872ac0SJason Evans }
126782872ac0SJason Evans 
126882872ac0SJason Evans void
1269b7eaed25SJason Evans ctl_postfork_child(tsdn_t *tsdn) {
12701f0a49e8SJason Evans 	malloc_mutex_postfork_child(tsdn, &ctl_mtx);
127182872ac0SJason Evans }
127282872ac0SJason Evans 
1273a4bd5210SJason Evans /******************************************************************************/
1274a4bd5210SJason Evans /* *_ctl() functions. */
1275a4bd5210SJason Evans 
1276a4bd5210SJason Evans #define READONLY()	do {						\
1277a4bd5210SJason Evans 	if (newp != NULL || newlen != 0) {				\
1278a4bd5210SJason Evans 		ret = EPERM;						\
1279a4bd5210SJason Evans 		goto label_return;					\
1280a4bd5210SJason Evans 	}								\
1281a4bd5210SJason Evans } while (0)
1282a4bd5210SJason Evans 
1283a4bd5210SJason Evans #define WRITEONLY()	do {						\
1284a4bd5210SJason Evans 	if (oldp != NULL || oldlenp != NULL) {				\
1285a4bd5210SJason Evans 		ret = EPERM;						\
1286a4bd5210SJason Evans 		goto label_return;					\
1287a4bd5210SJason Evans 	}								\
1288a4bd5210SJason Evans } while (0)
1289a4bd5210SJason Evans 
1290d0e79aa3SJason Evans #define READ_XOR_WRITE()	do {					\
1291d0e79aa3SJason Evans 	if ((oldp != NULL && oldlenp != NULL) && (newp != NULL ||	\
1292d0e79aa3SJason Evans 	    newlen != 0)) {						\
1293d0e79aa3SJason Evans 		ret = EPERM;						\
1294d0e79aa3SJason Evans 		goto label_return;					\
1295d0e79aa3SJason Evans 	}								\
1296d0e79aa3SJason Evans } while (0)
1297d0e79aa3SJason Evans 
1298a4bd5210SJason Evans #define READ(v, t)	do {						\
1299a4bd5210SJason Evans 	if (oldp != NULL && oldlenp != NULL) {				\
1300a4bd5210SJason Evans 		if (*oldlenp != sizeof(t)) {				\
1301a4bd5210SJason Evans 			size_t	copylen = (sizeof(t) <= *oldlenp)	\
1302a4bd5210SJason Evans 			    ? sizeof(t) : *oldlenp;			\
130388ad2f8dSJason Evans 			memcpy(oldp, (void *)&(v), copylen);		\
1304a4bd5210SJason Evans 			ret = EINVAL;					\
1305a4bd5210SJason Evans 			goto label_return;				\
1306d0e79aa3SJason Evans 		}							\
130788ad2f8dSJason Evans 		*(t *)oldp = (v);					\
1308a4bd5210SJason Evans 	}								\
1309a4bd5210SJason Evans } while (0)
1310a4bd5210SJason Evans 
1311a4bd5210SJason Evans #define WRITE(v, t)	do {						\
1312a4bd5210SJason Evans 	if (newp != NULL) {						\
1313a4bd5210SJason Evans 		if (newlen != sizeof(t)) {				\
1314a4bd5210SJason Evans 			ret = EINVAL;					\
1315a4bd5210SJason Evans 			goto label_return;				\
1316a4bd5210SJason Evans 		}							\
131788ad2f8dSJason Evans 		(v) = *(t *)newp;					\
1318a4bd5210SJason Evans 	}								\
1319a4bd5210SJason Evans } while (0)
1320a4bd5210SJason Evans 
1321b7eaed25SJason Evans #define MIB_UNSIGNED(v, i) do {						\
1322b7eaed25SJason Evans 	if (mib[i] > UINT_MAX) {					\
1323b7eaed25SJason Evans 		ret = EFAULT;						\
1324b7eaed25SJason Evans 		goto label_return;					\
1325b7eaed25SJason Evans 	}								\
1326b7eaed25SJason Evans 	v = (unsigned)mib[i];						\
1327b7eaed25SJason Evans } while (0)
1328b7eaed25SJason Evans 
1329a4bd5210SJason Evans /*
1330a4bd5210SJason Evans  * There's a lot of code duplication in the following macros due to limitations
1331a4bd5210SJason Evans  * in how nested cpp macros are expanded.
1332a4bd5210SJason Evans  */
1333a4bd5210SJason Evans #define CTL_RO_CLGEN(c, l, n, v, t)					\
1334a4bd5210SJason Evans static int								\
13351f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1336b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1337a4bd5210SJason Evans 	int ret;							\
1338a4bd5210SJason Evans 	t oldval;							\
1339a4bd5210SJason Evans 									\
1340b7eaed25SJason Evans 	if (!(c)) {							\
1341b7eaed25SJason Evans 		return ENOENT;						\
1342b7eaed25SJason Evans 	}								\
1343b7eaed25SJason Evans 	if (l) {							\
13441f0a49e8SJason Evans 		malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);		\
1345b7eaed25SJason Evans 	}								\
1346a4bd5210SJason Evans 	READONLY();							\
134788ad2f8dSJason Evans 	oldval = (v);							\
1348a4bd5210SJason Evans 	READ(oldval, t);						\
1349a4bd5210SJason Evans 									\
1350a4bd5210SJason Evans 	ret = 0;							\
1351a4bd5210SJason Evans label_return:								\
1352b7eaed25SJason Evans 	if (l) {							\
13531f0a49e8SJason Evans 		malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);		\
1354b7eaed25SJason Evans 	}								\
1355b7eaed25SJason Evans 	return ret;							\
1356a4bd5210SJason Evans }
1357a4bd5210SJason Evans 
1358a4bd5210SJason Evans #define CTL_RO_CGEN(c, n, v, t)						\
1359a4bd5210SJason Evans static int								\
13601f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1361b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1362a4bd5210SJason Evans 	int ret;							\
1363a4bd5210SJason Evans 	t oldval;							\
1364a4bd5210SJason Evans 									\
1365b7eaed25SJason Evans 	if (!(c)) {							\
1366b7eaed25SJason Evans 		return ENOENT;						\
1367b7eaed25SJason Evans 	}								\
13681f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);			\
1369a4bd5210SJason Evans 	READONLY();							\
137088ad2f8dSJason Evans 	oldval = (v);							\
1371a4bd5210SJason Evans 	READ(oldval, t);						\
1372a4bd5210SJason Evans 									\
1373a4bd5210SJason Evans 	ret = 0;							\
1374a4bd5210SJason Evans label_return:								\
13751f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);			\
1376b7eaed25SJason Evans 	return ret;							\
1377a4bd5210SJason Evans }
1378a4bd5210SJason Evans 
1379a4bd5210SJason Evans #define CTL_RO_GEN(n, v, t)						\
1380a4bd5210SJason Evans static int								\
13811f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1382b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1383a4bd5210SJason Evans 	int ret;							\
1384a4bd5210SJason Evans 	t oldval;							\
1385a4bd5210SJason Evans 									\
13861f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);			\
1387a4bd5210SJason Evans 	READONLY();							\
138888ad2f8dSJason Evans 	oldval = (v);							\
1389a4bd5210SJason Evans 	READ(oldval, t);						\
1390a4bd5210SJason Evans 									\
1391a4bd5210SJason Evans 	ret = 0;							\
1392a4bd5210SJason Evans label_return:								\
13931f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);			\
1394b7eaed25SJason Evans 	return ret;							\
1395a4bd5210SJason Evans }
1396a4bd5210SJason Evans 
1397a4bd5210SJason Evans /*
1398a4bd5210SJason Evans  * ctl_mtx is not acquired, under the assumption that no pertinent data will
1399a4bd5210SJason Evans  * mutate during the call.
1400a4bd5210SJason Evans  */
1401a4bd5210SJason Evans #define CTL_RO_NL_CGEN(c, n, v, t)					\
1402a4bd5210SJason Evans static int								\
14031f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1404b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1405a4bd5210SJason Evans 	int ret;							\
1406a4bd5210SJason Evans 	t oldval;							\
1407a4bd5210SJason Evans 									\
1408b7eaed25SJason Evans 	if (!(c)) {							\
1409b7eaed25SJason Evans 		return ENOENT;						\
1410b7eaed25SJason Evans 	}								\
1411a4bd5210SJason Evans 	READONLY();							\
141288ad2f8dSJason Evans 	oldval = (v);							\
1413a4bd5210SJason Evans 	READ(oldval, t);						\
1414a4bd5210SJason Evans 									\
1415a4bd5210SJason Evans 	ret = 0;							\
1416a4bd5210SJason Evans label_return:								\
1417b7eaed25SJason Evans 	return ret;							\
1418a4bd5210SJason Evans }
1419a4bd5210SJason Evans 
1420a4bd5210SJason Evans #define CTL_RO_NL_GEN(n, v, t)						\
1421a4bd5210SJason Evans static int								\
14221f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1423b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1424a4bd5210SJason Evans 	int ret;							\
1425a4bd5210SJason Evans 	t oldval;							\
1426a4bd5210SJason Evans 									\
1427a4bd5210SJason Evans 	READONLY();							\
142888ad2f8dSJason Evans 	oldval = (v);							\
1429a4bd5210SJason Evans 	READ(oldval, t);						\
1430a4bd5210SJason Evans 									\
1431a4bd5210SJason Evans 	ret = 0;							\
1432a4bd5210SJason Evans label_return:								\
1433b7eaed25SJason Evans 	return ret;							\
1434a4bd5210SJason Evans }
1435a4bd5210SJason Evans 
1436d0e79aa3SJason Evans #define CTL_TSD_RO_NL_CGEN(c, n, m, t)					\
1437d0e79aa3SJason Evans static int								\
14381f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1439b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1440d0e79aa3SJason Evans 	int ret;							\
1441d0e79aa3SJason Evans 	t oldval;							\
1442d0e79aa3SJason Evans 									\
1443b7eaed25SJason Evans 	if (!(c)) {							\
1444b7eaed25SJason Evans 		return ENOENT;						\
1445b7eaed25SJason Evans 	}								\
1446d0e79aa3SJason Evans 	READONLY();							\
1447d0e79aa3SJason Evans 	oldval = (m(tsd));						\
1448d0e79aa3SJason Evans 	READ(oldval, t);						\
1449d0e79aa3SJason Evans 									\
1450d0e79aa3SJason Evans 	ret = 0;							\
1451d0e79aa3SJason Evans label_return:								\
1452b7eaed25SJason Evans 	return ret;							\
1453d0e79aa3SJason Evans }
1454d0e79aa3SJason Evans 
1455df0d881dSJason Evans #define CTL_RO_CONFIG_GEN(n, t)						\
1456a4bd5210SJason Evans static int								\
14571f0a49e8SJason Evans n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,	\
1458b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {			\
1459a4bd5210SJason Evans 	int ret;							\
1460df0d881dSJason Evans 	t oldval;							\
1461a4bd5210SJason Evans 									\
1462a4bd5210SJason Evans 	READONLY();							\
1463a4bd5210SJason Evans 	oldval = n;							\
1464df0d881dSJason Evans 	READ(oldval, t);						\
1465a4bd5210SJason Evans 									\
1466a4bd5210SJason Evans 	ret = 0;							\
1467a4bd5210SJason Evans label_return:								\
1468b7eaed25SJason Evans 	return ret;							\
1469a4bd5210SJason Evans }
1470a4bd5210SJason Evans 
1471f921d10fSJason Evans /******************************************************************************/
1472f921d10fSJason Evans 
1473a4bd5210SJason Evans CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
1474a4bd5210SJason Evans 
1475a4bd5210SJason Evans static int
14761f0a49e8SJason Evans epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1477b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1478a4bd5210SJason Evans 	int ret;
14792b06b201SJason Evans 	UNUSED uint64_t newval;
1480a4bd5210SJason Evans 
14811f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
1482a4bd5210SJason Evans 	WRITE(newval, uint64_t);
1483b7eaed25SJason Evans 	if (newp != NULL) {
14841f0a49e8SJason Evans 		ctl_refresh(tsd_tsdn(tsd));
1485b7eaed25SJason Evans 	}
1486b7eaed25SJason Evans 	READ(ctl_arenas->epoch, uint64_t);
1487a4bd5210SJason Evans 
1488a4bd5210SJason Evans 	ret = 0;
1489a4bd5210SJason Evans label_return:
14901f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
1491b7eaed25SJason Evans 	return ret;
1492b7eaed25SJason Evans }
1493b7eaed25SJason Evans 
1494b7eaed25SJason Evans static int
1495b7eaed25SJason Evans background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
1496b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
1497b7eaed25SJason Evans 	int ret;
1498b7eaed25SJason Evans 	bool oldval;
1499b7eaed25SJason Evans 
1500b7eaed25SJason Evans 	if (!have_background_thread) {
1501b7eaed25SJason Evans 		return ENOENT;
1502b7eaed25SJason Evans 	}
1503b7eaed25SJason Evans 	background_thread_ctl_init(tsd_tsdn(tsd));
1504b7eaed25SJason Evans 
1505b7eaed25SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
1506b7eaed25SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
1507b7eaed25SJason Evans 	if (newp == NULL) {
1508b7eaed25SJason Evans 		oldval = background_thread_enabled();
1509b7eaed25SJason Evans 		READ(oldval, bool);
1510b7eaed25SJason Evans 	} else {
1511b7eaed25SJason Evans 		if (newlen != sizeof(bool)) {
1512b7eaed25SJason Evans 			ret = EINVAL;
1513b7eaed25SJason Evans 			goto label_return;
1514b7eaed25SJason Evans 		}
1515b7eaed25SJason Evans 		oldval = background_thread_enabled();
1516b7eaed25SJason Evans 		READ(oldval, bool);
1517b7eaed25SJason Evans 
1518b7eaed25SJason Evans 		bool newval = *(bool *)newp;
1519b7eaed25SJason Evans 		if (newval == oldval) {
1520b7eaed25SJason Evans 			ret = 0;
1521b7eaed25SJason Evans 			goto label_return;
1522b7eaed25SJason Evans 		}
1523b7eaed25SJason Evans 
1524b7eaed25SJason Evans 		background_thread_enabled_set(tsd_tsdn(tsd), newval);
1525b7eaed25SJason Evans 		if (newval) {
1526b7eaed25SJason Evans 			if (!can_enable_background_thread) {
1527b7eaed25SJason Evans 				malloc_printf("<jemalloc>: Error in dlsym("
1528b7eaed25SJason Evans 			            "RTLD_NEXT, \"pthread_create\"). Cannot "
1529b7eaed25SJason Evans 				    "enable background_thread\n");
1530b7eaed25SJason Evans 				ret = EFAULT;
1531b7eaed25SJason Evans 				goto label_return;
1532b7eaed25SJason Evans 			}
1533b7eaed25SJason Evans 			if (background_threads_enable(tsd)) {
1534b7eaed25SJason Evans 				ret = EFAULT;
1535b7eaed25SJason Evans 				goto label_return;
1536b7eaed25SJason Evans 			}
1537b7eaed25SJason Evans 		} else {
1538b7eaed25SJason Evans 			if (background_threads_disable(tsd)) {
1539b7eaed25SJason Evans 				ret = EFAULT;
1540b7eaed25SJason Evans 				goto label_return;
1541b7eaed25SJason Evans 			}
1542b7eaed25SJason Evans 		}
1543b7eaed25SJason Evans 	}
1544b7eaed25SJason Evans 	ret = 0;
1545b7eaed25SJason Evans label_return:
1546b7eaed25SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
1547b7eaed25SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
1548b7eaed25SJason Evans 
1549b7eaed25SJason Evans 	return ret;
1550a4bd5210SJason Evans }
1551a4bd5210SJason Evans 
1552f921d10fSJason Evans /******************************************************************************/
1553a4bd5210SJason Evans 
1554df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_cache_oblivious, bool)
1555df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_debug, bool)
1556df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_fill, bool)
1557df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_lazy_lock, bool)
1558df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_malloc_conf, const char *)
1559df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_prof, bool)
1560df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_prof_libgcc, bool)
1561df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_prof_libunwind, bool)
1562df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_stats, bool)
15638244f2aaSJason Evans CTL_RO_CONFIG_GEN(config_thp, bool)
1564df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_utrace, bool)
1565df0d881dSJason Evans CTL_RO_CONFIG_GEN(config_xmalloc, bool)
1566a4bd5210SJason Evans 
1567f921d10fSJason Evans /******************************************************************************/
1568a4bd5210SJason Evans 
1569f921d10fSJason Evans CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
1570b7eaed25SJason Evans CTL_RO_NL_GEN(opt_abort_conf, opt_abort_conf, bool)
1571b7eaed25SJason Evans CTL_RO_NL_GEN(opt_retain, opt_retain, bool)
1572f921d10fSJason Evans CTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
1573df0d881dSJason Evans CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned)
1574b7eaed25SJason Evans CTL_RO_NL_GEN(opt_percpu_arena, percpu_arena_mode_names[opt_percpu_arena],
1575b7eaed25SJason Evans     const char *)
1576b7eaed25SJason Evans CTL_RO_NL_GEN(opt_background_thread, opt_background_thread, bool)
1577b7eaed25SJason Evans CTL_RO_NL_GEN(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t)
1578b7eaed25SJason Evans CTL_RO_NL_GEN(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t)
1579f921d10fSJason Evans CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
1580b7eaed25SJason Evans CTL_RO_NL_GEN(opt_stats_print_opts, opt_stats_print_opts, const char *)
1581d0e79aa3SJason Evans CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *)
1582f921d10fSJason Evans CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
1583f921d10fSJason Evans CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
1584f921d10fSJason Evans CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
1585b7eaed25SJason Evans CTL_RO_NL_GEN(opt_tcache, opt_tcache, bool)
1586b7eaed25SJason Evans CTL_RO_NL_GEN(opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
1587f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
1588f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
1589d0e79aa3SJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool)
1590d0e79aa3SJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init,
1591d0e79aa3SJason Evans     opt_prof_thread_active_init, bool)
1592f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
1593f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
1594f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
1595f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
1596f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
1597f921d10fSJason Evans CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
1598a4bd5210SJason Evans 
1599f921d10fSJason Evans /******************************************************************************/
1600a4bd5210SJason Evans 
1601a4bd5210SJason Evans static int
16021f0a49e8SJason Evans thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1603b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1604a4bd5210SJason Evans 	int ret;
1605d0e79aa3SJason Evans 	arena_t *oldarena;
1606a4bd5210SJason Evans 	unsigned newind, oldind;
1607a4bd5210SJason Evans 
1608d0e79aa3SJason Evans 	oldarena = arena_choose(tsd, NULL);
1609b7eaed25SJason Evans 	if (oldarena == NULL) {
1610b7eaed25SJason Evans 		return EAGAIN;
1611b7eaed25SJason Evans 	}
1612b7eaed25SJason Evans 	newind = oldind = arena_ind_get(oldarena);
1613a4bd5210SJason Evans 	WRITE(newind, unsigned);
1614a4bd5210SJason Evans 	READ(oldind, unsigned);
1615b7eaed25SJason Evans 
1616a4bd5210SJason Evans 	if (newind != oldind) {
1617d0e79aa3SJason Evans 		arena_t *newarena;
1618a4bd5210SJason Evans 
1619b7eaed25SJason Evans 		if (newind >= narenas_total_get()) {
1620a4bd5210SJason Evans 			/* New arena index is out of range. */
1621a4bd5210SJason Evans 			ret = EFAULT;
1622a4bd5210SJason Evans 			goto label_return;
1623a4bd5210SJason Evans 		}
1624a4bd5210SJason Evans 
1625b7eaed25SJason Evans 		if (have_percpu_arena &&
1626b7eaed25SJason Evans 		    PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
1627b7eaed25SJason Evans 			if (newind < percpu_arena_ind_limit(opt_percpu_arena)) {
1628b7eaed25SJason Evans 				/*
1629b7eaed25SJason Evans 				 * If perCPU arena is enabled, thread_arena
1630b7eaed25SJason Evans 				 * control is not allowed for the auto arena
1631b7eaed25SJason Evans 				 * range.
1632b7eaed25SJason Evans 				 */
1633b7eaed25SJason Evans 				ret = EPERM;
1634b7eaed25SJason Evans 				goto label_return;
1635b7eaed25SJason Evans 			}
1636b7eaed25SJason Evans 		}
1637b7eaed25SJason Evans 
1638a4bd5210SJason Evans 		/* Initialize arena if necessary. */
16391f0a49e8SJason Evans 		newarena = arena_get(tsd_tsdn(tsd), newind, true);
1640d0e79aa3SJason Evans 		if (newarena == NULL) {
1641a4bd5210SJason Evans 			ret = EAGAIN;
1642a4bd5210SJason Evans 			goto label_return;
1643a4bd5210SJason Evans 		}
1644d0e79aa3SJason Evans 		/* Set new arena/tcache associations. */
1645d0e79aa3SJason Evans 		arena_migrate(tsd, oldind, newind);
1646b7eaed25SJason Evans 		if (tcache_available(tsd)) {
1647b7eaed25SJason Evans 			tcache_arena_reassociate(tsd_tsdn(tsd),
1648b7eaed25SJason Evans 			    tsd_tcachep_get(tsd), newarena);
1649a4bd5210SJason Evans 		}
1650a4bd5210SJason Evans 	}
1651a4bd5210SJason Evans 
1652a4bd5210SJason Evans 	ret = 0;
1653a4bd5210SJason Evans label_return:
1654b7eaed25SJason Evans 	return ret;
1655a4bd5210SJason Evans }
1656a4bd5210SJason Evans 
1657d0e79aa3SJason Evans CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get,
1658d0e79aa3SJason Evans     uint64_t)
1659d0e79aa3SJason Evans CTL_TSD_RO_NL_CGEN(config_stats, thread_allocatedp, tsd_thread_allocatedp_get,
1660d0e79aa3SJason Evans     uint64_t *)
1661d0e79aa3SJason Evans CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocated, tsd_thread_deallocated_get,
1662d0e79aa3SJason Evans     uint64_t)
1663d0e79aa3SJason Evans CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp,
1664d0e79aa3SJason Evans     tsd_thread_deallocatedp_get, uint64_t *)
1665a4bd5210SJason Evans 
1666f921d10fSJason Evans static int
16671f0a49e8SJason Evans thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
1668b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
1669f921d10fSJason Evans 	int ret;
1670f921d10fSJason Evans 	bool oldval;
1671a4bd5210SJason Evans 
1672b7eaed25SJason Evans 	oldval = tcache_enabled_get(tsd);
1673f921d10fSJason Evans 	if (newp != NULL) {
1674f921d10fSJason Evans 		if (newlen != sizeof(bool)) {
1675f921d10fSJason Evans 			ret = EINVAL;
1676f921d10fSJason Evans 			goto label_return;
1677f921d10fSJason Evans 		}
1678b7eaed25SJason Evans 		tcache_enabled_set(tsd, *(bool *)newp);
1679f921d10fSJason Evans 	}
1680f921d10fSJason Evans 	READ(oldval, bool);
1681a4bd5210SJason Evans 
1682f921d10fSJason Evans 	ret = 0;
1683f921d10fSJason Evans label_return:
1684b7eaed25SJason Evans 	return ret;
1685f921d10fSJason Evans }
1686f921d10fSJason Evans 
1687f921d10fSJason Evans static int
16881f0a49e8SJason Evans thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
1689b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
1690f921d10fSJason Evans 	int ret;
1691f921d10fSJason Evans 
1692b7eaed25SJason Evans 	if (!tcache_available(tsd)) {
1693b7eaed25SJason Evans 		ret = EFAULT;
1694b7eaed25SJason Evans 		goto label_return;
1695b7eaed25SJason Evans 	}
1696f921d10fSJason Evans 
1697f921d10fSJason Evans 	READONLY();
1698f921d10fSJason Evans 	WRITEONLY();
1699f921d10fSJason Evans 
1700*8b2f5aafSJason Evans 	tcache_flush(tsd);
1701f921d10fSJason Evans 
1702f921d10fSJason Evans 	ret = 0;
1703f921d10fSJason Evans label_return:
1704b7eaed25SJason Evans 	return ret;
1705f921d10fSJason Evans }
1706a4bd5210SJason Evans 
1707d0e79aa3SJason Evans static int
17081f0a49e8SJason Evans thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1709b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1710d0e79aa3SJason Evans 	int ret;
1711d0e79aa3SJason Evans 
1712b7eaed25SJason Evans 	if (!config_prof) {
1713b7eaed25SJason Evans 		return ENOENT;
1714b7eaed25SJason Evans 	}
1715d0e79aa3SJason Evans 
1716d0e79aa3SJason Evans 	READ_XOR_WRITE();
1717d0e79aa3SJason Evans 
1718d0e79aa3SJason Evans 	if (newp != NULL) {
1719d0e79aa3SJason Evans 		if (newlen != sizeof(const char *)) {
1720d0e79aa3SJason Evans 			ret = EINVAL;
1721d0e79aa3SJason Evans 			goto label_return;
1722d0e79aa3SJason Evans 		}
1723d0e79aa3SJason Evans 
1724d0e79aa3SJason Evans 		if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) !=
1725b7eaed25SJason Evans 		    0) {
1726d0e79aa3SJason Evans 			goto label_return;
1727b7eaed25SJason Evans 		}
1728d0e79aa3SJason Evans 	} else {
17291f0a49e8SJason Evans 		const char *oldname = prof_thread_name_get(tsd);
1730d0e79aa3SJason Evans 		READ(oldname, const char *);
1731d0e79aa3SJason Evans 	}
1732d0e79aa3SJason Evans 
1733d0e79aa3SJason Evans 	ret = 0;
1734d0e79aa3SJason Evans label_return:
1735b7eaed25SJason Evans 	return ret;
1736d0e79aa3SJason Evans }
1737d0e79aa3SJason Evans 
1738d0e79aa3SJason Evans static int
17391f0a49e8SJason Evans thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1740b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1741d0e79aa3SJason Evans 	int ret;
1742d0e79aa3SJason Evans 	bool oldval;
1743d0e79aa3SJason Evans 
1744b7eaed25SJason Evans 	if (!config_prof) {
1745b7eaed25SJason Evans 		return ENOENT;
1746b7eaed25SJason Evans 	}
1747d0e79aa3SJason Evans 
17481f0a49e8SJason Evans 	oldval = prof_thread_active_get(tsd);
1749d0e79aa3SJason Evans 	if (newp != NULL) {
1750d0e79aa3SJason Evans 		if (newlen != sizeof(bool)) {
1751d0e79aa3SJason Evans 			ret = EINVAL;
1752d0e79aa3SJason Evans 			goto label_return;
1753d0e79aa3SJason Evans 		}
17541f0a49e8SJason Evans 		if (prof_thread_active_set(tsd, *(bool *)newp)) {
1755d0e79aa3SJason Evans 			ret = EAGAIN;
1756d0e79aa3SJason Evans 			goto label_return;
1757d0e79aa3SJason Evans 		}
1758d0e79aa3SJason Evans 	}
1759d0e79aa3SJason Evans 	READ(oldval, bool);
1760d0e79aa3SJason Evans 
1761d0e79aa3SJason Evans 	ret = 0;
1762d0e79aa3SJason Evans label_return:
1763b7eaed25SJason Evans 	return ret;
1764d0e79aa3SJason Evans }
1765d0e79aa3SJason Evans 
1766d0e79aa3SJason Evans /******************************************************************************/
1767d0e79aa3SJason Evans 
1768d0e79aa3SJason Evans static int
17691f0a49e8SJason Evans tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1770b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1771d0e79aa3SJason Evans 	int ret;
1772d0e79aa3SJason Evans 	unsigned tcache_ind;
1773d0e79aa3SJason Evans 
1774d0e79aa3SJason Evans 	READONLY();
1775bde95144SJason Evans 	if (tcaches_create(tsd, &tcache_ind)) {
1776d0e79aa3SJason Evans 		ret = EFAULT;
1777d0e79aa3SJason Evans 		goto label_return;
1778d0e79aa3SJason Evans 	}
1779d0e79aa3SJason Evans 	READ(tcache_ind, unsigned);
1780d0e79aa3SJason Evans 
1781d0e79aa3SJason Evans 	ret = 0;
1782d0e79aa3SJason Evans label_return:
17838244f2aaSJason Evans 	return ret;
1784d0e79aa3SJason Evans }
1785d0e79aa3SJason Evans 
1786d0e79aa3SJason Evans static int
17871f0a49e8SJason Evans tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1788b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1789d0e79aa3SJason Evans 	int ret;
1790d0e79aa3SJason Evans 	unsigned tcache_ind;
1791d0e79aa3SJason Evans 
1792d0e79aa3SJason Evans 	WRITEONLY();
1793d0e79aa3SJason Evans 	tcache_ind = UINT_MAX;
1794d0e79aa3SJason Evans 	WRITE(tcache_ind, unsigned);
1795d0e79aa3SJason Evans 	if (tcache_ind == UINT_MAX) {
1796d0e79aa3SJason Evans 		ret = EFAULT;
1797d0e79aa3SJason Evans 		goto label_return;
1798d0e79aa3SJason Evans 	}
1799d0e79aa3SJason Evans 	tcaches_flush(tsd, tcache_ind);
1800d0e79aa3SJason Evans 
1801d0e79aa3SJason Evans 	ret = 0;
1802d0e79aa3SJason Evans label_return:
1803b7eaed25SJason Evans 	return ret;
1804d0e79aa3SJason Evans }
1805d0e79aa3SJason Evans 
1806d0e79aa3SJason Evans static int
18071f0a49e8SJason Evans tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1808b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1809d0e79aa3SJason Evans 	int ret;
1810d0e79aa3SJason Evans 	unsigned tcache_ind;
1811d0e79aa3SJason Evans 
1812d0e79aa3SJason Evans 	WRITEONLY();
1813d0e79aa3SJason Evans 	tcache_ind = UINT_MAX;
1814d0e79aa3SJason Evans 	WRITE(tcache_ind, unsigned);
1815d0e79aa3SJason Evans 	if (tcache_ind == UINT_MAX) {
1816d0e79aa3SJason Evans 		ret = EFAULT;
1817d0e79aa3SJason Evans 		goto label_return;
1818d0e79aa3SJason Evans 	}
1819d0e79aa3SJason Evans 	tcaches_destroy(tsd, tcache_ind);
1820d0e79aa3SJason Evans 
1821d0e79aa3SJason Evans 	ret = 0;
1822d0e79aa3SJason Evans label_return:
1823b7eaed25SJason Evans 	return ret;
1824d0e79aa3SJason Evans }
1825d0e79aa3SJason Evans 
1826a4bd5210SJason Evans /******************************************************************************/
1827a4bd5210SJason Evans 
1828b7eaed25SJason Evans static int
1829b7eaed25SJason Evans arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
1830b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
1831b7eaed25SJason Evans 	int ret;
1832b7eaed25SJason Evans 	tsdn_t *tsdn = tsd_tsdn(tsd);
1833b7eaed25SJason Evans 	unsigned arena_ind;
1834b7eaed25SJason Evans 	bool initialized;
1835b7eaed25SJason Evans 
1836b7eaed25SJason Evans 	READONLY();
1837b7eaed25SJason Evans 	MIB_UNSIGNED(arena_ind, 1);
183882872ac0SJason Evans 
18391f0a49e8SJason Evans 	malloc_mutex_lock(tsdn, &ctl_mtx);
1840b7eaed25SJason Evans 	initialized = arenas_i(arena_ind)->initialized;
1841b7eaed25SJason Evans 	malloc_mutex_unlock(tsdn, &ctl_mtx);
184282872ac0SJason Evans 
1843b7eaed25SJason Evans 	READ(initialized, bool);
1844b7eaed25SJason Evans 
1845b7eaed25SJason Evans 	ret = 0;
1846b7eaed25SJason Evans label_return:
1847b7eaed25SJason Evans 	return ret;
1848b7eaed25SJason Evans }
1849b7eaed25SJason Evans 
1850b7eaed25SJason Evans static void
1851b7eaed25SJason Evans arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) {
1852b7eaed25SJason Evans 	malloc_mutex_lock(tsdn, &ctl_mtx);
1853b7eaed25SJason Evans 	{
1854b7eaed25SJason Evans 		unsigned narenas = ctl_arenas->narenas;
1855b7eaed25SJason Evans 
1856b7eaed25SJason Evans 		/*
1857b7eaed25SJason Evans 		 * Access via index narenas is deprecated, and scheduled for
1858b7eaed25SJason Evans 		 * removal in 6.0.0.
1859b7eaed25SJason Evans 		 */
1860b7eaed25SJason Evans 		if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == narenas) {
186182872ac0SJason Evans 			unsigned i;
1862df0d881dSJason Evans 			VARIABLE_ARRAY(arena_t *, tarenas, narenas);
1863df0d881dSJason Evans 
1864b7eaed25SJason Evans 			for (i = 0; i < narenas; i++) {
18651f0a49e8SJason Evans 				tarenas[i] = arena_get(tsdn, i, false);
1866b7eaed25SJason Evans 			}
1867df0d881dSJason Evans 
1868df0d881dSJason Evans 			/*
1869df0d881dSJason Evans 			 * No further need to hold ctl_mtx, since narenas and
1870df0d881dSJason Evans 			 * tarenas contain everything needed below.
1871df0d881dSJason Evans 			 */
18721f0a49e8SJason Evans 			malloc_mutex_unlock(tsdn, &ctl_mtx);
1873df0d881dSJason Evans 
1874df0d881dSJason Evans 			for (i = 0; i < narenas; i++) {
1875b7eaed25SJason Evans 				if (tarenas[i] != NULL) {
1876b7eaed25SJason Evans 					arena_decay(tsdn, tarenas[i], false,
1877b7eaed25SJason Evans 					    all);
1878b7eaed25SJason Evans 				}
187982872ac0SJason Evans 			}
188082872ac0SJason Evans 		} else {
1881df0d881dSJason Evans 			arena_t *tarena;
1882df0d881dSJason Evans 
1883df0d881dSJason Evans 			assert(arena_ind < narenas);
1884df0d881dSJason Evans 
18851f0a49e8SJason Evans 			tarena = arena_get(tsdn, arena_ind, false);
1886df0d881dSJason Evans 
1887df0d881dSJason Evans 			/* No further need to hold ctl_mtx. */
18881f0a49e8SJason Evans 			malloc_mutex_unlock(tsdn, &ctl_mtx);
1889df0d881dSJason Evans 
1890b7eaed25SJason Evans 			if (tarena != NULL) {
1891b7eaed25SJason Evans 				arena_decay(tsdn, tarena, false, all);
1892df0d881dSJason Evans 			}
189382872ac0SJason Evans 		}
189482872ac0SJason Evans 	}
1895df0d881dSJason Evans }
1896df0d881dSJason Evans 
1897df0d881dSJason Evans static int
18981f0a49e8SJason Evans arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1899b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1900df0d881dSJason Evans 	int ret;
1901b7eaed25SJason Evans 	unsigned arena_ind;
1902df0d881dSJason Evans 
1903df0d881dSJason Evans 	READONLY();
1904df0d881dSJason Evans 	WRITEONLY();
1905b7eaed25SJason Evans 	MIB_UNSIGNED(arena_ind, 1);
1906b7eaed25SJason Evans 	arena_i_decay(tsd_tsdn(tsd), arena_ind, false);
190782872ac0SJason Evans 
190882872ac0SJason Evans 	ret = 0;
190982872ac0SJason Evans label_return:
1910b7eaed25SJason Evans 	return ret;
191182872ac0SJason Evans }
191282872ac0SJason Evans 
191382872ac0SJason Evans static int
1914b7eaed25SJason Evans arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1915b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
19161f0a49e8SJason Evans 	int ret;
19171f0a49e8SJason Evans 	unsigned arena_ind;
19181f0a49e8SJason Evans 
19191f0a49e8SJason Evans 	READONLY();
19201f0a49e8SJason Evans 	WRITEONLY();
1921b7eaed25SJason Evans 	MIB_UNSIGNED(arena_ind, 1);
1922b7eaed25SJason Evans 	arena_i_decay(tsd_tsdn(tsd), arena_ind, true);
19231f0a49e8SJason Evans 
1924b7eaed25SJason Evans 	ret = 0;
1925b7eaed25SJason Evans label_return:
1926b7eaed25SJason Evans 	return ret;
1927b7eaed25SJason Evans }
1928b7eaed25SJason Evans 
1929b7eaed25SJason Evans static int
1930b7eaed25SJason Evans arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen,
1931b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen, unsigned *arena_ind,
1932b7eaed25SJason Evans     arena_t **arena) {
1933b7eaed25SJason Evans 	int ret;
1934b7eaed25SJason Evans 
1935b7eaed25SJason Evans 	READONLY();
1936b7eaed25SJason Evans 	WRITEONLY();
1937b7eaed25SJason Evans 	MIB_UNSIGNED(*arena_ind, 1);
1938b7eaed25SJason Evans 
1939b7eaed25SJason Evans 	*arena = arena_get(tsd_tsdn(tsd), *arena_ind, false);
1940b7eaed25SJason Evans 	if (*arena == NULL || arena_is_auto(*arena)) {
19411f0a49e8SJason Evans 		ret = EFAULT;
19421f0a49e8SJason Evans 		goto label_return;
19431f0a49e8SJason Evans 	}
19441f0a49e8SJason Evans 
19451f0a49e8SJason Evans 	ret = 0;
19461f0a49e8SJason Evans label_return:
1947b7eaed25SJason Evans 	return ret;
1948b7eaed25SJason Evans }
1949b7eaed25SJason Evans 
1950b7eaed25SJason Evans static void
1951b7eaed25SJason Evans arena_reset_prepare_background_thread(tsd_t *tsd, unsigned arena_ind) {
1952b7eaed25SJason Evans 	/* Temporarily disable the background thread during arena reset. */
1953b7eaed25SJason Evans 	if (have_background_thread) {
1954b7eaed25SJason Evans 		malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
1955b7eaed25SJason Evans 		if (background_thread_enabled()) {
1956b7eaed25SJason Evans 			unsigned ind = arena_ind % ncpus;
1957b7eaed25SJason Evans 			background_thread_info_t *info =
1958b7eaed25SJason Evans 			    &background_thread_info[ind];
1959b7eaed25SJason Evans 			assert(info->state == background_thread_started);
1960b7eaed25SJason Evans 			malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
1961b7eaed25SJason Evans 			info->state = background_thread_paused;
1962b7eaed25SJason Evans 			malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
1963b7eaed25SJason Evans 		}
1964b7eaed25SJason Evans 	}
1965b7eaed25SJason Evans }
1966b7eaed25SJason Evans 
1967b7eaed25SJason Evans static void
1968b7eaed25SJason Evans arena_reset_finish_background_thread(tsd_t *tsd, unsigned arena_ind) {
1969b7eaed25SJason Evans 	if (have_background_thread) {
1970b7eaed25SJason Evans 		if (background_thread_enabled()) {
1971b7eaed25SJason Evans 			unsigned ind = arena_ind % ncpus;
1972b7eaed25SJason Evans 			background_thread_info_t *info =
1973b7eaed25SJason Evans 			    &background_thread_info[ind];
1974*8b2f5aafSJason Evans 			assert(info->state == background_thread_paused);
1975b7eaed25SJason Evans 			malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
1976b7eaed25SJason Evans 			info->state = background_thread_started;
1977b7eaed25SJason Evans 			malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
1978b7eaed25SJason Evans 		}
1979b7eaed25SJason Evans 		malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
1980b7eaed25SJason Evans 	}
1981b7eaed25SJason Evans }
1982b7eaed25SJason Evans 
1983b7eaed25SJason Evans static int
1984b7eaed25SJason Evans arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
1985b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
1986b7eaed25SJason Evans 	int ret;
1987b7eaed25SJason Evans 	unsigned arena_ind;
1988b7eaed25SJason Evans 	arena_t *arena;
1989b7eaed25SJason Evans 
1990b7eaed25SJason Evans 	ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp,
1991b7eaed25SJason Evans 	    newp, newlen, &arena_ind, &arena);
1992b7eaed25SJason Evans 	if (ret != 0) {
1993b7eaed25SJason Evans 		return ret;
1994b7eaed25SJason Evans 	}
1995b7eaed25SJason Evans 
1996b7eaed25SJason Evans 	arena_reset_prepare_background_thread(tsd, arena_ind);
1997b7eaed25SJason Evans 	arena_reset(tsd, arena);
1998b7eaed25SJason Evans 	arena_reset_finish_background_thread(tsd, arena_ind);
1999b7eaed25SJason Evans 
2000b7eaed25SJason Evans 	return ret;
2001b7eaed25SJason Evans }
2002b7eaed25SJason Evans 
2003b7eaed25SJason Evans static int
2004b7eaed25SJason Evans arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2005b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
2006b7eaed25SJason Evans 	int ret;
2007b7eaed25SJason Evans 	unsigned arena_ind;
2008b7eaed25SJason Evans 	arena_t *arena;
2009b7eaed25SJason Evans 	ctl_arena_t *ctl_darena, *ctl_arena;
2010b7eaed25SJason Evans 
2011b7eaed25SJason Evans 	ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp,
2012b7eaed25SJason Evans 	    newp, newlen, &arena_ind, &arena);
2013b7eaed25SJason Evans 	if (ret != 0) {
2014b7eaed25SJason Evans 		goto label_return;
2015b7eaed25SJason Evans 	}
2016b7eaed25SJason Evans 
2017b7eaed25SJason Evans 	if (arena_nthreads_get(arena, false) != 0 || arena_nthreads_get(arena,
2018b7eaed25SJason Evans 	    true) != 0) {
2019b7eaed25SJason Evans 		ret = EFAULT;
2020b7eaed25SJason Evans 		goto label_return;
2021b7eaed25SJason Evans 	}
2022b7eaed25SJason Evans 
2023b7eaed25SJason Evans 	arena_reset_prepare_background_thread(tsd, arena_ind);
2024b7eaed25SJason Evans 	/* Merge stats after resetting and purging arena. */
2025b7eaed25SJason Evans 	arena_reset(tsd, arena);
2026b7eaed25SJason Evans 	arena_decay(tsd_tsdn(tsd), arena, false, true);
2027b7eaed25SJason Evans 	ctl_darena = arenas_i(MALLCTL_ARENAS_DESTROYED);
2028b7eaed25SJason Evans 	ctl_darena->initialized = true;
2029b7eaed25SJason Evans 	ctl_arena_refresh(tsd_tsdn(tsd), arena, ctl_darena, arena_ind, true);
2030b7eaed25SJason Evans 	/* Destroy arena. */
2031b7eaed25SJason Evans 	arena_destroy(tsd, arena);
2032b7eaed25SJason Evans 	ctl_arena = arenas_i(arena_ind);
2033b7eaed25SJason Evans 	ctl_arena->initialized = false;
2034b7eaed25SJason Evans 	/* Record arena index for later recycling via arenas.create. */
2035b7eaed25SJason Evans 	ql_elm_new(ctl_arena, destroyed_link);
2036b7eaed25SJason Evans 	ql_tail_insert(&ctl_arenas->destroyed, ctl_arena, destroyed_link);
2037b7eaed25SJason Evans 	arena_reset_finish_background_thread(tsd, arena_ind);
2038b7eaed25SJason Evans 
2039b7eaed25SJason Evans 	assert(ret == 0);
2040b7eaed25SJason Evans label_return:
2041b7eaed25SJason Evans 	return ret;
20421f0a49e8SJason Evans }
20431f0a49e8SJason Evans 
20441f0a49e8SJason Evans static int
20451f0a49e8SJason Evans arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2046b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
2047d0e79aa3SJason Evans 	int ret;
2048d0e79aa3SJason Evans 	const char *dss = NULL;
2049b7eaed25SJason Evans 	unsigned arena_ind;
205082872ac0SJason Evans 	dss_prec_t dss_prec_old = dss_prec_limit;
205182872ac0SJason Evans 	dss_prec_t dss_prec = dss_prec_limit;
205282872ac0SJason Evans 
20531f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
205482872ac0SJason Evans 	WRITE(dss, const char *);
2055b7eaed25SJason Evans 	MIB_UNSIGNED(arena_ind, 1);
2056d0e79aa3SJason Evans 	if (dss != NULL) {
2057d0e79aa3SJason Evans 		int i;
2058d0e79aa3SJason Evans 		bool match = false;
2059d0e79aa3SJason Evans 
206082872ac0SJason Evans 		for (i = 0; i < dss_prec_limit; i++) {
206182872ac0SJason Evans 			if (strcmp(dss_prec_names[i], dss) == 0) {
206282872ac0SJason Evans 				dss_prec = i;
206382872ac0SJason Evans 				match = true;
206482872ac0SJason Evans 				break;
206582872ac0SJason Evans 			}
206682872ac0SJason Evans 		}
2067d0e79aa3SJason Evans 
2068d0e79aa3SJason Evans 		if (!match) {
206982872ac0SJason Evans 			ret = EINVAL;
207082872ac0SJason Evans 			goto label_return;
207182872ac0SJason Evans 		}
2072d0e79aa3SJason Evans 	}
207382872ac0SJason Evans 
2074b7eaed25SJason Evans 	/*
2075b7eaed25SJason Evans 	 * Access via index narenas is deprecated, and scheduled for removal in
2076b7eaed25SJason Evans 	 * 6.0.0.
2077b7eaed25SJason Evans 	 */
2078b7eaed25SJason Evans 	if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind ==
2079b7eaed25SJason Evans 	    ctl_arenas->narenas) {
2080b7eaed25SJason Evans 		if (dss_prec != dss_prec_limit &&
2081b7eaed25SJason Evans 		    extent_dss_prec_set(dss_prec)) {
2082b7eaed25SJason Evans 			ret = EFAULT;
2083b7eaed25SJason Evans 			goto label_return;
2084b7eaed25SJason Evans 		}
2085b7eaed25SJason Evans 		dss_prec_old = extent_dss_prec_get();
2086b7eaed25SJason Evans 	} else {
20871f0a49e8SJason Evans 		arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
2088d0e79aa3SJason Evans 		if (arena == NULL || (dss_prec != dss_prec_limit &&
2089b7eaed25SJason Evans 		    arena_dss_prec_set(arena, dss_prec))) {
2090d0e79aa3SJason Evans 			ret = EFAULT;
2091d0e79aa3SJason Evans 			goto label_return;
209282872ac0SJason Evans 		}
2093b7eaed25SJason Evans 		dss_prec_old = arena_dss_prec_get(arena);
2094d0e79aa3SJason Evans 	}
2095d0e79aa3SJason Evans 
209682872ac0SJason Evans 	dss = dss_prec_names[dss_prec_old];
209782872ac0SJason Evans 	READ(dss, const char *);
2098d0e79aa3SJason Evans 
2099d0e79aa3SJason Evans 	ret = 0;
2100d0e79aa3SJason Evans label_return:
21011f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
2102b7eaed25SJason Evans 	return ret;
2103d0e79aa3SJason Evans }
2104d0e79aa3SJason Evans 
2105d0e79aa3SJason Evans static int
2106b7eaed25SJason Evans arena_i_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
2107b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) {
2108d0e79aa3SJason Evans 	int ret;
2109b7eaed25SJason Evans 	unsigned arena_ind;
2110d0e79aa3SJason Evans 	arena_t *arena;
2111d0e79aa3SJason Evans 
2112b7eaed25SJason Evans 	MIB_UNSIGNED(arena_ind, 1);
21131f0a49e8SJason Evans 	arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
2114d0e79aa3SJason Evans 	if (arena == NULL) {
211582872ac0SJason Evans 		ret = EFAULT;
211682872ac0SJason Evans 		goto label_return;
211782872ac0SJason Evans 	}
211882872ac0SJason Evans 
2119d0e79aa3SJason Evans 	if (oldp != NULL && oldlenp != NULL) {
2120b7eaed25SJason Evans 		size_t oldval = dirty ? arena_dirty_decay_ms_get(arena) :
2121b7eaed25SJason Evans 		    arena_muzzy_decay_ms_get(arena);
2122d0e79aa3SJason Evans 		READ(oldval, ssize_t);
2123d0e79aa3SJason Evans 	}
2124d0e79aa3SJason Evans 	if (newp != NULL) {
2125d0e79aa3SJason Evans 		if (newlen != sizeof(ssize_t)) {
2126d0e79aa3SJason Evans 			ret = EINVAL;
2127d0e79aa3SJason Evans 			goto label_return;
2128d0e79aa3SJason Evans 		}
2129b7eaed25SJason Evans 		if (dirty ? arena_dirty_decay_ms_set(tsd_tsdn(tsd), arena,
2130b7eaed25SJason Evans 		    *(ssize_t *)newp) : arena_muzzy_decay_ms_set(tsd_tsdn(tsd),
2131b7eaed25SJason Evans 		    arena, *(ssize_t *)newp)) {
2132d0e79aa3SJason Evans 			ret = EFAULT;
2133d0e79aa3SJason Evans 			goto label_return;
2134d0e79aa3SJason Evans 		}
2135d0e79aa3SJason Evans 	}
2136d0e79aa3SJason Evans 
2137d0e79aa3SJason Evans 	ret = 0;
2138d0e79aa3SJason Evans label_return:
2139b7eaed25SJason Evans 	return ret;
2140d0e79aa3SJason Evans }
2141d0e79aa3SJason Evans 
2142d0e79aa3SJason Evans static int
2143b7eaed25SJason Evans arena_i_dirty_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2144b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
2145b7eaed25SJason Evans 	return arena_i_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
2146b7eaed25SJason Evans 	    newlen, true);
2147df0d881dSJason Evans }
2148df0d881dSJason Evans 
2149df0d881dSJason Evans static int
2150b7eaed25SJason Evans arena_i_muzzy_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2151b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
2152b7eaed25SJason Evans 	return arena_i_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
2153b7eaed25SJason Evans 	    newlen, false);
2154b7eaed25SJason Evans }
2155b7eaed25SJason Evans 
2156b7eaed25SJason Evans static int
2157b7eaed25SJason Evans arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2158b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
2159d0e79aa3SJason Evans 	int ret;
2160b7eaed25SJason Evans 	unsigned arena_ind;
2161d0e79aa3SJason Evans 	arena_t *arena;
2162d0e79aa3SJason Evans 
21631f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
2164b7eaed25SJason Evans 	MIB_UNSIGNED(arena_ind, 1);
2165d0e79aa3SJason Evans 	if (arena_ind < narenas_total_get() && (arena =
21661f0a49e8SJason Evans 	    arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) {
2167d0e79aa3SJason Evans 		if (newp != NULL) {
2168b7eaed25SJason Evans 			extent_hooks_t *old_extent_hooks;
2169b7eaed25SJason Evans 			extent_hooks_t *new_extent_hooks
2170b7eaed25SJason Evans 			    JEMALLOC_CC_SILENCE_INIT(NULL);
2171b7eaed25SJason Evans 			WRITE(new_extent_hooks, extent_hooks_t *);
2172b7eaed25SJason Evans 			old_extent_hooks = extent_hooks_set(tsd, arena,
2173b7eaed25SJason Evans 			    new_extent_hooks);
2174b7eaed25SJason Evans 			READ(old_extent_hooks, extent_hooks_t *);
2175d0e79aa3SJason Evans 		} else {
2176b7eaed25SJason Evans 			extent_hooks_t *old_extent_hooks =
2177b7eaed25SJason Evans 			    extent_hooks_get(arena);
2178b7eaed25SJason Evans 			READ(old_extent_hooks, extent_hooks_t *);
2179d0e79aa3SJason Evans 		}
2180d0e79aa3SJason Evans 	} else {
2181d0e79aa3SJason Evans 		ret = EFAULT;
2182d0e79aa3SJason Evans 		goto label_return;
2183d0e79aa3SJason Evans 	}
218482872ac0SJason Evans 	ret = 0;
218582872ac0SJason Evans label_return:
21861f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
2187b7eaed25SJason Evans 	return ret;
218882872ac0SJason Evans }
218982872ac0SJason Evans 
219082872ac0SJason Evans static const ctl_named_node_t *
2191b7eaed25SJason Evans arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) {
219282872ac0SJason Evans 	const ctl_named_node_t *ret;
219382872ac0SJason Evans 
21941f0a49e8SJason Evans 	malloc_mutex_lock(tsdn, &ctl_mtx);
2195b7eaed25SJason Evans 	switch (i) {
2196b7eaed25SJason Evans 	case MALLCTL_ARENAS_ALL:
2197b7eaed25SJason Evans 	case MALLCTL_ARENAS_DESTROYED:
2198b7eaed25SJason Evans 		break;
2199b7eaed25SJason Evans 	default:
2200b7eaed25SJason Evans 		if (i > ctl_arenas->narenas) {
220182872ac0SJason Evans 			ret = NULL;
220282872ac0SJason Evans 			goto label_return;
220382872ac0SJason Evans 		}
2204b7eaed25SJason Evans 		break;
2205b7eaed25SJason Evans 	}
220682872ac0SJason Evans 
220782872ac0SJason Evans 	ret = super_arena_i_node;
220882872ac0SJason Evans label_return:
22091f0a49e8SJason Evans 	malloc_mutex_unlock(tsdn, &ctl_mtx);
2210b7eaed25SJason Evans 	return ret;
221182872ac0SJason Evans }
221282872ac0SJason Evans 
221382872ac0SJason Evans /******************************************************************************/
221482872ac0SJason Evans 
221582872ac0SJason Evans static int
22161f0a49e8SJason Evans arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2217b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
221882872ac0SJason Evans 	int ret;
221982872ac0SJason Evans 	unsigned narenas;
222082872ac0SJason Evans 
22211f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
222282872ac0SJason Evans 	READONLY();
222382872ac0SJason Evans 	if (*oldlenp != sizeof(unsigned)) {
222482872ac0SJason Evans 		ret = EINVAL;
222582872ac0SJason Evans 		goto label_return;
222682872ac0SJason Evans 	}
2227b7eaed25SJason Evans 	narenas = ctl_arenas->narenas;
222882872ac0SJason Evans 	READ(narenas, unsigned);
222982872ac0SJason Evans 
223082872ac0SJason Evans 	ret = 0;
223182872ac0SJason Evans label_return:
22321f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
2233b7eaed25SJason Evans 	return ret;
223482872ac0SJason Evans }
2235a4bd5210SJason Evans 
2236a4bd5210SJason Evans static int
2237b7eaed25SJason Evans arenas_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
2238b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) {
2239d0e79aa3SJason Evans 	int ret;
2240d0e79aa3SJason Evans 
2241d0e79aa3SJason Evans 	if (oldp != NULL && oldlenp != NULL) {
2242b7eaed25SJason Evans 		size_t oldval = (dirty ? arena_dirty_decay_ms_default_get() :
2243b7eaed25SJason Evans 		    arena_muzzy_decay_ms_default_get());
2244d0e79aa3SJason Evans 		READ(oldval, ssize_t);
2245d0e79aa3SJason Evans 	}
2246d0e79aa3SJason Evans 	if (newp != NULL) {
2247d0e79aa3SJason Evans 		if (newlen != sizeof(ssize_t)) {
2248d0e79aa3SJason Evans 			ret = EINVAL;
2249d0e79aa3SJason Evans 			goto label_return;
2250d0e79aa3SJason Evans 		}
2251b7eaed25SJason Evans 		if (dirty ?  arena_dirty_decay_ms_default_set(*(ssize_t *)newp)
2252b7eaed25SJason Evans 		    : arena_muzzy_decay_ms_default_set(*(ssize_t *)newp)) {
2253d0e79aa3SJason Evans 			ret = EFAULT;
2254d0e79aa3SJason Evans 			goto label_return;
2255d0e79aa3SJason Evans 		}
2256d0e79aa3SJason Evans 	}
2257d0e79aa3SJason Evans 
2258d0e79aa3SJason Evans 	ret = 0;
2259d0e79aa3SJason Evans label_return:
2260b7eaed25SJason Evans 	return ret;
2261d0e79aa3SJason Evans }
2262d0e79aa3SJason Evans 
2263df0d881dSJason Evans static int
2264b7eaed25SJason Evans arenas_dirty_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2265b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
2266b7eaed25SJason Evans 	return arenas_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
2267b7eaed25SJason Evans 	    newlen, true);
2268df0d881dSJason Evans }
2269df0d881dSJason Evans 
2270b7eaed25SJason Evans static int
2271b7eaed25SJason Evans arenas_muzzy_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2272b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
2273b7eaed25SJason Evans 	return arenas_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
2274b7eaed25SJason Evans 	    newlen, false);
2275df0d881dSJason Evans }
2276df0d881dSJason Evans 
2277a4bd5210SJason Evans CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
2278a4bd5210SJason Evans CTL_RO_NL_GEN(arenas_page, PAGE, size_t)
2279b7eaed25SJason Evans CTL_RO_NL_GEN(arenas_tcache_max, tcache_maxclass, size_t)
2280a4bd5210SJason Evans CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
2281b7eaed25SJason Evans CTL_RO_NL_GEN(arenas_nhbins, nhbins, unsigned)
2282f921d10fSJason Evans CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
2283f921d10fSJason Evans CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
2284b7eaed25SJason Evans CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t)
2285f921d10fSJason Evans static const ctl_named_node_t *
2286b7eaed25SJason Evans arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) {
2287b7eaed25SJason Evans 	if (i > NBINS) {
2288b7eaed25SJason Evans 		return NULL;
2289b7eaed25SJason Evans 	}
2290b7eaed25SJason Evans 	return super_arenas_bin_i_node;
2291f921d10fSJason Evans }
2292f921d10fSJason Evans 
2293b7eaed25SJason Evans CTL_RO_NL_GEN(arenas_nlextents, NSIZES - NBINS, unsigned)
2294b7eaed25SJason Evans CTL_RO_NL_GEN(arenas_lextent_i_size, sz_index2size(NBINS+(szind_t)mib[2]),
2295df0d881dSJason Evans     size_t)
2296d0e79aa3SJason Evans static const ctl_named_node_t *
2297b7eaed25SJason Evans arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
2298b7eaed25SJason Evans     size_t i) {
2299b7eaed25SJason Evans 	if (i > NSIZES - NBINS) {
2300b7eaed25SJason Evans 		return NULL;
2301b7eaed25SJason Evans 	}
2302b7eaed25SJason Evans 	return super_arenas_lextent_i_node;
230382872ac0SJason Evans }
230482872ac0SJason Evans 
230582872ac0SJason Evans static int
2306b7eaed25SJason Evans arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2307b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
230882872ac0SJason Evans 	int ret;
2309b7eaed25SJason Evans 	extent_hooks_t *extent_hooks;
2310b7eaed25SJason Evans 	unsigned arena_ind;
231182872ac0SJason Evans 
23121f0a49e8SJason Evans 	malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
2313b7eaed25SJason Evans 
2314b7eaed25SJason Evans 	extent_hooks = (extent_hooks_t *)&extent_hooks_default;
2315b7eaed25SJason Evans 	WRITE(extent_hooks, extent_hooks_t *);
2316*8b2f5aafSJason Evans 	if ((arena_ind = ctl_arena_init(tsd, extent_hooks)) == UINT_MAX) {
231782872ac0SJason Evans 		ret = EAGAIN;
2318a4bd5210SJason Evans 		goto label_return;
2319a4bd5210SJason Evans 	}
2320b7eaed25SJason Evans 	READ(arena_ind, unsigned);
2321a4bd5210SJason Evans 
2322a4bd5210SJason Evans 	ret = 0;
2323a4bd5210SJason Evans label_return:
23241f0a49e8SJason Evans 	malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
2325b7eaed25SJason Evans 	return ret;
2326a4bd5210SJason Evans }
2327a4bd5210SJason Evans 
2328a4bd5210SJason Evans /******************************************************************************/
2329a4bd5210SJason Evans 
2330a4bd5210SJason Evans static int
23311f0a49e8SJason Evans prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2332b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
23331f0a49e8SJason Evans 	int ret;
23341f0a49e8SJason Evans 	bool oldval;
23351f0a49e8SJason Evans 
2336b7eaed25SJason Evans 	if (!config_prof) {
2337b7eaed25SJason Evans 		return ENOENT;
2338b7eaed25SJason Evans 	}
23391f0a49e8SJason Evans 
23401f0a49e8SJason Evans 	if (newp != NULL) {
23411f0a49e8SJason Evans 		if (newlen != sizeof(bool)) {
23421f0a49e8SJason Evans 			ret = EINVAL;
23431f0a49e8SJason Evans 			goto label_return;
23441f0a49e8SJason Evans 		}
23451f0a49e8SJason Evans 		oldval = prof_thread_active_init_set(tsd_tsdn(tsd),
23461f0a49e8SJason Evans 		    *(bool *)newp);
2347b7eaed25SJason Evans 	} else {
23481f0a49e8SJason Evans 		oldval = prof_thread_active_init_get(tsd_tsdn(tsd));
2349b7eaed25SJason Evans 	}
23501f0a49e8SJason Evans 	READ(oldval, bool);
23511f0a49e8SJason Evans 
23521f0a49e8SJason Evans 	ret = 0;
23531f0a49e8SJason Evans label_return:
2354b7eaed25SJason Evans 	return ret;
23551f0a49e8SJason Evans }
23561f0a49e8SJason Evans 
23571f0a49e8SJason Evans static int
23581f0a49e8SJason Evans prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2359b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
2360d0e79aa3SJason Evans 	int ret;
2361d0e79aa3SJason Evans 	bool oldval;
2362d0e79aa3SJason Evans 
2363b7eaed25SJason Evans 	if (!config_prof) {
2364b7eaed25SJason Evans 		return ENOENT;
2365b7eaed25SJason Evans 	}
2366d0e79aa3SJason Evans 
2367d0e79aa3SJason Evans 	if (newp != NULL) {
2368d0e79aa3SJason Evans 		if (newlen != sizeof(bool)) {
2369d0e79aa3SJason Evans 			ret = EINVAL;
2370d0e79aa3SJason Evans 			goto label_return;
2371d0e79aa3SJason Evans 		}
23721f0a49e8SJason Evans 		oldval = prof_active_set(tsd_tsdn(tsd), *(bool *)newp);
2373b7eaed25SJason Evans 	} else {
23741f0a49e8SJason Evans 		oldval = prof_active_get(tsd_tsdn(tsd));
2375b7eaed25SJason Evans 	}
2376d0e79aa3SJason Evans 	READ(oldval, bool);
2377d0e79aa3SJason Evans 
2378d0e79aa3SJason Evans 	ret = 0;
2379d0e79aa3SJason Evans label_return:
2380b7eaed25SJason Evans 	return ret;
2381d0e79aa3SJason Evans }
2382d0e79aa3SJason Evans 
2383d0e79aa3SJason Evans static int
23841f0a49e8SJason Evans prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2385b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
2386a4bd5210SJason Evans 	int ret;
2387a4bd5210SJason Evans 	const char *filename = NULL;
2388a4bd5210SJason Evans 
2389b7eaed25SJason Evans 	if (!config_prof) {
2390b7eaed25SJason Evans 		return ENOENT;
2391b7eaed25SJason Evans 	}
2392a4bd5210SJason Evans 
2393a4bd5210SJason Evans 	WRITEONLY();
2394a4bd5210SJason Evans 	WRITE(filename, const char *);
2395a4bd5210SJason Evans 
23961f0a49e8SJason Evans 	if (prof_mdump(tsd, filename)) {
2397a4bd5210SJason Evans 		ret = EFAULT;
2398a4bd5210SJason Evans 		goto label_return;
2399a4bd5210SJason Evans 	}
2400a4bd5210SJason Evans 
2401a4bd5210SJason Evans 	ret = 0;
2402a4bd5210SJason Evans label_return:
2403b7eaed25SJason Evans 	return ret;
2404a4bd5210SJason Evans }
2405a4bd5210SJason Evans 
2406d0e79aa3SJason Evans static int
24071f0a49e8SJason Evans prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2408b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
2409d0e79aa3SJason Evans 	int ret;
2410d0e79aa3SJason Evans 	bool oldval;
2411d0e79aa3SJason Evans 
2412b7eaed25SJason Evans 	if (!config_prof) {
2413b7eaed25SJason Evans 		return ENOENT;
2414b7eaed25SJason Evans 	}
2415d0e79aa3SJason Evans 
2416d0e79aa3SJason Evans 	if (newp != NULL) {
2417d0e79aa3SJason Evans 		if (newlen != sizeof(bool)) {
2418d0e79aa3SJason Evans 			ret = EINVAL;
2419d0e79aa3SJason Evans 			goto label_return;
2420d0e79aa3SJason Evans 		}
24211f0a49e8SJason Evans 		oldval = prof_gdump_set(tsd_tsdn(tsd), *(bool *)newp);
2422b7eaed25SJason Evans 	} else {
24231f0a49e8SJason Evans 		oldval = prof_gdump_get(tsd_tsdn(tsd));
2424b7eaed25SJason Evans 	}
2425d0e79aa3SJason Evans 	READ(oldval, bool);
2426d0e79aa3SJason Evans 
2427d0e79aa3SJason Evans 	ret = 0;
2428d0e79aa3SJason Evans label_return:
2429b7eaed25SJason Evans 	return ret;
2430d0e79aa3SJason Evans }
2431d0e79aa3SJason Evans 
2432d0e79aa3SJason Evans static int
24331f0a49e8SJason Evans prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
2434b7eaed25SJason Evans     size_t *oldlenp, void *newp, size_t newlen) {
2435d0e79aa3SJason Evans 	int ret;
2436d0e79aa3SJason Evans 	size_t lg_sample = lg_prof_sample;
2437d0e79aa3SJason Evans 
2438b7eaed25SJason Evans 	if (!config_prof) {
2439b7eaed25SJason Evans 		return ENOENT;
2440b7eaed25SJason Evans 	}
2441d0e79aa3SJason Evans 
2442d0e79aa3SJason Evans 	WRITEONLY();
2443d0e79aa3SJason Evans 	WRITE(lg_sample, size_t);
2444b7eaed25SJason Evans 	if (lg_sample >= (sizeof(uint64_t) << 3)) {
2445d0e79aa3SJason Evans 		lg_sample = (sizeof(uint64_t) << 3) - 1;
2446b7eaed25SJason Evans 	}
2447d0e79aa3SJason Evans 
2448bde95144SJason Evans 	prof_reset(tsd, lg_sample);
2449d0e79aa3SJason Evans 
2450d0e79aa3SJason Evans 	ret = 0;
2451d0e79aa3SJason Evans label_return:
2452b7eaed25SJason Evans 	return ret;
2453d0e79aa3SJason Evans }
2454d0e79aa3SJason Evans 
2455a4bd5210SJason Evans CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
2456d0e79aa3SJason Evans CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t)
2457a4bd5210SJason Evans 
2458a4bd5210SJason Evans /******************************************************************************/
2459a4bd5210SJason Evans 
2460b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats->allocated, size_t)
2461b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_active, ctl_stats->active, size_t)
2462b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats->metadata, size_t)
2463b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_resident, ctl_stats->resident, size_t)
2464b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t)
2465b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t)
2466f921d10fSJason Evans 
2467b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_background_thread_num_threads,
2468b7eaed25SJason Evans     ctl_stats->background_thread.num_threads, size_t)
2469b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_background_thread_num_runs,
2470b7eaed25SJason Evans     ctl_stats->background_thread.num_runs, uint64_t)
2471b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_background_thread_run_interval,
2472b7eaed25SJason Evans     nstime_ns(&ctl_stats->background_thread.run_interval), uint64_t)
2473b7eaed25SJason Evans 
2474b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *)
2475b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_dirty_decay_ms, arenas_i(mib[2])->dirty_decay_ms,
2476d0e79aa3SJason Evans     ssize_t)
2477b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_muzzy_decay_ms, arenas_i(mib[2])->muzzy_decay_ms,
2478df0d881dSJason Evans     ssize_t)
2479b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned)
2480b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_uptime,
2481b7eaed25SJason Evans     nstime_ns(&arenas_i(mib[2])->astats->astats.uptime), uint64_t)
2482b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t)
2483b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t)
2484b7eaed25SJason Evans CTL_RO_GEN(stats_arenas_i_pmuzzy, arenas_i(mib[2])->pmuzzy, size_t)
2485f921d10fSJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
2486b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.mapped, ATOMIC_RELAXED),
2487b7eaed25SJason Evans     size_t)
24881f0a49e8SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_retained,
2489b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.retained, ATOMIC_RELAXED),
2490b7eaed25SJason Evans     size_t)
2491b7eaed25SJason Evans 
2492b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_npurge,
2493b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_dirty.npurge),
2494b7eaed25SJason Evans     uint64_t)
2495b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_nmadvise,
2496b7eaed25SJason Evans     arena_stats_read_u64(
2497b7eaed25SJason Evans     &arenas_i(mib[2])->astats->astats.decay_dirty.nmadvise), uint64_t)
2498b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_purged,
2499b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_dirty.purged),
2500b7eaed25SJason Evans     uint64_t)
2501b7eaed25SJason Evans 
2502b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_npurge,
2503b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_muzzy.npurge),
2504b7eaed25SJason Evans     uint64_t)
2505b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_nmadvise,
2506b7eaed25SJason Evans     arena_stats_read_u64(
2507b7eaed25SJason Evans     &arenas_i(mib[2])->astats->astats.decay_muzzy.nmadvise), uint64_t)
2508b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_purged,
2509b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_muzzy.purged),
2510b7eaed25SJason Evans     uint64_t)
2511b7eaed25SJason Evans 
2512b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_base,
2513b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.base, ATOMIC_RELAXED),
2514b7eaed25SJason Evans     size_t)
2515b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_internal,
2516b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.internal, ATOMIC_RELAXED),
2517b7eaed25SJason Evans     size_t)
2518b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_tcache_bytes,
2519b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.tcache_bytes,
2520b7eaed25SJason Evans     ATOMIC_RELAXED), size_t)
2521b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_resident,
2522b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.resident, ATOMIC_RELAXED),
2523b7eaed25SJason Evans     size_t)
2524f921d10fSJason Evans 
2525a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
2526b7eaed25SJason Evans     arenas_i(mib[2])->astats->allocated_small, size_t)
2527a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
2528b7eaed25SJason Evans     arenas_i(mib[2])->astats->nmalloc_small, uint64_t)
2529a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
2530b7eaed25SJason Evans     arenas_i(mib[2])->astats->ndalloc_small, uint64_t)
2531a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
2532b7eaed25SJason Evans     arenas_i(mib[2])->astats->nrequests_small, uint64_t)
2533a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
2534b7eaed25SJason Evans     atomic_load_zu(&arenas_i(mib[2])->astats->astats.allocated_large,
2535b7eaed25SJason Evans     ATOMIC_RELAXED), size_t)
2536a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
2537b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large),
2538b7eaed25SJason Evans     uint64_t)
2539a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
2540b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.ndalloc_large),
2541b7eaed25SJason Evans     uint64_t)
2542a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
2543b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large),
2544b7eaed25SJason Evans     uint64_t) /* Intentional. */
2545b7eaed25SJason Evans 
2546b7eaed25SJason Evans /* Lock profiling related APIs below. */
2547b7eaed25SJason Evans #define RO_MUTEX_CTL_GEN(n, l)						\
2548b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_num_ops,				\
2549b7eaed25SJason Evans     l.n_lock_ops, uint64_t)						\
2550b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_num_wait,				\
2551b7eaed25SJason Evans     l.n_wait_times, uint64_t)						\
2552b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_num_spin_acq,			\
2553b7eaed25SJason Evans     l.n_spin_acquired, uint64_t)					\
2554b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_num_owner_switch,			\
2555b7eaed25SJason Evans     l.n_owner_switches, uint64_t) 					\
2556b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_total_wait_time,			\
2557b7eaed25SJason Evans     nstime_ns(&l.tot_wait_time), uint64_t)				\
2558b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_max_wait_time,			\
2559b7eaed25SJason Evans     nstime_ns(&l.max_wait_time), uint64_t)				\
2560b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds,			\
2561b7eaed25SJason Evans     l.max_n_thds, uint32_t)
2562b7eaed25SJason Evans 
2563b7eaed25SJason Evans /* Global mutexes. */
2564b7eaed25SJason Evans #define OP(mtx)								\
2565b7eaed25SJason Evans     RO_MUTEX_CTL_GEN(mutexes_##mtx,					\
2566b7eaed25SJason Evans         ctl_stats->mutex_prof_data[global_prof_mutex_##mtx])
2567b7eaed25SJason Evans MUTEX_PROF_GLOBAL_MUTEXES
2568b7eaed25SJason Evans #undef OP
2569b7eaed25SJason Evans 
2570b7eaed25SJason Evans /* Per arena mutexes */
2571b7eaed25SJason Evans #define OP(mtx) RO_MUTEX_CTL_GEN(arenas_i_mutexes_##mtx,		\
2572b7eaed25SJason Evans     arenas_i(mib[2])->astats->astats.mutex_prof_data[arena_prof_mutex_##mtx])
2573b7eaed25SJason Evans MUTEX_PROF_ARENA_MUTEXES
2574b7eaed25SJason Evans #undef OP
2575b7eaed25SJason Evans 
2576b7eaed25SJason Evans /* tcache bin mutex */
2577b7eaed25SJason Evans RO_MUTEX_CTL_GEN(arenas_i_bins_j_mutex,
2578b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].mutex_data)
2579b7eaed25SJason Evans #undef RO_MUTEX_CTL_GEN
2580b7eaed25SJason Evans 
2581b7eaed25SJason Evans /* Resets all mutex stats, including global, arena and bin mutexes. */
2582b7eaed25SJason Evans static int
2583b7eaed25SJason Evans stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
2584b7eaed25SJason Evans     void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
2585b7eaed25SJason Evans 	if (!config_stats) {
2586b7eaed25SJason Evans 		return ENOENT;
2587b7eaed25SJason Evans 	}
2588b7eaed25SJason Evans 
2589b7eaed25SJason Evans 	tsdn_t *tsdn = tsd_tsdn(tsd);
2590b7eaed25SJason Evans 
2591b7eaed25SJason Evans #define MUTEX_PROF_RESET(mtx)						\
2592b7eaed25SJason Evans     malloc_mutex_lock(tsdn, &mtx);					\
2593b7eaed25SJason Evans     malloc_mutex_prof_data_reset(tsdn, &mtx);				\
2594b7eaed25SJason Evans     malloc_mutex_unlock(tsdn, &mtx);
2595b7eaed25SJason Evans 
2596b7eaed25SJason Evans 	/* Global mutexes: ctl and prof. */
2597b7eaed25SJason Evans 	MUTEX_PROF_RESET(ctl_mtx);
2598b7eaed25SJason Evans 	if (have_background_thread) {
2599b7eaed25SJason Evans 		MUTEX_PROF_RESET(background_thread_lock);
2600b7eaed25SJason Evans 	}
2601b7eaed25SJason Evans 	if (config_prof && opt_prof) {
2602b7eaed25SJason Evans 		MUTEX_PROF_RESET(bt2gctx_mtx);
2603b7eaed25SJason Evans 	}
2604b7eaed25SJason Evans 
2605b7eaed25SJason Evans 
2606b7eaed25SJason Evans 	/* Per arena mutexes. */
2607b7eaed25SJason Evans 	unsigned n = narenas_total_get();
2608b7eaed25SJason Evans 
2609b7eaed25SJason Evans 	for (unsigned i = 0; i < n; i++) {
2610b7eaed25SJason Evans 		arena_t *arena = arena_get(tsdn, i, false);
2611b7eaed25SJason Evans 		if (!arena) {
2612b7eaed25SJason Evans 			continue;
2613b7eaed25SJason Evans 		}
2614b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->large_mtx);
2615b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->extent_avail_mtx);
2616b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->extents_dirty.mtx);
2617b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->extents_muzzy.mtx);
2618b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->extents_retained.mtx);
2619b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->decay_dirty.mtx);
2620b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->decay_muzzy.mtx);
2621b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->tcache_ql_mtx);
2622b7eaed25SJason Evans 		MUTEX_PROF_RESET(arena->base->mtx);
2623b7eaed25SJason Evans 
2624b7eaed25SJason Evans 		for (szind_t i = 0; i < NBINS; i++) {
2625b7eaed25SJason Evans 			arena_bin_t *bin = &arena->bins[i];
2626b7eaed25SJason Evans 			MUTEX_PROF_RESET(bin->lock);
2627b7eaed25SJason Evans 		}
2628b7eaed25SJason Evans 	}
2629b7eaed25SJason Evans #undef MUTEX_PROF_RESET
2630b7eaed25SJason Evans 	return 0;
2631b7eaed25SJason Evans }
2632a4bd5210SJason Evans 
2633a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
2634b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t)
2635a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
2636b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].ndalloc, uint64_t)
2637a4bd5210SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
2638b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].nrequests, uint64_t)
2639d0e79aa3SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs,
2640b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].curregs, size_t)
2641b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nfills,
2642b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].nfills, uint64_t)
2643b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nflushes,
2644b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].nflushes, uint64_t)
2645b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs,
2646b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].nslabs, uint64_t)
2647b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs,
2648b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].reslabs, uint64_t)
2649b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs,
2650b7eaed25SJason Evans     arenas_i(mib[2])->astats->bstats[mib[4]].curslabs, size_t)
2651a4bd5210SJason Evans 
265282872ac0SJason Evans static const ctl_named_node_t *
26531f0a49e8SJason Evans stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
2654b7eaed25SJason Evans     size_t j) {
2655b7eaed25SJason Evans 	if (j > NBINS) {
2656b7eaed25SJason Evans 		return NULL;
2657b7eaed25SJason Evans 	}
2658b7eaed25SJason Evans 	return super_stats_arenas_i_bins_j_node;
2659a4bd5210SJason Evans }
2660a4bd5210SJason Evans 
2661b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc,
2662b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc),
2663d0e79aa3SJason Evans     uint64_t)
2664b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc,
2665b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc),
2666b7eaed25SJason Evans     uint64_t)
2667b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests,
2668b7eaed25SJason Evans     arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].nrequests),
2669b7eaed25SJason Evans     uint64_t)
2670b7eaed25SJason Evans CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents,
2671b7eaed25SJason Evans     arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t)
2672d0e79aa3SJason Evans 
2673d0e79aa3SJason Evans static const ctl_named_node_t *
2674b7eaed25SJason Evans stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
2675b7eaed25SJason Evans     size_t j) {
2676b7eaed25SJason Evans 	if (j > NSIZES - NBINS) {
2677b7eaed25SJason Evans 		return NULL;
2678b7eaed25SJason Evans 	}
2679b7eaed25SJason Evans 	return super_stats_arenas_i_lextents_j_node;
2680d0e79aa3SJason Evans }
2681d0e79aa3SJason Evans 
268282872ac0SJason Evans static const ctl_named_node_t *
2683b7eaed25SJason Evans stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) {
2684e722f8f8SJason Evans 	const ctl_named_node_t *ret;
2685b7eaed25SJason Evans 	size_t a;
2686a4bd5210SJason Evans 
26871f0a49e8SJason Evans 	malloc_mutex_lock(tsdn, &ctl_mtx);
2688b7eaed25SJason Evans 	a = arenas_i2a_impl(i, true, true);
2689b7eaed25SJason Evans 	if (a == UINT_MAX || !ctl_arenas->arenas[a]->initialized) {
2690a4bd5210SJason Evans 		ret = NULL;
2691a4bd5210SJason Evans 		goto label_return;
2692a4bd5210SJason Evans 	}
2693a4bd5210SJason Evans 
2694a4bd5210SJason Evans 	ret = super_stats_arenas_i_node;
2695a4bd5210SJason Evans label_return:
26961f0a49e8SJason Evans 	malloc_mutex_unlock(tsdn, &ctl_mtx);
2697b7eaed25SJason Evans 	return ret;
2698a4bd5210SJason Evans }
2699