ctl.c revision 261071
1234370Sjasone#define	JEMALLOC_CTL_C_
2234370Sjasone#include "jemalloc/internal/jemalloc_internal.h"
3234370Sjasone
4234370Sjasone/******************************************************************************/
5234370Sjasone/* Data. */
6234370Sjasone
7234370Sjasone/*
8234370Sjasone * ctl_mtx protects the following:
9234370Sjasone * - ctl_stats.*
10234370Sjasone * - opt_prof_active
11234370Sjasone */
12234370Sjasonestatic malloc_mutex_t	ctl_mtx;
13234370Sjasonestatic bool		ctl_initialized;
14234370Sjasonestatic uint64_t		ctl_epoch;
15234370Sjasonestatic ctl_stats_t	ctl_stats;
16234370Sjasone
17234370Sjasone/******************************************************************************/
18235238Sjasone/* Helpers for named and indexed nodes. */
19235238Sjasone
20235238Sjasonestatic inline const ctl_named_node_t *
21235238Sjasonectl_named_node(const ctl_node_t *node)
22235238Sjasone{
23235238Sjasone
24235238Sjasone	return ((node->named) ? (const ctl_named_node_t *)node : NULL);
25235238Sjasone}
26235238Sjasone
27235238Sjasonestatic inline const ctl_named_node_t *
28235238Sjasonectl_named_children(const ctl_named_node_t *node, int index)
29235238Sjasone{
30235238Sjasone	const ctl_named_node_t *children = ctl_named_node(node->children);
31235238Sjasone
32235238Sjasone	return (children ? &children[index] : NULL);
33235238Sjasone}
34235238Sjasone
35235238Sjasonestatic inline const ctl_indexed_node_t *
36235238Sjasonectl_indexed_node(const ctl_node_t *node)
37235238Sjasone{
38235238Sjasone
39235238Sjasone	return ((node->named == false) ? (const ctl_indexed_node_t *)node :
40235238Sjasone	    NULL);
41235238Sjasone}
42235238Sjasone
43235238Sjasone/******************************************************************************/
44234370Sjasone/* Function prototypes for non-inline static functions. */
45234370Sjasone
46234370Sjasone#define	CTL_PROTO(n)							\
47234370Sjasonestatic int	n##_ctl(const size_t *mib, size_t miblen, void *oldp,	\
48234370Sjasone    size_t *oldlenp, void *newp, size_t newlen);
49234370Sjasone
50234370Sjasone#define	INDEX_PROTO(n)							\
51242844Sjasonestatic const ctl_named_node_t	*n##_index(const size_t *mib,		\
52242844Sjasone    size_t miblen, size_t i);
53234370Sjasone
54234370Sjasonestatic bool	ctl_arena_init(ctl_arena_stats_t *astats);
55234370Sjasonestatic void	ctl_arena_clear(ctl_arena_stats_t *astats);
56234370Sjasonestatic void	ctl_arena_stats_amerge(ctl_arena_stats_t *cstats,
57234370Sjasone    arena_t *arena);
58234370Sjasonestatic void	ctl_arena_stats_smerge(ctl_arena_stats_t *sstats,
59234370Sjasone    ctl_arena_stats_t *astats);
60234370Sjasonestatic void	ctl_arena_refresh(arena_t *arena, unsigned i);
61242844Sjasonestatic bool	ctl_grow(void);
62234370Sjasonestatic void	ctl_refresh(void);
63234370Sjasonestatic bool	ctl_init(void);
64234370Sjasonestatic int	ctl_lookup(const char *name, ctl_node_t const **nodesp,
65234370Sjasone    size_t *mibp, size_t *depthp);
66234370Sjasone
67234370SjasoneCTL_PROTO(version)
68234370SjasoneCTL_PROTO(epoch)
69234370SjasoneCTL_PROTO(thread_tcache_enabled)
70234370SjasoneCTL_PROTO(thread_tcache_flush)
71234370SjasoneCTL_PROTO(thread_arena)
72234370SjasoneCTL_PROTO(thread_allocated)
73234370SjasoneCTL_PROTO(thread_allocatedp)
74234370SjasoneCTL_PROTO(thread_deallocated)
75234370SjasoneCTL_PROTO(thread_deallocatedp)
76234370SjasoneCTL_PROTO(config_debug)
77234370SjasoneCTL_PROTO(config_dss)
78234370SjasoneCTL_PROTO(config_fill)
79234370SjasoneCTL_PROTO(config_lazy_lock)
80235238SjasoneCTL_PROTO(config_mremap)
81234370SjasoneCTL_PROTO(config_munmap)
82234370SjasoneCTL_PROTO(config_prof)
83234370SjasoneCTL_PROTO(config_prof_libgcc)
84234370SjasoneCTL_PROTO(config_prof_libunwind)
85234370SjasoneCTL_PROTO(config_stats)
86234370SjasoneCTL_PROTO(config_tcache)
87234370SjasoneCTL_PROTO(config_tls)
88234370SjasoneCTL_PROTO(config_utrace)
89234370SjasoneCTL_PROTO(config_valgrind)
90234370SjasoneCTL_PROTO(config_xmalloc)
91234370SjasoneCTL_PROTO(opt_abort)
92242844SjasoneCTL_PROTO(opt_dss)
93234370SjasoneCTL_PROTO(opt_lg_chunk)
94234370SjasoneCTL_PROTO(opt_narenas)
95234370SjasoneCTL_PROTO(opt_lg_dirty_mult)
96234370SjasoneCTL_PROTO(opt_stats_print)
97234370SjasoneCTL_PROTO(opt_junk)
98234370SjasoneCTL_PROTO(opt_zero)
99234370SjasoneCTL_PROTO(opt_quarantine)
100234370SjasoneCTL_PROTO(opt_redzone)
101234370SjasoneCTL_PROTO(opt_utrace)
102234370SjasoneCTL_PROTO(opt_valgrind)
103234370SjasoneCTL_PROTO(opt_xmalloc)
104234370SjasoneCTL_PROTO(opt_tcache)
105234370SjasoneCTL_PROTO(opt_lg_tcache_max)
106234370SjasoneCTL_PROTO(opt_prof)
107234370SjasoneCTL_PROTO(opt_prof_prefix)
108234370SjasoneCTL_PROTO(opt_prof_active)
109234370SjasoneCTL_PROTO(opt_lg_prof_sample)
110234370SjasoneCTL_PROTO(opt_lg_prof_interval)
111234370SjasoneCTL_PROTO(opt_prof_gdump)
112234543SjasoneCTL_PROTO(opt_prof_final)
113234370SjasoneCTL_PROTO(opt_prof_leak)
114234370SjasoneCTL_PROTO(opt_prof_accum)
115242844SjasoneCTL_PROTO(arena_i_purge)
116242844Sjasonestatic void	arena_purge(unsigned arena_ind);
117242844SjasoneCTL_PROTO(arena_i_dss)
118242844SjasoneINDEX_PROTO(arena_i)
119234370SjasoneCTL_PROTO(arenas_bin_i_size)
120234370SjasoneCTL_PROTO(arenas_bin_i_nregs)
121234370SjasoneCTL_PROTO(arenas_bin_i_run_size)
122234370SjasoneINDEX_PROTO(arenas_bin_i)
123234370SjasoneCTL_PROTO(arenas_lrun_i_size)
124234370SjasoneINDEX_PROTO(arenas_lrun_i)
125234370SjasoneCTL_PROTO(arenas_narenas)
126234370SjasoneCTL_PROTO(arenas_initialized)
127234370SjasoneCTL_PROTO(arenas_quantum)
128234370SjasoneCTL_PROTO(arenas_page)
129234370SjasoneCTL_PROTO(arenas_tcache_max)
130234370SjasoneCTL_PROTO(arenas_nbins)
131234370SjasoneCTL_PROTO(arenas_nhbins)
132234370SjasoneCTL_PROTO(arenas_nlruns)
133234370SjasoneCTL_PROTO(arenas_purge)
134242844SjasoneCTL_PROTO(arenas_extend)
135234370SjasoneCTL_PROTO(prof_active)
136234370SjasoneCTL_PROTO(prof_dump)
137234370SjasoneCTL_PROTO(prof_interval)
138234370SjasoneCTL_PROTO(stats_chunks_current)
139234370SjasoneCTL_PROTO(stats_chunks_total)
140234370SjasoneCTL_PROTO(stats_chunks_high)
141234370SjasoneCTL_PROTO(stats_huge_allocated)
142234370SjasoneCTL_PROTO(stats_huge_nmalloc)
143234370SjasoneCTL_PROTO(stats_huge_ndalloc)
144234370SjasoneCTL_PROTO(stats_arenas_i_small_allocated)
145234370SjasoneCTL_PROTO(stats_arenas_i_small_nmalloc)
146234370SjasoneCTL_PROTO(stats_arenas_i_small_ndalloc)
147234370SjasoneCTL_PROTO(stats_arenas_i_small_nrequests)
148234370SjasoneCTL_PROTO(stats_arenas_i_large_allocated)
149234370SjasoneCTL_PROTO(stats_arenas_i_large_nmalloc)
150234370SjasoneCTL_PROTO(stats_arenas_i_large_ndalloc)
151234370SjasoneCTL_PROTO(stats_arenas_i_large_nrequests)
152234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_allocated)
153234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nmalloc)
154234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_ndalloc)
155234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nrequests)
156234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nfills)
157234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nflushes)
158234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nruns)
159234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nreruns)
160234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_curruns)
161234370SjasoneINDEX_PROTO(stats_arenas_i_bins_j)
162234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_nmalloc)
163234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_ndalloc)
164234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_nrequests)
165234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_curruns)
166234370SjasoneINDEX_PROTO(stats_arenas_i_lruns_j)
167234370SjasoneCTL_PROTO(stats_arenas_i_nthreads)
168242844SjasoneCTL_PROTO(stats_arenas_i_dss)
169234370SjasoneCTL_PROTO(stats_arenas_i_pactive)
170234370SjasoneCTL_PROTO(stats_arenas_i_pdirty)
171234370SjasoneCTL_PROTO(stats_arenas_i_mapped)
172234370SjasoneCTL_PROTO(stats_arenas_i_npurge)
173234370SjasoneCTL_PROTO(stats_arenas_i_nmadvise)
174234370SjasoneCTL_PROTO(stats_arenas_i_purged)
175234370SjasoneINDEX_PROTO(stats_arenas_i)
176234370SjasoneCTL_PROTO(stats_cactive)
177234370SjasoneCTL_PROTO(stats_allocated)
178234370SjasoneCTL_PROTO(stats_active)
179234370SjasoneCTL_PROTO(stats_mapped)
180234370Sjasone
181234370Sjasone/******************************************************************************/
182234370Sjasone/* mallctl tree. */
183234370Sjasone
184234370Sjasone/* Maximum tree depth. */
185234370Sjasone#define	CTL_MAX_DEPTH	6
186234370Sjasone
187235238Sjasone#define	NAME(n)	{true},	n
188235238Sjasone#define	CHILD(t, c)							\
189235238Sjasone	sizeof(c##_node) / sizeof(ctl_##t##_node_t),			\
190235238Sjasone	(ctl_node_t *)c##_node,						\
191235238Sjasone	NULL
192235238Sjasone#define	CTL(c)	0, NULL, c##_ctl
193234370Sjasone
194234370Sjasone/*
195234370Sjasone * Only handles internal indexed nodes, since there are currently no external
196234370Sjasone * ones.
197234370Sjasone */
198235238Sjasone#define	INDEX(i)	{false},	i##_index
199234370Sjasone
200235238Sjasonestatic const ctl_named_node_t	tcache_node[] = {
201234370Sjasone	{NAME("enabled"),	CTL(thread_tcache_enabled)},
202234370Sjasone	{NAME("flush"),		CTL(thread_tcache_flush)}
203234370Sjasone};
204234370Sjasone
205235238Sjasonestatic const ctl_named_node_t	thread_node[] = {
206234370Sjasone	{NAME("arena"),		CTL(thread_arena)},
207234370Sjasone	{NAME("allocated"),	CTL(thread_allocated)},
208234370Sjasone	{NAME("allocatedp"),	CTL(thread_allocatedp)},
209234370Sjasone	{NAME("deallocated"),	CTL(thread_deallocated)},
210234370Sjasone	{NAME("deallocatedp"),	CTL(thread_deallocatedp)},
211235238Sjasone	{NAME("tcache"),	CHILD(named, tcache)}
212234370Sjasone};
213234370Sjasone
214235238Sjasonestatic const ctl_named_node_t	config_node[] = {
215234370Sjasone	{NAME("debug"),			CTL(config_debug)},
216234370Sjasone	{NAME("dss"),			CTL(config_dss)},
217234370Sjasone	{NAME("fill"),			CTL(config_fill)},
218234370Sjasone	{NAME("lazy_lock"),		CTL(config_lazy_lock)},
219235238Sjasone	{NAME("mremap"),		CTL(config_mremap)},
220234370Sjasone	{NAME("munmap"),		CTL(config_munmap)},
221234370Sjasone	{NAME("prof"),			CTL(config_prof)},
222234370Sjasone	{NAME("prof_libgcc"),		CTL(config_prof_libgcc)},
223234370Sjasone	{NAME("prof_libunwind"),	CTL(config_prof_libunwind)},
224234370Sjasone	{NAME("stats"),			CTL(config_stats)},
225234370Sjasone	{NAME("tcache"),		CTL(config_tcache)},
226234370Sjasone	{NAME("tls"),			CTL(config_tls)},
227234370Sjasone	{NAME("utrace"),		CTL(config_utrace)},
228234370Sjasone	{NAME("valgrind"),		CTL(config_valgrind)},
229234370Sjasone	{NAME("xmalloc"),		CTL(config_xmalloc)}
230234370Sjasone};
231234370Sjasone
232235238Sjasonestatic const ctl_named_node_t opt_node[] = {
233234370Sjasone	{NAME("abort"),			CTL(opt_abort)},
234242844Sjasone	{NAME("dss"),			CTL(opt_dss)},
235234370Sjasone	{NAME("lg_chunk"),		CTL(opt_lg_chunk)},
236234370Sjasone	{NAME("narenas"),		CTL(opt_narenas)},
237234370Sjasone	{NAME("lg_dirty_mult"),		CTL(opt_lg_dirty_mult)},
238234370Sjasone	{NAME("stats_print"),		CTL(opt_stats_print)},
239234370Sjasone	{NAME("junk"),			CTL(opt_junk)},
240234370Sjasone	{NAME("zero"),			CTL(opt_zero)},
241234370Sjasone	{NAME("quarantine"),		CTL(opt_quarantine)},
242234370Sjasone	{NAME("redzone"),		CTL(opt_redzone)},
243234370Sjasone	{NAME("utrace"),		CTL(opt_utrace)},
244234370Sjasone	{NAME("valgrind"),		CTL(opt_valgrind)},
245234370Sjasone	{NAME("xmalloc"),		CTL(opt_xmalloc)},
246234370Sjasone	{NAME("tcache"),		CTL(opt_tcache)},
247234370Sjasone	{NAME("lg_tcache_max"),		CTL(opt_lg_tcache_max)},
248234370Sjasone	{NAME("prof"),			CTL(opt_prof)},
249234370Sjasone	{NAME("prof_prefix"),		CTL(opt_prof_prefix)},
250234370Sjasone	{NAME("prof_active"),		CTL(opt_prof_active)},
251234370Sjasone	{NAME("lg_prof_sample"),	CTL(opt_lg_prof_sample)},
252234370Sjasone	{NAME("lg_prof_interval"),	CTL(opt_lg_prof_interval)},
253234370Sjasone	{NAME("prof_gdump"),		CTL(opt_prof_gdump)},
254234543Sjasone	{NAME("prof_final"),		CTL(opt_prof_final)},
255234370Sjasone	{NAME("prof_leak"),		CTL(opt_prof_leak)},
256234370Sjasone	{NAME("prof_accum"),		CTL(opt_prof_accum)}
257234370Sjasone};
258234370Sjasone
259242844Sjasonestatic const ctl_named_node_t arena_i_node[] = {
260242844Sjasone	{NAME("purge"),			CTL(arena_i_purge)},
261242844Sjasone	{NAME("dss"),			CTL(arena_i_dss)}
262242844Sjasone};
263242844Sjasonestatic const ctl_named_node_t super_arena_i_node[] = {
264242844Sjasone	{NAME(""),			CHILD(named, arena_i)}
265242844Sjasone};
266242844Sjasone
267242844Sjasonestatic const ctl_indexed_node_t arena_node[] = {
268242844Sjasone	{INDEX(arena_i)}
269242844Sjasone};
270242844Sjasone
271235238Sjasonestatic const ctl_named_node_t arenas_bin_i_node[] = {
272234370Sjasone	{NAME("size"),			CTL(arenas_bin_i_size)},
273234370Sjasone	{NAME("nregs"),			CTL(arenas_bin_i_nregs)},
274234370Sjasone	{NAME("run_size"),		CTL(arenas_bin_i_run_size)}
275234370Sjasone};
276235238Sjasonestatic const ctl_named_node_t super_arenas_bin_i_node[] = {
277235238Sjasone	{NAME(""),			CHILD(named, arenas_bin_i)}
278234370Sjasone};
279234370Sjasone
280235238Sjasonestatic const ctl_indexed_node_t arenas_bin_node[] = {
281234370Sjasone	{INDEX(arenas_bin_i)}
282234370Sjasone};
283234370Sjasone
284235238Sjasonestatic const ctl_named_node_t arenas_lrun_i_node[] = {
285234370Sjasone	{NAME("size"),			CTL(arenas_lrun_i_size)}
286234370Sjasone};
287235238Sjasonestatic const ctl_named_node_t super_arenas_lrun_i_node[] = {
288235238Sjasone	{NAME(""),			CHILD(named, arenas_lrun_i)}
289234370Sjasone};
290234370Sjasone
291235238Sjasonestatic const ctl_indexed_node_t arenas_lrun_node[] = {
292234370Sjasone	{INDEX(arenas_lrun_i)}
293234370Sjasone};
294234370Sjasone
295235238Sjasonestatic const ctl_named_node_t arenas_node[] = {
296234370Sjasone	{NAME("narenas"),		CTL(arenas_narenas)},
297234370Sjasone	{NAME("initialized"),		CTL(arenas_initialized)},
298234370Sjasone	{NAME("quantum"),		CTL(arenas_quantum)},
299234370Sjasone	{NAME("page"),			CTL(arenas_page)},
300234370Sjasone	{NAME("tcache_max"),		CTL(arenas_tcache_max)},
301234370Sjasone	{NAME("nbins"),			CTL(arenas_nbins)},
302234370Sjasone	{NAME("nhbins"),		CTL(arenas_nhbins)},
303235238Sjasone	{NAME("bin"),			CHILD(indexed, arenas_bin)},
304234370Sjasone	{NAME("nlruns"),		CTL(arenas_nlruns)},
305235238Sjasone	{NAME("lrun"),			CHILD(indexed, arenas_lrun)},
306242844Sjasone	{NAME("purge"),			CTL(arenas_purge)},
307242844Sjasone	{NAME("extend"),		CTL(arenas_extend)}
308234370Sjasone};
309234370Sjasone
310235238Sjasonestatic const ctl_named_node_t	prof_node[] = {
311234370Sjasone	{NAME("active"),	CTL(prof_active)},
312234370Sjasone	{NAME("dump"),		CTL(prof_dump)},
313234370Sjasone	{NAME("interval"),	CTL(prof_interval)}
314234370Sjasone};
315234370Sjasone
316235238Sjasonestatic const ctl_named_node_t stats_chunks_node[] = {
317234370Sjasone	{NAME("current"),		CTL(stats_chunks_current)},
318234370Sjasone	{NAME("total"),			CTL(stats_chunks_total)},
319234370Sjasone	{NAME("high"),			CTL(stats_chunks_high)}
320234370Sjasone};
321234370Sjasone
322235238Sjasonestatic const ctl_named_node_t stats_huge_node[] = {
323234370Sjasone	{NAME("allocated"),		CTL(stats_huge_allocated)},
324234370Sjasone	{NAME("nmalloc"),		CTL(stats_huge_nmalloc)},
325234370Sjasone	{NAME("ndalloc"),		CTL(stats_huge_ndalloc)}
326234370Sjasone};
327234370Sjasone
328235238Sjasonestatic const ctl_named_node_t stats_arenas_i_small_node[] = {
329234370Sjasone	{NAME("allocated"),		CTL(stats_arenas_i_small_allocated)},
330234370Sjasone	{NAME("nmalloc"),		CTL(stats_arenas_i_small_nmalloc)},
331234370Sjasone	{NAME("ndalloc"),		CTL(stats_arenas_i_small_ndalloc)},
332234370Sjasone	{NAME("nrequests"),		CTL(stats_arenas_i_small_nrequests)}
333234370Sjasone};
334234370Sjasone
335235238Sjasonestatic const ctl_named_node_t stats_arenas_i_large_node[] = {
336234370Sjasone	{NAME("allocated"),		CTL(stats_arenas_i_large_allocated)},
337234370Sjasone	{NAME("nmalloc"),		CTL(stats_arenas_i_large_nmalloc)},
338234370Sjasone	{NAME("ndalloc"),		CTL(stats_arenas_i_large_ndalloc)},
339234370Sjasone	{NAME("nrequests"),		CTL(stats_arenas_i_large_nrequests)}
340234370Sjasone};
341234370Sjasone
342235238Sjasonestatic const ctl_named_node_t stats_arenas_i_bins_j_node[] = {
343234370Sjasone	{NAME("allocated"),		CTL(stats_arenas_i_bins_j_allocated)},
344234370Sjasone	{NAME("nmalloc"),		CTL(stats_arenas_i_bins_j_nmalloc)},
345234370Sjasone	{NAME("ndalloc"),		CTL(stats_arenas_i_bins_j_ndalloc)},
346234370Sjasone	{NAME("nrequests"),		CTL(stats_arenas_i_bins_j_nrequests)},
347234370Sjasone	{NAME("nfills"),		CTL(stats_arenas_i_bins_j_nfills)},
348234370Sjasone	{NAME("nflushes"),		CTL(stats_arenas_i_bins_j_nflushes)},
349234370Sjasone	{NAME("nruns"),			CTL(stats_arenas_i_bins_j_nruns)},
350234370Sjasone	{NAME("nreruns"),		CTL(stats_arenas_i_bins_j_nreruns)},
351234370Sjasone	{NAME("curruns"),		CTL(stats_arenas_i_bins_j_curruns)}
352234370Sjasone};
353235238Sjasonestatic const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = {
354235238Sjasone	{NAME(""),			CHILD(named, stats_arenas_i_bins_j)}
355234370Sjasone};
356234370Sjasone
357235238Sjasonestatic const ctl_indexed_node_t stats_arenas_i_bins_node[] = {
358234370Sjasone	{INDEX(stats_arenas_i_bins_j)}
359234370Sjasone};
360234370Sjasone
361235238Sjasonestatic const ctl_named_node_t stats_arenas_i_lruns_j_node[] = {
362234370Sjasone	{NAME("nmalloc"),		CTL(stats_arenas_i_lruns_j_nmalloc)},
363234370Sjasone	{NAME("ndalloc"),		CTL(stats_arenas_i_lruns_j_ndalloc)},
364234370Sjasone	{NAME("nrequests"),		CTL(stats_arenas_i_lruns_j_nrequests)},
365234370Sjasone	{NAME("curruns"),		CTL(stats_arenas_i_lruns_j_curruns)}
366234370Sjasone};
367235238Sjasonestatic const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = {
368235238Sjasone	{NAME(""),			CHILD(named, stats_arenas_i_lruns_j)}
369234370Sjasone};
370234370Sjasone
371235238Sjasonestatic const ctl_indexed_node_t stats_arenas_i_lruns_node[] = {
372234370Sjasone	{INDEX(stats_arenas_i_lruns_j)}
373234370Sjasone};
374234370Sjasone
375235238Sjasonestatic const ctl_named_node_t stats_arenas_i_node[] = {
376234370Sjasone	{NAME("nthreads"),		CTL(stats_arenas_i_nthreads)},
377242844Sjasone	{NAME("dss"),			CTL(stats_arenas_i_dss)},
378234370Sjasone	{NAME("pactive"),		CTL(stats_arenas_i_pactive)},
379234370Sjasone	{NAME("pdirty"),		CTL(stats_arenas_i_pdirty)},
380234370Sjasone	{NAME("mapped"),		CTL(stats_arenas_i_mapped)},
381234370Sjasone	{NAME("npurge"),		CTL(stats_arenas_i_npurge)},
382234370Sjasone	{NAME("nmadvise"),		CTL(stats_arenas_i_nmadvise)},
383234370Sjasone	{NAME("purged"),		CTL(stats_arenas_i_purged)},
384235238Sjasone	{NAME("small"),			CHILD(named, stats_arenas_i_small)},
385235238Sjasone	{NAME("large"),			CHILD(named, stats_arenas_i_large)},
386235238Sjasone	{NAME("bins"),			CHILD(indexed, stats_arenas_i_bins)},
387235238Sjasone	{NAME("lruns"),			CHILD(indexed, stats_arenas_i_lruns)}
388234370Sjasone};
389235238Sjasonestatic const ctl_named_node_t super_stats_arenas_i_node[] = {
390235238Sjasone	{NAME(""),			CHILD(named, stats_arenas_i)}
391234370Sjasone};
392234370Sjasone
393235238Sjasonestatic const ctl_indexed_node_t stats_arenas_node[] = {
394234370Sjasone	{INDEX(stats_arenas_i)}
395234370Sjasone};
396234370Sjasone
397235238Sjasonestatic const ctl_named_node_t stats_node[] = {
398234370Sjasone	{NAME("cactive"),		CTL(stats_cactive)},
399234370Sjasone	{NAME("allocated"),		CTL(stats_allocated)},
400234370Sjasone	{NAME("active"),		CTL(stats_active)},
401234370Sjasone	{NAME("mapped"),		CTL(stats_mapped)},
402235238Sjasone	{NAME("chunks"),		CHILD(named, stats_chunks)},
403235238Sjasone	{NAME("huge"),			CHILD(named, stats_huge)},
404235238Sjasone	{NAME("arenas"),		CHILD(indexed, stats_arenas)}
405234370Sjasone};
406234370Sjasone
407235238Sjasonestatic const ctl_named_node_t	root_node[] = {
408234370Sjasone	{NAME("version"),	CTL(version)},
409234370Sjasone	{NAME("epoch"),		CTL(epoch)},
410235238Sjasone	{NAME("thread"),	CHILD(named, thread)},
411235238Sjasone	{NAME("config"),	CHILD(named, config)},
412235238Sjasone	{NAME("opt"),		CHILD(named, opt)},
413242844Sjasone	{NAME("arena"),		CHILD(indexed, arena)},
414235238Sjasone	{NAME("arenas"),	CHILD(named, arenas)},
415235238Sjasone	{NAME("prof"),		CHILD(named, prof)},
416235238Sjasone	{NAME("stats"),		CHILD(named, stats)}
417234370Sjasone};
418235238Sjasonestatic const ctl_named_node_t super_root_node[] = {
419235238Sjasone	{NAME(""),		CHILD(named, root)}
420234370Sjasone};
421234370Sjasone
422234370Sjasone#undef NAME
423234370Sjasone#undef CHILD
424234370Sjasone#undef CTL
425234370Sjasone#undef INDEX
426234370Sjasone
427234370Sjasone/******************************************************************************/
428234370Sjasone
429234370Sjasonestatic bool
430234370Sjasonectl_arena_init(ctl_arena_stats_t *astats)
431234370Sjasone{
432234370Sjasone
433234370Sjasone	if (astats->lstats == NULL) {
434234370Sjasone		astats->lstats = (malloc_large_stats_t *)base_alloc(nlclasses *
435234370Sjasone		    sizeof(malloc_large_stats_t));
436234370Sjasone		if (astats->lstats == NULL)
437234370Sjasone			return (true);
438234370Sjasone	}
439234370Sjasone
440234370Sjasone	return (false);
441234370Sjasone}
442234370Sjasone
443234370Sjasonestatic void
444234370Sjasonectl_arena_clear(ctl_arena_stats_t *astats)
445234370Sjasone{
446234370Sjasone
447242844Sjasone	astats->dss = dss_prec_names[dss_prec_limit];
448234370Sjasone	astats->pactive = 0;
449234370Sjasone	astats->pdirty = 0;
450234370Sjasone	if (config_stats) {
451234370Sjasone		memset(&astats->astats, 0, sizeof(arena_stats_t));
452234370Sjasone		astats->allocated_small = 0;
453234370Sjasone		astats->nmalloc_small = 0;
454234370Sjasone		astats->ndalloc_small = 0;
455234370Sjasone		astats->nrequests_small = 0;
456234370Sjasone		memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t));
457234370Sjasone		memset(astats->lstats, 0, nlclasses *
458234370Sjasone		    sizeof(malloc_large_stats_t));
459234370Sjasone	}
460234370Sjasone}
461234370Sjasone
462234370Sjasonestatic void
463234370Sjasonectl_arena_stats_amerge(ctl_arena_stats_t *cstats, arena_t *arena)
464234370Sjasone{
465234370Sjasone	unsigned i;
466234370Sjasone
467242844Sjasone	arena_stats_merge(arena, &cstats->dss, &cstats->pactive,
468242844Sjasone	    &cstats->pdirty, &cstats->astats, cstats->bstats, cstats->lstats);
469234370Sjasone
470234370Sjasone	for (i = 0; i < NBINS; i++) {
471234370Sjasone		cstats->allocated_small += cstats->bstats[i].allocated;
472234370Sjasone		cstats->nmalloc_small += cstats->bstats[i].nmalloc;
473234370Sjasone		cstats->ndalloc_small += cstats->bstats[i].ndalloc;
474234370Sjasone		cstats->nrequests_small += cstats->bstats[i].nrequests;
475234370Sjasone	}
476234370Sjasone}
477234370Sjasone
478234370Sjasonestatic void
479234370Sjasonectl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats)
480234370Sjasone{
481234370Sjasone	unsigned i;
482234370Sjasone
483234370Sjasone	sstats->pactive += astats->pactive;
484234370Sjasone	sstats->pdirty += astats->pdirty;
485234370Sjasone
486234370Sjasone	sstats->astats.mapped += astats->astats.mapped;
487234370Sjasone	sstats->astats.npurge += astats->astats.npurge;
488234370Sjasone	sstats->astats.nmadvise += astats->astats.nmadvise;
489234370Sjasone	sstats->astats.purged += astats->astats.purged;
490234370Sjasone
491234370Sjasone	sstats->allocated_small += astats->allocated_small;
492234370Sjasone	sstats->nmalloc_small += astats->nmalloc_small;
493234370Sjasone	sstats->ndalloc_small += astats->ndalloc_small;
494234370Sjasone	sstats->nrequests_small += astats->nrequests_small;
495234370Sjasone
496234370Sjasone	sstats->astats.allocated_large += astats->astats.allocated_large;
497234370Sjasone	sstats->astats.nmalloc_large += astats->astats.nmalloc_large;
498234370Sjasone	sstats->astats.ndalloc_large += astats->astats.ndalloc_large;
499234370Sjasone	sstats->astats.nrequests_large += astats->astats.nrequests_large;
500234370Sjasone
501234370Sjasone	for (i = 0; i < nlclasses; i++) {
502234370Sjasone		sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc;
503234370Sjasone		sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc;
504234370Sjasone		sstats->lstats[i].nrequests += astats->lstats[i].nrequests;
505234370Sjasone		sstats->lstats[i].curruns += astats->lstats[i].curruns;
506234370Sjasone	}
507234370Sjasone
508234370Sjasone	for (i = 0; i < NBINS; i++) {
509234370Sjasone		sstats->bstats[i].allocated += astats->bstats[i].allocated;
510234370Sjasone		sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc;
511234370Sjasone		sstats->bstats[i].ndalloc += astats->bstats[i].ndalloc;
512234370Sjasone		sstats->bstats[i].nrequests += astats->bstats[i].nrequests;
513234370Sjasone		if (config_tcache) {
514234370Sjasone			sstats->bstats[i].nfills += astats->bstats[i].nfills;
515234370Sjasone			sstats->bstats[i].nflushes +=
516234370Sjasone			    astats->bstats[i].nflushes;
517234370Sjasone		}
518234370Sjasone		sstats->bstats[i].nruns += astats->bstats[i].nruns;
519234370Sjasone		sstats->bstats[i].reruns += astats->bstats[i].reruns;
520234370Sjasone		sstats->bstats[i].curruns += astats->bstats[i].curruns;
521234370Sjasone	}
522234370Sjasone}
523234370Sjasone
524234370Sjasonestatic void
525234370Sjasonectl_arena_refresh(arena_t *arena, unsigned i)
526234370Sjasone{
527234370Sjasone	ctl_arena_stats_t *astats = &ctl_stats.arenas[i];
528242844Sjasone	ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas];
529234370Sjasone
530234370Sjasone	ctl_arena_clear(astats);
531234370Sjasone
532234370Sjasone	sstats->nthreads += astats->nthreads;
533234370Sjasone	if (config_stats) {
534234370Sjasone		ctl_arena_stats_amerge(astats, arena);
535234370Sjasone		/* Merge into sum stats as well. */
536234370Sjasone		ctl_arena_stats_smerge(sstats, astats);
537234370Sjasone	} else {
538234370Sjasone		astats->pactive += arena->nactive;
539234370Sjasone		astats->pdirty += arena->ndirty;
540234370Sjasone		/* Merge into sum stats as well. */
541234370Sjasone		sstats->pactive += arena->nactive;
542234370Sjasone		sstats->pdirty += arena->ndirty;
543234370Sjasone	}
544234370Sjasone}
545234370Sjasone
546242844Sjasonestatic bool
547242844Sjasonectl_grow(void)
548242844Sjasone{
549242844Sjasone	ctl_arena_stats_t *astats;
550242844Sjasone	arena_t **tarenas;
551242844Sjasone
552256823Sjasone	/* Allocate extended arena stats and arenas arrays. */
553256823Sjasone	astats = (ctl_arena_stats_t *)imalloc((ctl_stats.narenas + 2) *
554256823Sjasone	    sizeof(ctl_arena_stats_t));
555256823Sjasone	if (astats == NULL)
556256823Sjasone		return (true);
557256823Sjasone	tarenas = (arena_t **)imalloc((ctl_stats.narenas + 1) *
558256823Sjasone	    sizeof(arena_t *));
559256823Sjasone	if (tarenas == NULL) {
560256823Sjasone		idalloc(astats);
561256823Sjasone		return (true);
562256823Sjasone	}
563242844Sjasone
564256823Sjasone	/* Initialize the new astats element. */
565256823Sjasone	memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) *
566256823Sjasone	    sizeof(ctl_arena_stats_t));
567242844Sjasone	memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t));
568256823Sjasone	if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) {
569256823Sjasone		idalloc(tarenas);
570256823Sjasone		idalloc(astats);
571242844Sjasone		return (true);
572256823Sjasone	}
573242844Sjasone	/* Swap merged stats to their new location. */
574242844Sjasone	{
575242844Sjasone		ctl_arena_stats_t tstats;
576242844Sjasone		memcpy(&tstats, &astats[ctl_stats.narenas],
577242844Sjasone		    sizeof(ctl_arena_stats_t));
578242844Sjasone		memcpy(&astats[ctl_stats.narenas],
579242844Sjasone		    &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t));
580242844Sjasone		memcpy(&astats[ctl_stats.narenas + 1], &tstats,
581242844Sjasone		    sizeof(ctl_arena_stats_t));
582242844Sjasone	}
583256823Sjasone	/* Initialize the new arenas element. */
584256823Sjasone	tarenas[ctl_stats.narenas] = NULL;
585256823Sjasone	{
586256823Sjasone		arena_t **arenas_old = arenas;
587256823Sjasone		/*
588256823Sjasone		 * Swap extended arenas array into place.  Although ctl_mtx
589256823Sjasone		 * protects this function from other threads extending the
590256823Sjasone		 * array, it does not protect from other threads mutating it
591256823Sjasone		 * (i.e. initializing arenas and setting array elements to
592256823Sjasone		 * point to them).  Therefore, array copying must happen under
593256823Sjasone		 * the protection of arenas_lock.
594256823Sjasone		 */
595256823Sjasone		malloc_mutex_lock(&arenas_lock);
596256823Sjasone		arenas = tarenas;
597256823Sjasone		memcpy(arenas, arenas_old, ctl_stats.narenas *
598256823Sjasone		    sizeof(arena_t *));
599256823Sjasone		narenas_total++;
600256823Sjasone		arenas_extend(narenas_total - 1);
601256823Sjasone		malloc_mutex_unlock(&arenas_lock);
602256823Sjasone		/*
603256823Sjasone		 * Deallocate arenas_old only if it came from imalloc() (not
604256823Sjasone		 * base_alloc()).
605256823Sjasone		 */
606256823Sjasone		if (ctl_stats.narenas != narenas_auto)
607256823Sjasone			idalloc(arenas_old);
608256823Sjasone	}
609242844Sjasone	ctl_stats.arenas = astats;
610242844Sjasone	ctl_stats.narenas++;
611242844Sjasone
612242844Sjasone	return (false);
613242844Sjasone}
614242844Sjasone
615234370Sjasonestatic void
616234370Sjasonectl_refresh(void)
617234370Sjasone{
618234370Sjasone	unsigned i;
619242844Sjasone	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
620234370Sjasone
621234370Sjasone	if (config_stats) {
622234370Sjasone		malloc_mutex_lock(&chunks_mtx);
623234370Sjasone		ctl_stats.chunks.current = stats_chunks.curchunks;
624234370Sjasone		ctl_stats.chunks.total = stats_chunks.nchunks;
625234370Sjasone		ctl_stats.chunks.high = stats_chunks.highchunks;
626234370Sjasone		malloc_mutex_unlock(&chunks_mtx);
627234370Sjasone
628234370Sjasone		malloc_mutex_lock(&huge_mtx);
629234370Sjasone		ctl_stats.huge.allocated = huge_allocated;
630234370Sjasone		ctl_stats.huge.nmalloc = huge_nmalloc;
631234370Sjasone		ctl_stats.huge.ndalloc = huge_ndalloc;
632234370Sjasone		malloc_mutex_unlock(&huge_mtx);
633234370Sjasone	}
634234370Sjasone
635234370Sjasone	/*
636234370Sjasone	 * Clear sum stats, since they will be merged into by
637234370Sjasone	 * ctl_arena_refresh().
638234370Sjasone	 */
639242844Sjasone	ctl_stats.arenas[ctl_stats.narenas].nthreads = 0;
640242844Sjasone	ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]);
641234370Sjasone
642234370Sjasone	malloc_mutex_lock(&arenas_lock);
643242844Sjasone	memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
644242844Sjasone	for (i = 0; i < ctl_stats.narenas; i++) {
645234370Sjasone		if (arenas[i] != NULL)
646234370Sjasone			ctl_stats.arenas[i].nthreads = arenas[i]->nthreads;
647234370Sjasone		else
648234370Sjasone			ctl_stats.arenas[i].nthreads = 0;
649234370Sjasone	}
650234370Sjasone	malloc_mutex_unlock(&arenas_lock);
651242844Sjasone	for (i = 0; i < ctl_stats.narenas; i++) {
652234370Sjasone		bool initialized = (tarenas[i] != NULL);
653234370Sjasone
654234370Sjasone		ctl_stats.arenas[i].initialized = initialized;
655234370Sjasone		if (initialized)
656234370Sjasone			ctl_arena_refresh(tarenas[i], i);
657234370Sjasone	}
658234370Sjasone
659234370Sjasone	if (config_stats) {
660242844Sjasone		ctl_stats.allocated =
661242844Sjasone		    ctl_stats.arenas[ctl_stats.narenas].allocated_small
662242844Sjasone		    + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large
663234370Sjasone		    + ctl_stats.huge.allocated;
664242844Sjasone		ctl_stats.active =
665242844Sjasone		    (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE)
666242844Sjasone		    + ctl_stats.huge.allocated;
667234370Sjasone		ctl_stats.mapped = (ctl_stats.chunks.current << opt_lg_chunk);
668234370Sjasone	}
669234370Sjasone
670234370Sjasone	ctl_epoch++;
671234370Sjasone}
672234370Sjasone
673234370Sjasonestatic bool
674234370Sjasonectl_init(void)
675234370Sjasone{
676234370Sjasone	bool ret;
677234370Sjasone
678234370Sjasone	malloc_mutex_lock(&ctl_mtx);
679234370Sjasone	if (ctl_initialized == false) {
680234370Sjasone		/*
681234370Sjasone		 * Allocate space for one extra arena stats element, which
682234370Sjasone		 * contains summed stats across all arenas.
683234370Sjasone		 */
684242844Sjasone		assert(narenas_auto == narenas_total_get());
685242844Sjasone		ctl_stats.narenas = narenas_auto;
686234370Sjasone		ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
687242844Sjasone		    (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t));
688234370Sjasone		if (ctl_stats.arenas == NULL) {
689234370Sjasone			ret = true;
690234370Sjasone			goto label_return;
691234370Sjasone		}
692242844Sjasone		memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) *
693234370Sjasone		    sizeof(ctl_arena_stats_t));
694234370Sjasone
695234370Sjasone		/*
696234370Sjasone		 * Initialize all stats structures, regardless of whether they
697234370Sjasone		 * ever get used.  Lazy initialization would allow errors to
698234370Sjasone		 * cause inconsistent state to be viewable by the application.
699234370Sjasone		 */
700234370Sjasone		if (config_stats) {
701234370Sjasone			unsigned i;
702242844Sjasone			for (i = 0; i <= ctl_stats.narenas; i++) {
703234370Sjasone				if (ctl_arena_init(&ctl_stats.arenas[i])) {
704234370Sjasone					ret = true;
705234370Sjasone					goto label_return;
706234370Sjasone				}
707234370Sjasone			}
708234370Sjasone		}
709242844Sjasone		ctl_stats.arenas[ctl_stats.narenas].initialized = true;
710234370Sjasone
711234370Sjasone		ctl_epoch = 0;
712234370Sjasone		ctl_refresh();
713234370Sjasone		ctl_initialized = true;
714234370Sjasone	}
715234370Sjasone
716234370Sjasone	ret = false;
717234370Sjasonelabel_return:
718234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
719234370Sjasone	return (ret);
720234370Sjasone}
721234370Sjasone
722234370Sjasonestatic int
723234370Sjasonectl_lookup(const char *name, ctl_node_t const **nodesp, size_t *mibp,
724234370Sjasone    size_t *depthp)
725234370Sjasone{
726234370Sjasone	int ret;
727234370Sjasone	const char *elm, *tdot, *dot;
728234370Sjasone	size_t elen, i, j;
729235238Sjasone	const ctl_named_node_t *node;
730234370Sjasone
731234370Sjasone	elm = name;
732234370Sjasone	/* Equivalent to strchrnul(). */
733234370Sjasone	dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0');
734234370Sjasone	elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
735234370Sjasone	if (elen == 0) {
736234370Sjasone		ret = ENOENT;
737234370Sjasone		goto label_return;
738234370Sjasone	}
739234370Sjasone	node = super_root_node;
740234370Sjasone	for (i = 0; i < *depthp; i++) {
741235238Sjasone		assert(node);
742235238Sjasone		assert(node->nchildren > 0);
743235238Sjasone		if (ctl_named_node(node->children) != NULL) {
744235238Sjasone			const ctl_named_node_t *pnode = node;
745234370Sjasone
746234370Sjasone			/* Children are named. */
747235238Sjasone			for (j = 0; j < node->nchildren; j++) {
748235238Sjasone				const ctl_named_node_t *child =
749235238Sjasone				    ctl_named_children(node, j);
750235238Sjasone				if (strlen(child->name) == elen &&
751235238Sjasone				    strncmp(elm, child->name, elen) == 0) {
752234370Sjasone					node = child;
753234370Sjasone					if (nodesp != NULL)
754235238Sjasone						nodesp[i] =
755235238Sjasone						    (const ctl_node_t *)node;
756234370Sjasone					mibp[i] = j;
757234370Sjasone					break;
758234370Sjasone				}
759234370Sjasone			}
760234370Sjasone			if (node == pnode) {
761234370Sjasone				ret = ENOENT;
762234370Sjasone				goto label_return;
763234370Sjasone			}
764234370Sjasone		} else {
765234370Sjasone			uintmax_t index;
766235238Sjasone			const ctl_indexed_node_t *inode;
767234370Sjasone
768234370Sjasone			/* Children are indexed. */
769234370Sjasone			index = malloc_strtoumax(elm, NULL, 10);
770234370Sjasone			if (index == UINTMAX_MAX || index > SIZE_T_MAX) {
771234370Sjasone				ret = ENOENT;
772234370Sjasone				goto label_return;
773234370Sjasone			}
774234370Sjasone
775235238Sjasone			inode = ctl_indexed_node(node->children);
776235238Sjasone			node = inode->index(mibp, *depthp, (size_t)index);
777234370Sjasone			if (node == NULL) {
778234370Sjasone				ret = ENOENT;
779234370Sjasone				goto label_return;
780234370Sjasone			}
781234370Sjasone
782234370Sjasone			if (nodesp != NULL)
783235238Sjasone				nodesp[i] = (const ctl_node_t *)node;
784234370Sjasone			mibp[i] = (size_t)index;
785234370Sjasone		}
786234370Sjasone
787234370Sjasone		if (node->ctl != NULL) {
788234370Sjasone			/* Terminal node. */
789234370Sjasone			if (*dot != '\0') {
790234370Sjasone				/*
791234370Sjasone				 * The name contains more elements than are
792234370Sjasone				 * in this path through the tree.
793234370Sjasone				 */
794234370Sjasone				ret = ENOENT;
795234370Sjasone				goto label_return;
796234370Sjasone			}
797234370Sjasone			/* Complete lookup successful. */
798234370Sjasone			*depthp = i + 1;
799234370Sjasone			break;
800234370Sjasone		}
801234370Sjasone
802234370Sjasone		/* Update elm. */
803234370Sjasone		if (*dot == '\0') {
804234370Sjasone			/* No more elements. */
805234370Sjasone			ret = ENOENT;
806234370Sjasone			goto label_return;
807234370Sjasone		}
808234370Sjasone		elm = &dot[1];
809234370Sjasone		dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot :
810234370Sjasone		    strchr(elm, '\0');
811234370Sjasone		elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
812234370Sjasone	}
813234370Sjasone
814234370Sjasone	ret = 0;
815234370Sjasonelabel_return:
816234370Sjasone	return (ret);
817234370Sjasone}
818234370Sjasone
819234370Sjasoneint
820234370Sjasonectl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
821234370Sjasone    size_t newlen)
822234370Sjasone{
823234370Sjasone	int ret;
824234370Sjasone	size_t depth;
825234370Sjasone	ctl_node_t const *nodes[CTL_MAX_DEPTH];
826234370Sjasone	size_t mib[CTL_MAX_DEPTH];
827235238Sjasone	const ctl_named_node_t *node;
828234370Sjasone
829234370Sjasone	if (ctl_initialized == false && ctl_init()) {
830234370Sjasone		ret = EAGAIN;
831234370Sjasone		goto label_return;
832234370Sjasone	}
833234370Sjasone
834234370Sjasone	depth = CTL_MAX_DEPTH;
835234370Sjasone	ret = ctl_lookup(name, nodes, mib, &depth);
836234370Sjasone	if (ret != 0)
837234370Sjasone		goto label_return;
838234370Sjasone
839235238Sjasone	node = ctl_named_node(nodes[depth-1]);
840235238Sjasone	if (node != NULL && node->ctl)
841235238Sjasone		ret = node->ctl(mib, depth, oldp, oldlenp, newp, newlen);
842235238Sjasone	else {
843234370Sjasone		/* The name refers to a partial path through the ctl tree. */
844234370Sjasone		ret = ENOENT;
845234370Sjasone	}
846234370Sjasone
847234370Sjasonelabel_return:
848234370Sjasone	return(ret);
849234370Sjasone}
850234370Sjasone
851234370Sjasoneint
852234370Sjasonectl_nametomib(const char *name, size_t *mibp, size_t *miblenp)
853234370Sjasone{
854234370Sjasone	int ret;
855234370Sjasone
856234370Sjasone	if (ctl_initialized == false && ctl_init()) {
857234370Sjasone		ret = EAGAIN;
858234370Sjasone		goto label_return;
859234370Sjasone	}
860234370Sjasone
861234370Sjasone	ret = ctl_lookup(name, NULL, mibp, miblenp);
862234370Sjasonelabel_return:
863234370Sjasone	return(ret);
864234370Sjasone}
865234370Sjasone
866234370Sjasoneint
867234370Sjasonectl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
868234370Sjasone    void *newp, size_t newlen)
869234370Sjasone{
870234370Sjasone	int ret;
871235238Sjasone	const ctl_named_node_t *node;
872234370Sjasone	size_t i;
873234370Sjasone
874234370Sjasone	if (ctl_initialized == false && ctl_init()) {
875234370Sjasone		ret = EAGAIN;
876234370Sjasone		goto label_return;
877234370Sjasone	}
878234370Sjasone
879234370Sjasone	/* Iterate down the tree. */
880234370Sjasone	node = super_root_node;
881234370Sjasone	for (i = 0; i < miblen; i++) {
882235238Sjasone		assert(node);
883235238Sjasone		assert(node->nchildren > 0);
884235238Sjasone		if (ctl_named_node(node->children) != NULL) {
885234370Sjasone			/* Children are named. */
886235238Sjasone			if (node->nchildren <= mib[i]) {
887234370Sjasone				ret = ENOENT;
888234370Sjasone				goto label_return;
889234370Sjasone			}
890235238Sjasone			node = ctl_named_children(node, mib[i]);
891234370Sjasone		} else {
892235238Sjasone			const ctl_indexed_node_t *inode;
893234370Sjasone
894234370Sjasone			/* Indexed element. */
895235238Sjasone			inode = ctl_indexed_node(node->children);
896235238Sjasone			node = inode->index(mib, miblen, mib[i]);
897234370Sjasone			if (node == NULL) {
898234370Sjasone				ret = ENOENT;
899234370Sjasone				goto label_return;
900234370Sjasone			}
901234370Sjasone		}
902234370Sjasone	}
903234370Sjasone
904234370Sjasone	/* Call the ctl function. */
905235238Sjasone	if (node && node->ctl)
906235238Sjasone		ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen);
907235238Sjasone	else {
908234370Sjasone		/* Partial MIB. */
909234370Sjasone		ret = ENOENT;
910234370Sjasone	}
911234370Sjasone
912234370Sjasonelabel_return:
913234370Sjasone	return(ret);
914234370Sjasone}
915234370Sjasone
916234370Sjasonebool
917234370Sjasonectl_boot(void)
918234370Sjasone{
919234370Sjasone
920234370Sjasone	if (malloc_mutex_init(&ctl_mtx))
921234370Sjasone		return (true);
922234370Sjasone
923234370Sjasone	ctl_initialized = false;
924234370Sjasone
925234370Sjasone	return (false);
926234370Sjasone}
927234370Sjasone
928242844Sjasonevoid
929242844Sjasonectl_prefork(void)
930242844Sjasone{
931242844Sjasone
932261071Sjasone	malloc_mutex_prefork(&ctl_mtx);
933242844Sjasone}
934242844Sjasone
935242844Sjasonevoid
936242844Sjasonectl_postfork_parent(void)
937242844Sjasone{
938242844Sjasone
939242844Sjasone	malloc_mutex_postfork_parent(&ctl_mtx);
940242844Sjasone}
941242844Sjasone
942242844Sjasonevoid
943242844Sjasonectl_postfork_child(void)
944242844Sjasone{
945242844Sjasone
946242844Sjasone	malloc_mutex_postfork_child(&ctl_mtx);
947242844Sjasone}
948242844Sjasone
949234370Sjasone/******************************************************************************/
950234370Sjasone/* *_ctl() functions. */
951234370Sjasone
952234370Sjasone#define	READONLY()	do {						\
953234370Sjasone	if (newp != NULL || newlen != 0) {				\
954234370Sjasone		ret = EPERM;						\
955235238Sjasone		goto label_return;					\
956234370Sjasone	}								\
957234370Sjasone} while (0)
958234370Sjasone
959234370Sjasone#define	WRITEONLY()	do {						\
960234370Sjasone	if (oldp != NULL || oldlenp != NULL) {				\
961234370Sjasone		ret = EPERM;						\
962235238Sjasone		goto label_return;					\
963234370Sjasone	}								\
964234370Sjasone} while (0)
965234370Sjasone
966234370Sjasone#define	READ(v, t)	do {						\
967234370Sjasone	if (oldp != NULL && oldlenp != NULL) {				\
968234370Sjasone		if (*oldlenp != sizeof(t)) {				\
969234370Sjasone			size_t	copylen = (sizeof(t) <= *oldlenp)	\
970234370Sjasone			    ? sizeof(t) : *oldlenp;			\
971245868Sjasone			memcpy(oldp, (void *)&(v), copylen);		\
972234370Sjasone			ret = EINVAL;					\
973235238Sjasone			goto label_return;				\
974234370Sjasone		} else							\
975245868Sjasone			*(t *)oldp = (v);				\
976234370Sjasone	}								\
977234370Sjasone} while (0)
978234370Sjasone
979234370Sjasone#define	WRITE(v, t)	do {						\
980234370Sjasone	if (newp != NULL) {						\
981234370Sjasone		if (newlen != sizeof(t)) {				\
982234370Sjasone			ret = EINVAL;					\
983235238Sjasone			goto label_return;				\
984234370Sjasone		}							\
985245868Sjasone		(v) = *(t *)newp;					\
986234370Sjasone	}								\
987234370Sjasone} while (0)
988234370Sjasone
989234370Sjasone/*
990234370Sjasone * There's a lot of code duplication in the following macros due to limitations
991234370Sjasone * in how nested cpp macros are expanded.
992234370Sjasone */
993234370Sjasone#define	CTL_RO_CLGEN(c, l, n, v, t)					\
994234370Sjasonestatic int								\
995234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
996234370Sjasone    void *newp, size_t newlen)						\
997234370Sjasone{									\
998234370Sjasone	int ret;							\
999234370Sjasone	t oldval;							\
1000234370Sjasone									\
1001234370Sjasone	if ((c) == false)						\
1002234370Sjasone		return (ENOENT);					\
1003234370Sjasone	if (l)								\
1004234370Sjasone		malloc_mutex_lock(&ctl_mtx);				\
1005234370Sjasone	READONLY();							\
1006245868Sjasone	oldval = (v);							\
1007234370Sjasone	READ(oldval, t);						\
1008234370Sjasone									\
1009234370Sjasone	ret = 0;							\
1010235238Sjasonelabel_return:								\
1011234370Sjasone	if (l)								\
1012234370Sjasone		malloc_mutex_unlock(&ctl_mtx);				\
1013234370Sjasone	return (ret);							\
1014234370Sjasone}
1015234370Sjasone
1016234370Sjasone#define	CTL_RO_CGEN(c, n, v, t)						\
1017234370Sjasonestatic int								\
1018234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1019234370Sjasone    void *newp, size_t newlen)						\
1020234370Sjasone{									\
1021234370Sjasone	int ret;							\
1022234370Sjasone	t oldval;							\
1023234370Sjasone									\
1024234370Sjasone	if ((c) == false)						\
1025234370Sjasone		return (ENOENT);					\
1026234370Sjasone	malloc_mutex_lock(&ctl_mtx);					\
1027234370Sjasone	READONLY();							\
1028245868Sjasone	oldval = (v);							\
1029234370Sjasone	READ(oldval, t);						\
1030234370Sjasone									\
1031234370Sjasone	ret = 0;							\
1032235238Sjasonelabel_return:								\
1033234370Sjasone	malloc_mutex_unlock(&ctl_mtx);					\
1034234370Sjasone	return (ret);							\
1035234370Sjasone}
1036234370Sjasone
1037234370Sjasone#define	CTL_RO_GEN(n, v, t)						\
1038234370Sjasonestatic int								\
1039234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1040234370Sjasone    void *newp, size_t newlen)						\
1041234370Sjasone{									\
1042234370Sjasone	int ret;							\
1043234370Sjasone	t oldval;							\
1044234370Sjasone									\
1045234370Sjasone	malloc_mutex_lock(&ctl_mtx);					\
1046234370Sjasone	READONLY();							\
1047245868Sjasone	oldval = (v);							\
1048234370Sjasone	READ(oldval, t);						\
1049234370Sjasone									\
1050234370Sjasone	ret = 0;							\
1051235238Sjasonelabel_return:								\
1052234370Sjasone	malloc_mutex_unlock(&ctl_mtx);					\
1053234370Sjasone	return (ret);							\
1054234370Sjasone}
1055234370Sjasone
1056234370Sjasone/*
1057234370Sjasone * ctl_mtx is not acquired, under the assumption that no pertinent data will
1058234370Sjasone * mutate during the call.
1059234370Sjasone */
1060234370Sjasone#define	CTL_RO_NL_CGEN(c, n, v, t)					\
1061234370Sjasonestatic int								\
1062234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1063234370Sjasone    void *newp, size_t newlen)						\
1064234370Sjasone{									\
1065234370Sjasone	int ret;							\
1066234370Sjasone	t oldval;							\
1067234370Sjasone									\
1068234370Sjasone	if ((c) == false)						\
1069234370Sjasone		return (ENOENT);					\
1070234370Sjasone	READONLY();							\
1071245868Sjasone	oldval = (v);							\
1072234370Sjasone	READ(oldval, t);						\
1073234370Sjasone									\
1074234370Sjasone	ret = 0;							\
1075235238Sjasonelabel_return:								\
1076234370Sjasone	return (ret);							\
1077234370Sjasone}
1078234370Sjasone
1079234370Sjasone#define	CTL_RO_NL_GEN(n, v, t)						\
1080234370Sjasonestatic int								\
1081234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1082234370Sjasone    void *newp, size_t newlen)						\
1083234370Sjasone{									\
1084234370Sjasone	int ret;							\
1085234370Sjasone	t oldval;							\
1086234370Sjasone									\
1087234370Sjasone	READONLY();							\
1088245868Sjasone	oldval = (v);							\
1089234370Sjasone	READ(oldval, t);						\
1090234370Sjasone									\
1091234370Sjasone	ret = 0;							\
1092235238Sjasonelabel_return:								\
1093234370Sjasone	return (ret);							\
1094234370Sjasone}
1095234370Sjasone
1096234370Sjasone#define	CTL_RO_BOOL_CONFIG_GEN(n)					\
1097234370Sjasonestatic int								\
1098234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1099234370Sjasone    void *newp, size_t newlen)						\
1100234370Sjasone{									\
1101234370Sjasone	int ret;							\
1102234370Sjasone	bool oldval;							\
1103234370Sjasone									\
1104234370Sjasone	READONLY();							\
1105234370Sjasone	oldval = n;							\
1106234370Sjasone	READ(oldval, bool);						\
1107234370Sjasone									\
1108234370Sjasone	ret = 0;							\
1109235238Sjasonelabel_return:								\
1110234370Sjasone	return (ret);							\
1111234370Sjasone}
1112234370Sjasone
1113261071Sjasone/******************************************************************************/
1114261071Sjasone
1115234370SjasoneCTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
1116234370Sjasone
1117234370Sjasonestatic int
1118234370Sjasoneepoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1119234370Sjasone    void *newp, size_t newlen)
1120234370Sjasone{
1121234370Sjasone	int ret;
1122256823Sjasone	UNUSED uint64_t newval;
1123234370Sjasone
1124234370Sjasone	malloc_mutex_lock(&ctl_mtx);
1125234370Sjasone	WRITE(newval, uint64_t);
1126235238Sjasone	if (newp != NULL)
1127234370Sjasone		ctl_refresh();
1128234370Sjasone	READ(ctl_epoch, uint64_t);
1129234370Sjasone
1130234370Sjasone	ret = 0;
1131234370Sjasonelabel_return:
1132234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1133234370Sjasone	return (ret);
1134234370Sjasone}
1135234370Sjasone
1136261071Sjasone/******************************************************************************/
1137234370Sjasone
1138261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_debug)
1139261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_dss)
1140261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_fill)
1141261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_lazy_lock)
1142261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_mremap)
1143261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_munmap)
1144261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof)
1145261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc)
1146261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof_libunwind)
1147261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_stats)
1148261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_tcache)
1149261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_tls)
1150261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_utrace)
1151261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_valgrind)
1152261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_xmalloc)
1153234370Sjasone
1154261071Sjasone/******************************************************************************/
1155234370Sjasone
1156261071SjasoneCTL_RO_NL_GEN(opt_abort, opt_abort, bool)
1157261071SjasoneCTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
1158261071SjasoneCTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
1159261071SjasoneCTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t)
1160261071SjasoneCTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
1161261071SjasoneCTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
1162261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, bool)
1163261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t)
1164261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool)
1165261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
1166261071SjasoneCTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
1167261071SjasoneCTL_RO_NL_CGEN(config_valgrind, opt_valgrind, opt_valgrind, bool)
1168261071SjasoneCTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
1169261071SjasoneCTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
1170261071SjasoneCTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
1171261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
1172261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
1173261071SjasoneCTL_RO_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) /* Mutable. */
1174261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
1175261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
1176261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
1177261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
1178261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
1179261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
1180234370Sjasone
1181261071Sjasone/******************************************************************************/
1182234370Sjasone
1183234370Sjasonestatic int
1184234370Sjasonethread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1185234370Sjasone    void *newp, size_t newlen)
1186234370Sjasone{
1187234370Sjasone	int ret;
1188234370Sjasone	unsigned newind, oldind;
1189234370Sjasone
1190242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1191234370Sjasone	newind = oldind = choose_arena(NULL)->ind;
1192234370Sjasone	WRITE(newind, unsigned);
1193234370Sjasone	READ(oldind, unsigned);
1194234370Sjasone	if (newind != oldind) {
1195234370Sjasone		arena_t *arena;
1196234370Sjasone
1197242844Sjasone		if (newind >= ctl_stats.narenas) {
1198234370Sjasone			/* New arena index is out of range. */
1199234370Sjasone			ret = EFAULT;
1200234370Sjasone			goto label_return;
1201234370Sjasone		}
1202234370Sjasone
1203234370Sjasone		/* Initialize arena if necessary. */
1204234370Sjasone		malloc_mutex_lock(&arenas_lock);
1205234370Sjasone		if ((arena = arenas[newind]) == NULL && (arena =
1206234370Sjasone		    arenas_extend(newind)) == NULL) {
1207234370Sjasone			malloc_mutex_unlock(&arenas_lock);
1208234370Sjasone			ret = EAGAIN;
1209234370Sjasone			goto label_return;
1210234370Sjasone		}
1211234370Sjasone		assert(arena == arenas[newind]);
1212234370Sjasone		arenas[oldind]->nthreads--;
1213234370Sjasone		arenas[newind]->nthreads++;
1214234370Sjasone		malloc_mutex_unlock(&arenas_lock);
1215234370Sjasone
1216234370Sjasone		/* Set new arena association. */
1217234370Sjasone		if (config_tcache) {
1218234370Sjasone			tcache_t *tcache;
1219234370Sjasone			if ((uintptr_t)(tcache = *tcache_tsd_get()) >
1220234370Sjasone			    (uintptr_t)TCACHE_STATE_MAX) {
1221234370Sjasone				tcache_arena_dissociate(tcache);
1222234370Sjasone				tcache_arena_associate(tcache, arena);
1223234370Sjasone			}
1224234370Sjasone		}
1225234370Sjasone		arenas_tsd_set(&arena);
1226234370Sjasone	}
1227234370Sjasone
1228234370Sjasone	ret = 0;
1229234370Sjasonelabel_return:
1230242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1231234370Sjasone	return (ret);
1232234370Sjasone}
1233234370Sjasone
1234234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_allocated,
1235234370Sjasone    thread_allocated_tsd_get()->allocated, uint64_t)
1236234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_allocatedp,
1237234370Sjasone    &thread_allocated_tsd_get()->allocated, uint64_t *)
1238234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_deallocated,
1239234370Sjasone    thread_allocated_tsd_get()->deallocated, uint64_t)
1240234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_deallocatedp,
1241234370Sjasone    &thread_allocated_tsd_get()->deallocated, uint64_t *)
1242234370Sjasone
1243261071Sjasonestatic int
1244261071Sjasonethread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp,
1245261071Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1246261071Sjasone{
1247261071Sjasone	int ret;
1248261071Sjasone	bool oldval;
1249234370Sjasone
1250261071Sjasone	if (config_tcache == false)
1251261071Sjasone		return (ENOENT);
1252234370Sjasone
1253261071Sjasone	oldval = tcache_enabled_get();
1254261071Sjasone	if (newp != NULL) {
1255261071Sjasone		if (newlen != sizeof(bool)) {
1256261071Sjasone			ret = EINVAL;
1257261071Sjasone			goto label_return;
1258261071Sjasone		}
1259261071Sjasone		tcache_enabled_set(*(bool *)newp);
1260261071Sjasone	}
1261261071Sjasone	READ(oldval, bool);
1262234370Sjasone
1263261071Sjasone	ret = 0;
1264261071Sjasonelabel_return:
1265261071Sjasone	return (ret);
1266261071Sjasone}
1267234370Sjasone
1268261071Sjasonestatic int
1269261071Sjasonethread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp,
1270261071Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1271261071Sjasone{
1272261071Sjasone	int ret;
1273261071Sjasone
1274261071Sjasone	if (config_tcache == false)
1275261071Sjasone		return (ENOENT);
1276261071Sjasone
1277261071Sjasone	READONLY();
1278261071Sjasone	WRITEONLY();
1279261071Sjasone
1280261071Sjasone	tcache_flush();
1281261071Sjasone
1282261071Sjasone	ret = 0;
1283261071Sjasonelabel_return:
1284261071Sjasone	return (ret);
1285261071Sjasone}
1286261071Sjasone
1287234370Sjasone/******************************************************************************/
1288234370Sjasone
1289242844Sjasone/* ctl_mutex must be held during execution of this function. */
1290242844Sjasonestatic void
1291242844Sjasonearena_purge(unsigned arena_ind)
1292242844Sjasone{
1293242844Sjasone	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
1294242844Sjasone
1295242844Sjasone	malloc_mutex_lock(&arenas_lock);
1296242844Sjasone	memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
1297242844Sjasone	malloc_mutex_unlock(&arenas_lock);
1298242844Sjasone
1299242844Sjasone	if (arena_ind == ctl_stats.narenas) {
1300242844Sjasone		unsigned i;
1301242844Sjasone		for (i = 0; i < ctl_stats.narenas; i++) {
1302242844Sjasone			if (tarenas[i] != NULL)
1303242844Sjasone				arena_purge_all(tarenas[i]);
1304242844Sjasone		}
1305242844Sjasone	} else {
1306242844Sjasone		assert(arena_ind < ctl_stats.narenas);
1307242844Sjasone		if (tarenas[arena_ind] != NULL)
1308242844Sjasone			arena_purge_all(tarenas[arena_ind]);
1309242844Sjasone	}
1310242844Sjasone}
1311242844Sjasone
1312242844Sjasonestatic int
1313242844Sjasonearena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1314242844Sjasone    void *newp, size_t newlen)
1315242844Sjasone{
1316242844Sjasone	int ret;
1317242844Sjasone
1318242844Sjasone	READONLY();
1319242844Sjasone	WRITEONLY();
1320242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1321242844Sjasone	arena_purge(mib[1]);
1322242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1323242844Sjasone
1324242844Sjasone	ret = 0;
1325242844Sjasonelabel_return:
1326242844Sjasone	return (ret);
1327242844Sjasone}
1328242844Sjasone
1329242844Sjasonestatic int
1330242844Sjasonearena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1331242844Sjasone    void *newp, size_t newlen)
1332242844Sjasone{
1333242844Sjasone	int ret, i;
1334242844Sjasone	bool match, err;
1335242844Sjasone	const char *dss;
1336242844Sjasone	unsigned arena_ind = mib[1];
1337242844Sjasone	dss_prec_t dss_prec_old = dss_prec_limit;
1338242844Sjasone	dss_prec_t dss_prec = dss_prec_limit;
1339242844Sjasone
1340242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1341242844Sjasone	WRITE(dss, const char *);
1342242844Sjasone	match = false;
1343242844Sjasone	for (i = 0; i < dss_prec_limit; i++) {
1344242844Sjasone		if (strcmp(dss_prec_names[i], dss) == 0) {
1345242844Sjasone			dss_prec = i;
1346242844Sjasone			match = true;
1347242844Sjasone			break;
1348242844Sjasone		}
1349242844Sjasone	}
1350242844Sjasone	if (match == false) {
1351242844Sjasone		ret = EINVAL;
1352242844Sjasone		goto label_return;
1353242844Sjasone	}
1354242844Sjasone
1355242844Sjasone	if (arena_ind < ctl_stats.narenas) {
1356242844Sjasone		arena_t *arena = arenas[arena_ind];
1357242844Sjasone		if (arena != NULL) {
1358242844Sjasone			dss_prec_old = arena_dss_prec_get(arena);
1359242844Sjasone			arena_dss_prec_set(arena, dss_prec);
1360242844Sjasone			err = false;
1361242844Sjasone		} else
1362242844Sjasone			err = true;
1363242844Sjasone	} else {
1364242844Sjasone		dss_prec_old = chunk_dss_prec_get();
1365242844Sjasone		err = chunk_dss_prec_set(dss_prec);
1366242844Sjasone	}
1367242844Sjasone	dss = dss_prec_names[dss_prec_old];
1368242844Sjasone	READ(dss, const char *);
1369242844Sjasone	if (err) {
1370242844Sjasone		ret = EFAULT;
1371242844Sjasone		goto label_return;
1372242844Sjasone	}
1373242844Sjasone
1374242844Sjasone	ret = 0;
1375242844Sjasonelabel_return:
1376242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1377242844Sjasone	return (ret);
1378242844Sjasone}
1379242844Sjasone
1380242844Sjasonestatic const ctl_named_node_t *
1381242844Sjasonearena_i_index(const size_t *mib, size_t miblen, size_t i)
1382242844Sjasone{
1383242844Sjasone	const ctl_named_node_t * ret;
1384242844Sjasone
1385242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1386242844Sjasone	if (i > ctl_stats.narenas) {
1387242844Sjasone		ret = NULL;
1388242844Sjasone		goto label_return;
1389242844Sjasone	}
1390242844Sjasone
1391242844Sjasone	ret = super_arena_i_node;
1392242844Sjasonelabel_return:
1393242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1394242844Sjasone	return (ret);
1395242844Sjasone}
1396242844Sjasone
1397242844Sjasone/******************************************************************************/
1398242844Sjasone
1399242844Sjasonestatic int
1400242844Sjasonearenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp,
1401242844Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1402242844Sjasone{
1403242844Sjasone	int ret;
1404242844Sjasone	unsigned narenas;
1405234370Sjasone
1406242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1407242844Sjasone	READONLY();
1408242844Sjasone	if (*oldlenp != sizeof(unsigned)) {
1409242844Sjasone		ret = EINVAL;
1410242844Sjasone		goto label_return;
1411242844Sjasone	}
1412242844Sjasone	narenas = ctl_stats.narenas;
1413242844Sjasone	READ(narenas, unsigned);
1414242844Sjasone
1415242844Sjasone	ret = 0;
1416242844Sjasonelabel_return:
1417242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1418242844Sjasone	return (ret);
1419242844Sjasone}
1420242844Sjasone
1421234370Sjasonestatic int
1422234370Sjasonearenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
1423234370Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1424234370Sjasone{
1425234370Sjasone	int ret;
1426234370Sjasone	unsigned nread, i;
1427234370Sjasone
1428234370Sjasone	malloc_mutex_lock(&ctl_mtx);
1429234370Sjasone	READONLY();
1430242844Sjasone	if (*oldlenp != ctl_stats.narenas * sizeof(bool)) {
1431234370Sjasone		ret = EINVAL;
1432242844Sjasone		nread = (*oldlenp < ctl_stats.narenas * sizeof(bool))
1433242844Sjasone		    ? (*oldlenp / sizeof(bool)) : ctl_stats.narenas;
1434234370Sjasone	} else {
1435234370Sjasone		ret = 0;
1436242844Sjasone		nread = ctl_stats.narenas;
1437234370Sjasone	}
1438234370Sjasone
1439234370Sjasone	for (i = 0; i < nread; i++)
1440234370Sjasone		((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
1441234370Sjasone
1442234370Sjasonelabel_return:
1443234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1444234370Sjasone	return (ret);
1445234370Sjasone}
1446234370Sjasone
1447234370SjasoneCTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
1448234370SjasoneCTL_RO_NL_GEN(arenas_page, PAGE, size_t)
1449234370SjasoneCTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t)
1450234370SjasoneCTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
1451234370SjasoneCTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned)
1452261071SjasoneCTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
1453261071SjasoneCTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
1454261071SjasoneCTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
1455261071Sjasonestatic const ctl_named_node_t *
1456261071Sjasonearenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
1457261071Sjasone{
1458261071Sjasone
1459261071Sjasone	if (i > NBINS)
1460261071Sjasone		return (NULL);
1461261071Sjasone	return (super_arenas_bin_i_node);
1462261071Sjasone}
1463261071Sjasone
1464234370SjasoneCTL_RO_NL_GEN(arenas_nlruns, nlclasses, size_t)
1465261071SjasoneCTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << LG_PAGE), size_t)
1466261071Sjasonestatic const ctl_named_node_t *
1467261071Sjasonearenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
1468261071Sjasone{
1469234370Sjasone
1470261071Sjasone	if (i > nlclasses)
1471261071Sjasone		return (NULL);
1472261071Sjasone	return (super_arenas_lrun_i_node);
1473261071Sjasone}
1474261071Sjasone
1475234370Sjasonestatic int
1476234370Sjasonearenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1477234370Sjasone    void *newp, size_t newlen)
1478234370Sjasone{
1479234370Sjasone	int ret;
1480242844Sjasone	unsigned arena_ind;
1481234370Sjasone
1482242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1483234370Sjasone	WRITEONLY();
1484242844Sjasone	arena_ind = UINT_MAX;
1485242844Sjasone	WRITE(arena_ind, unsigned);
1486242844Sjasone	if (newp != NULL && arena_ind >= ctl_stats.narenas)
1487234370Sjasone		ret = EFAULT;
1488242844Sjasone	else {
1489242844Sjasone		if (arena_ind == UINT_MAX)
1490242844Sjasone			arena_ind = ctl_stats.narenas;
1491242844Sjasone		arena_purge(arena_ind);
1492242844Sjasone		ret = 0;
1493242844Sjasone	}
1494234370Sjasone
1495242844Sjasonelabel_return:
1496242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1497242844Sjasone	return (ret);
1498242844Sjasone}
1499234370Sjasone
1500242844Sjasonestatic int
1501242844Sjasonearenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1502242844Sjasone    void *newp, size_t newlen)
1503242844Sjasone{
1504242844Sjasone	int ret;
1505245868Sjasone	unsigned narenas;
1506242844Sjasone
1507242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1508242844Sjasone	READONLY();
1509242844Sjasone	if (ctl_grow()) {
1510242844Sjasone		ret = EAGAIN;
1511242844Sjasone		goto label_return;
1512234370Sjasone	}
1513245868Sjasone	narenas = ctl_stats.narenas - 1;
1514245868Sjasone	READ(narenas, unsigned);
1515234370Sjasone
1516234370Sjasone	ret = 0;
1517234370Sjasonelabel_return:
1518242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1519234370Sjasone	return (ret);
1520234370Sjasone}
1521234370Sjasone
1522234370Sjasone/******************************************************************************/
1523234370Sjasone
1524234370Sjasonestatic int
1525234370Sjasoneprof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1526234370Sjasone    void *newp, size_t newlen)
1527234370Sjasone{
1528234370Sjasone	int ret;
1529234370Sjasone	bool oldval;
1530234370Sjasone
1531234370Sjasone	if (config_prof == false)
1532234370Sjasone		return (ENOENT);
1533234370Sjasone
1534234370Sjasone	malloc_mutex_lock(&ctl_mtx); /* Protect opt_prof_active. */
1535234370Sjasone	oldval = opt_prof_active;
1536234370Sjasone	if (newp != NULL) {
1537234370Sjasone		/*
1538234370Sjasone		 * The memory barriers will tend to make opt_prof_active
1539234370Sjasone		 * propagate faster on systems with weak memory ordering.
1540234370Sjasone		 */
1541234370Sjasone		mb_write();
1542234370Sjasone		WRITE(opt_prof_active, bool);
1543234370Sjasone		mb_write();
1544234370Sjasone	}
1545234370Sjasone	READ(oldval, bool);
1546234370Sjasone
1547234370Sjasone	ret = 0;
1548234370Sjasonelabel_return:
1549234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1550234370Sjasone	return (ret);
1551234370Sjasone}
1552234370Sjasone
1553234370Sjasonestatic int
1554234370Sjasoneprof_dump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1555234370Sjasone    void *newp, size_t newlen)
1556234370Sjasone{
1557234370Sjasone	int ret;
1558234370Sjasone	const char *filename = NULL;
1559234370Sjasone
1560234370Sjasone	if (config_prof == false)
1561234370Sjasone		return (ENOENT);
1562234370Sjasone
1563234370Sjasone	WRITEONLY();
1564234370Sjasone	WRITE(filename, const char *);
1565234370Sjasone
1566234370Sjasone	if (prof_mdump(filename)) {
1567234370Sjasone		ret = EFAULT;
1568234370Sjasone		goto label_return;
1569234370Sjasone	}
1570234370Sjasone
1571234370Sjasone	ret = 0;
1572234370Sjasonelabel_return:
1573234370Sjasone	return (ret);
1574234370Sjasone}
1575234370Sjasone
1576234370SjasoneCTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
1577234370Sjasone
1578234370Sjasone/******************************************************************************/
1579234370Sjasone
1580261071SjasoneCTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *)
1581261071SjasoneCTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t)
1582261071SjasoneCTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t)
1583261071SjasoneCTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t)
1584261071Sjasone
1585234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_current, ctl_stats.chunks.current,
1586234370Sjasone    size_t)
1587234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_total, ctl_stats.chunks.total, uint64_t)
1588234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_high, ctl_stats.chunks.high, size_t)
1589234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_allocated, huge_allocated, size_t)
1590234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_nmalloc, huge_nmalloc, uint64_t)
1591234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_ndalloc, huge_ndalloc, uint64_t)
1592261071Sjasone
1593261071SjasoneCTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *)
1594261071SjasoneCTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
1595261071SjasoneCTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
1596261071SjasoneCTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
1597261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
1598261071Sjasone    ctl_stats.arenas[mib[2]].astats.mapped, size_t)
1599261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_npurge,
1600261071Sjasone    ctl_stats.arenas[mib[2]].astats.npurge, uint64_t)
1601261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise,
1602261071Sjasone    ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t)
1603261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_purged,
1604261071Sjasone    ctl_stats.arenas[mib[2]].astats.purged, uint64_t)
1605261071Sjasone
1606234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
1607234370Sjasone    ctl_stats.arenas[mib[2]].allocated_small, size_t)
1608234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
1609234370Sjasone    ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t)
1610234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
1611234370Sjasone    ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t)
1612234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
1613234370Sjasone    ctl_stats.arenas[mib[2]].nrequests_small, uint64_t)
1614234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
1615234370Sjasone    ctl_stats.arenas[mib[2]].astats.allocated_large, size_t)
1616234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
1617234370Sjasone    ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t)
1618234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
1619234370Sjasone    ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t)
1620234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
1621234370Sjasone    ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t)
1622234370Sjasone
1623234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_allocated,
1624234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].allocated, size_t)
1625234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
1626234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t)
1627234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
1628234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t)
1629234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
1630234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t)
1631234370SjasoneCTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills,
1632234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t)
1633234370SjasoneCTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes,
1634234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t)
1635234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns,
1636234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t)
1637234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns,
1638234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t)
1639234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns,
1640234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t)
1641234370Sjasone
1642242844Sjasonestatic const ctl_named_node_t *
1643234370Sjasonestats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j)
1644234370Sjasone{
1645234370Sjasone
1646234370Sjasone	if (j > NBINS)
1647234370Sjasone		return (NULL);
1648234370Sjasone	return (super_stats_arenas_i_bins_j_node);
1649234370Sjasone}
1650234370Sjasone
1651234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc,
1652234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t)
1653234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc,
1654234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t)
1655234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests,
1656234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t)
1657234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns,
1658234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t)
1659234370Sjasone
1660242844Sjasonestatic const ctl_named_node_t *
1661234370Sjasonestats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
1662234370Sjasone{
1663234370Sjasone
1664234370Sjasone	if (j > nlclasses)
1665234370Sjasone		return (NULL);
1666234370Sjasone	return (super_stats_arenas_i_lruns_j_node);
1667234370Sjasone}
1668234370Sjasone
1669242844Sjasonestatic const ctl_named_node_t *
1670234370Sjasonestats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
1671234370Sjasone{
1672235238Sjasone	const ctl_named_node_t * ret;
1673234370Sjasone
1674234370Sjasone	malloc_mutex_lock(&ctl_mtx);
1675242844Sjasone	if (i > ctl_stats.narenas || ctl_stats.arenas[i].initialized == false) {
1676234370Sjasone		ret = NULL;
1677234370Sjasone		goto label_return;
1678234370Sjasone	}
1679234370Sjasone
1680234370Sjasone	ret = super_stats_arenas_i_node;
1681234370Sjasonelabel_return:
1682234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1683234370Sjasone	return (ret);
1684234370Sjasone}
1685