ctl.c revision 245868
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	size_t astats_size;
550242844Sjasone	ctl_arena_stats_t *astats;
551242844Sjasone	arena_t **tarenas;
552242844Sjasone
553242844Sjasone	/* Extend arena stats and arenas arrays. */
554242844Sjasone	astats_size = (ctl_stats.narenas + 2) * sizeof(ctl_arena_stats_t);
555242844Sjasone	if (ctl_stats.narenas == narenas_auto) {
556242844Sjasone		/* ctl_stats.arenas and arenas came from base_alloc(). */
557242844Sjasone		astats = (ctl_arena_stats_t *)imalloc(astats_size);
558242844Sjasone		if (astats == NULL)
559242844Sjasone			return (true);
560242844Sjasone		memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) *
561242844Sjasone		    sizeof(ctl_arena_stats_t));
562242844Sjasone
563242844Sjasone		tarenas = (arena_t **)imalloc((ctl_stats.narenas + 1) *
564242844Sjasone		    sizeof(arena_t *));
565242844Sjasone		if (tarenas == NULL) {
566242844Sjasone			idalloc(astats);
567242844Sjasone			return (true);
568242844Sjasone		}
569242844Sjasone		memcpy(tarenas, arenas, ctl_stats.narenas * sizeof(arena_t *));
570242844Sjasone	} else {
571242844Sjasone		astats = (ctl_arena_stats_t *)iralloc(ctl_stats.arenas,
572242844Sjasone		    astats_size, 0, 0, false, false);
573242844Sjasone		if (astats == NULL)
574242844Sjasone			return (true);
575242844Sjasone
576242844Sjasone		tarenas = (arena_t **)iralloc(arenas, (ctl_stats.narenas + 1) *
577242844Sjasone		    sizeof(arena_t *), 0, 0, false, false);
578242844Sjasone		if (tarenas == NULL)
579242844Sjasone			return (true);
580242844Sjasone	}
581242844Sjasone	/* Initialize the new astats and arenas elements. */
582242844Sjasone	memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t));
583242844Sjasone	if (ctl_arena_init(&astats[ctl_stats.narenas + 1]))
584242844Sjasone		return (true);
585242844Sjasone	tarenas[ctl_stats.narenas] = NULL;
586242844Sjasone	/* Swap merged stats to their new location. */
587242844Sjasone	{
588242844Sjasone		ctl_arena_stats_t tstats;
589242844Sjasone		memcpy(&tstats, &astats[ctl_stats.narenas],
590242844Sjasone		    sizeof(ctl_arena_stats_t));
591242844Sjasone		memcpy(&astats[ctl_stats.narenas],
592242844Sjasone		    &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t));
593242844Sjasone		memcpy(&astats[ctl_stats.narenas + 1], &tstats,
594242844Sjasone		    sizeof(ctl_arena_stats_t));
595242844Sjasone	}
596242844Sjasone	ctl_stats.arenas = astats;
597242844Sjasone	ctl_stats.narenas++;
598242844Sjasone	malloc_mutex_lock(&arenas_lock);
599242844Sjasone	arenas = tarenas;
600242844Sjasone	narenas_total++;
601242844Sjasone	arenas_extend(narenas_total - 1);
602242844Sjasone	malloc_mutex_unlock(&arenas_lock);
603242844Sjasone
604242844Sjasone	return (false);
605242844Sjasone}
606242844Sjasone
607234370Sjasonestatic void
608234370Sjasonectl_refresh(void)
609234370Sjasone{
610234370Sjasone	unsigned i;
611242844Sjasone	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
612234370Sjasone
613234370Sjasone	if (config_stats) {
614234370Sjasone		malloc_mutex_lock(&chunks_mtx);
615234370Sjasone		ctl_stats.chunks.current = stats_chunks.curchunks;
616234370Sjasone		ctl_stats.chunks.total = stats_chunks.nchunks;
617234370Sjasone		ctl_stats.chunks.high = stats_chunks.highchunks;
618234370Sjasone		malloc_mutex_unlock(&chunks_mtx);
619234370Sjasone
620234370Sjasone		malloc_mutex_lock(&huge_mtx);
621234370Sjasone		ctl_stats.huge.allocated = huge_allocated;
622234370Sjasone		ctl_stats.huge.nmalloc = huge_nmalloc;
623234370Sjasone		ctl_stats.huge.ndalloc = huge_ndalloc;
624234370Sjasone		malloc_mutex_unlock(&huge_mtx);
625234370Sjasone	}
626234370Sjasone
627234370Sjasone	/*
628234370Sjasone	 * Clear sum stats, since they will be merged into by
629234370Sjasone	 * ctl_arena_refresh().
630234370Sjasone	 */
631242844Sjasone	ctl_stats.arenas[ctl_stats.narenas].nthreads = 0;
632242844Sjasone	ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]);
633234370Sjasone
634234370Sjasone	malloc_mutex_lock(&arenas_lock);
635242844Sjasone	memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
636242844Sjasone	for (i = 0; i < ctl_stats.narenas; i++) {
637234370Sjasone		if (arenas[i] != NULL)
638234370Sjasone			ctl_stats.arenas[i].nthreads = arenas[i]->nthreads;
639234370Sjasone		else
640234370Sjasone			ctl_stats.arenas[i].nthreads = 0;
641234370Sjasone	}
642234370Sjasone	malloc_mutex_unlock(&arenas_lock);
643242844Sjasone	for (i = 0; i < ctl_stats.narenas; i++) {
644234370Sjasone		bool initialized = (tarenas[i] != NULL);
645234370Sjasone
646234370Sjasone		ctl_stats.arenas[i].initialized = initialized;
647234370Sjasone		if (initialized)
648234370Sjasone			ctl_arena_refresh(tarenas[i], i);
649234370Sjasone	}
650234370Sjasone
651234370Sjasone	if (config_stats) {
652242844Sjasone		ctl_stats.allocated =
653242844Sjasone		    ctl_stats.arenas[ctl_stats.narenas].allocated_small
654242844Sjasone		    + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large
655234370Sjasone		    + ctl_stats.huge.allocated;
656242844Sjasone		ctl_stats.active =
657242844Sjasone		    (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE)
658242844Sjasone		    + ctl_stats.huge.allocated;
659234370Sjasone		ctl_stats.mapped = (ctl_stats.chunks.current << opt_lg_chunk);
660234370Sjasone	}
661234370Sjasone
662234370Sjasone	ctl_epoch++;
663234370Sjasone}
664234370Sjasone
665234370Sjasonestatic bool
666234370Sjasonectl_init(void)
667234370Sjasone{
668234370Sjasone	bool ret;
669234370Sjasone
670234370Sjasone	malloc_mutex_lock(&ctl_mtx);
671234370Sjasone	if (ctl_initialized == false) {
672234370Sjasone		/*
673234370Sjasone		 * Allocate space for one extra arena stats element, which
674234370Sjasone		 * contains summed stats across all arenas.
675234370Sjasone		 */
676242844Sjasone		assert(narenas_auto == narenas_total_get());
677242844Sjasone		ctl_stats.narenas = narenas_auto;
678234370Sjasone		ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
679242844Sjasone		    (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t));
680234370Sjasone		if (ctl_stats.arenas == NULL) {
681234370Sjasone			ret = true;
682234370Sjasone			goto label_return;
683234370Sjasone		}
684242844Sjasone		memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) *
685234370Sjasone		    sizeof(ctl_arena_stats_t));
686234370Sjasone
687234370Sjasone		/*
688234370Sjasone		 * Initialize all stats structures, regardless of whether they
689234370Sjasone		 * ever get used.  Lazy initialization would allow errors to
690234370Sjasone		 * cause inconsistent state to be viewable by the application.
691234370Sjasone		 */
692234370Sjasone		if (config_stats) {
693234370Sjasone			unsigned i;
694242844Sjasone			for (i = 0; i <= ctl_stats.narenas; i++) {
695234370Sjasone				if (ctl_arena_init(&ctl_stats.arenas[i])) {
696234370Sjasone					ret = true;
697234370Sjasone					goto label_return;
698234370Sjasone				}
699234370Sjasone			}
700234370Sjasone		}
701242844Sjasone		ctl_stats.arenas[ctl_stats.narenas].initialized = true;
702234370Sjasone
703234370Sjasone		ctl_epoch = 0;
704234370Sjasone		ctl_refresh();
705234370Sjasone		ctl_initialized = true;
706234370Sjasone	}
707234370Sjasone
708234370Sjasone	ret = false;
709234370Sjasonelabel_return:
710234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
711234370Sjasone	return (ret);
712234370Sjasone}
713234370Sjasone
714234370Sjasonestatic int
715234370Sjasonectl_lookup(const char *name, ctl_node_t const **nodesp, size_t *mibp,
716234370Sjasone    size_t *depthp)
717234370Sjasone{
718234370Sjasone	int ret;
719234370Sjasone	const char *elm, *tdot, *dot;
720234370Sjasone	size_t elen, i, j;
721235238Sjasone	const ctl_named_node_t *node;
722234370Sjasone
723234370Sjasone	elm = name;
724234370Sjasone	/* Equivalent to strchrnul(). */
725234370Sjasone	dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0');
726234370Sjasone	elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
727234370Sjasone	if (elen == 0) {
728234370Sjasone		ret = ENOENT;
729234370Sjasone		goto label_return;
730234370Sjasone	}
731234370Sjasone	node = super_root_node;
732234370Sjasone	for (i = 0; i < *depthp; i++) {
733235238Sjasone		assert(node);
734235238Sjasone		assert(node->nchildren > 0);
735235238Sjasone		if (ctl_named_node(node->children) != NULL) {
736235238Sjasone			const ctl_named_node_t *pnode = node;
737234370Sjasone
738234370Sjasone			/* Children are named. */
739235238Sjasone			for (j = 0; j < node->nchildren; j++) {
740235238Sjasone				const ctl_named_node_t *child =
741235238Sjasone				    ctl_named_children(node, j);
742235238Sjasone				if (strlen(child->name) == elen &&
743235238Sjasone				    strncmp(elm, child->name, elen) == 0) {
744234370Sjasone					node = child;
745234370Sjasone					if (nodesp != NULL)
746235238Sjasone						nodesp[i] =
747235238Sjasone						    (const ctl_node_t *)node;
748234370Sjasone					mibp[i] = j;
749234370Sjasone					break;
750234370Sjasone				}
751234370Sjasone			}
752234370Sjasone			if (node == pnode) {
753234370Sjasone				ret = ENOENT;
754234370Sjasone				goto label_return;
755234370Sjasone			}
756234370Sjasone		} else {
757234370Sjasone			uintmax_t index;
758235238Sjasone			const ctl_indexed_node_t *inode;
759234370Sjasone
760234370Sjasone			/* Children are indexed. */
761234370Sjasone			index = malloc_strtoumax(elm, NULL, 10);
762234370Sjasone			if (index == UINTMAX_MAX || index > SIZE_T_MAX) {
763234370Sjasone				ret = ENOENT;
764234370Sjasone				goto label_return;
765234370Sjasone			}
766234370Sjasone
767235238Sjasone			inode = ctl_indexed_node(node->children);
768235238Sjasone			node = inode->index(mibp, *depthp, (size_t)index);
769234370Sjasone			if (node == NULL) {
770234370Sjasone				ret = ENOENT;
771234370Sjasone				goto label_return;
772234370Sjasone			}
773234370Sjasone
774234370Sjasone			if (nodesp != NULL)
775235238Sjasone				nodesp[i] = (const ctl_node_t *)node;
776234370Sjasone			mibp[i] = (size_t)index;
777234370Sjasone		}
778234370Sjasone
779234370Sjasone		if (node->ctl != NULL) {
780234370Sjasone			/* Terminal node. */
781234370Sjasone			if (*dot != '\0') {
782234370Sjasone				/*
783234370Sjasone				 * The name contains more elements than are
784234370Sjasone				 * in this path through the tree.
785234370Sjasone				 */
786234370Sjasone				ret = ENOENT;
787234370Sjasone				goto label_return;
788234370Sjasone			}
789234370Sjasone			/* Complete lookup successful. */
790234370Sjasone			*depthp = i + 1;
791234370Sjasone			break;
792234370Sjasone		}
793234370Sjasone
794234370Sjasone		/* Update elm. */
795234370Sjasone		if (*dot == '\0') {
796234370Sjasone			/* No more elements. */
797234370Sjasone			ret = ENOENT;
798234370Sjasone			goto label_return;
799234370Sjasone		}
800234370Sjasone		elm = &dot[1];
801234370Sjasone		dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot :
802234370Sjasone		    strchr(elm, '\0');
803234370Sjasone		elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
804234370Sjasone	}
805234370Sjasone
806234370Sjasone	ret = 0;
807234370Sjasonelabel_return:
808234370Sjasone	return (ret);
809234370Sjasone}
810234370Sjasone
811234370Sjasoneint
812234370Sjasonectl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
813234370Sjasone    size_t newlen)
814234370Sjasone{
815234370Sjasone	int ret;
816234370Sjasone	size_t depth;
817234370Sjasone	ctl_node_t const *nodes[CTL_MAX_DEPTH];
818234370Sjasone	size_t mib[CTL_MAX_DEPTH];
819235238Sjasone	const ctl_named_node_t *node;
820234370Sjasone
821234370Sjasone	if (ctl_initialized == false && ctl_init()) {
822234370Sjasone		ret = EAGAIN;
823234370Sjasone		goto label_return;
824234370Sjasone	}
825234370Sjasone
826234370Sjasone	depth = CTL_MAX_DEPTH;
827234370Sjasone	ret = ctl_lookup(name, nodes, mib, &depth);
828234370Sjasone	if (ret != 0)
829234370Sjasone		goto label_return;
830234370Sjasone
831235238Sjasone	node = ctl_named_node(nodes[depth-1]);
832235238Sjasone	if (node != NULL && node->ctl)
833235238Sjasone		ret = node->ctl(mib, depth, oldp, oldlenp, newp, newlen);
834235238Sjasone	else {
835234370Sjasone		/* The name refers to a partial path through the ctl tree. */
836234370Sjasone		ret = ENOENT;
837234370Sjasone	}
838234370Sjasone
839234370Sjasonelabel_return:
840234370Sjasone	return(ret);
841234370Sjasone}
842234370Sjasone
843234370Sjasoneint
844234370Sjasonectl_nametomib(const char *name, size_t *mibp, size_t *miblenp)
845234370Sjasone{
846234370Sjasone	int ret;
847234370Sjasone
848234370Sjasone	if (ctl_initialized == false && ctl_init()) {
849234370Sjasone		ret = EAGAIN;
850234370Sjasone		goto label_return;
851234370Sjasone	}
852234370Sjasone
853234370Sjasone	ret = ctl_lookup(name, NULL, mibp, miblenp);
854234370Sjasonelabel_return:
855234370Sjasone	return(ret);
856234370Sjasone}
857234370Sjasone
858234370Sjasoneint
859234370Sjasonectl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
860234370Sjasone    void *newp, size_t newlen)
861234370Sjasone{
862234370Sjasone	int ret;
863235238Sjasone	const ctl_named_node_t *node;
864234370Sjasone	size_t i;
865234370Sjasone
866234370Sjasone	if (ctl_initialized == false && ctl_init()) {
867234370Sjasone		ret = EAGAIN;
868234370Sjasone		goto label_return;
869234370Sjasone	}
870234370Sjasone
871234370Sjasone	/* Iterate down the tree. */
872234370Sjasone	node = super_root_node;
873234370Sjasone	for (i = 0; i < miblen; i++) {
874235238Sjasone		assert(node);
875235238Sjasone		assert(node->nchildren > 0);
876235238Sjasone		if (ctl_named_node(node->children) != NULL) {
877234370Sjasone			/* Children are named. */
878235238Sjasone			if (node->nchildren <= mib[i]) {
879234370Sjasone				ret = ENOENT;
880234370Sjasone				goto label_return;
881234370Sjasone			}
882235238Sjasone			node = ctl_named_children(node, mib[i]);
883234370Sjasone		} else {
884235238Sjasone			const ctl_indexed_node_t *inode;
885234370Sjasone
886234370Sjasone			/* Indexed element. */
887235238Sjasone			inode = ctl_indexed_node(node->children);
888235238Sjasone			node = inode->index(mib, miblen, mib[i]);
889234370Sjasone			if (node == NULL) {
890234370Sjasone				ret = ENOENT;
891234370Sjasone				goto label_return;
892234370Sjasone			}
893234370Sjasone		}
894234370Sjasone	}
895234370Sjasone
896234370Sjasone	/* Call the ctl function. */
897235238Sjasone	if (node && node->ctl)
898235238Sjasone		ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen);
899235238Sjasone	else {
900234370Sjasone		/* Partial MIB. */
901234370Sjasone		ret = ENOENT;
902234370Sjasone	}
903234370Sjasone
904234370Sjasonelabel_return:
905234370Sjasone	return(ret);
906234370Sjasone}
907234370Sjasone
908234370Sjasonebool
909234370Sjasonectl_boot(void)
910234370Sjasone{
911234370Sjasone
912234370Sjasone	if (malloc_mutex_init(&ctl_mtx))
913234370Sjasone		return (true);
914234370Sjasone
915234370Sjasone	ctl_initialized = false;
916234370Sjasone
917234370Sjasone	return (false);
918234370Sjasone}
919234370Sjasone
920242844Sjasonevoid
921242844Sjasonectl_prefork(void)
922242844Sjasone{
923242844Sjasone
924242844Sjasone	malloc_mutex_lock(&ctl_mtx);
925242844Sjasone}
926242844Sjasone
927242844Sjasonevoid
928242844Sjasonectl_postfork_parent(void)
929242844Sjasone{
930242844Sjasone
931242844Sjasone	malloc_mutex_postfork_parent(&ctl_mtx);
932242844Sjasone}
933242844Sjasone
934242844Sjasonevoid
935242844Sjasonectl_postfork_child(void)
936242844Sjasone{
937242844Sjasone
938242844Sjasone	malloc_mutex_postfork_child(&ctl_mtx);
939242844Sjasone}
940242844Sjasone
941234370Sjasone/******************************************************************************/
942234370Sjasone/* *_ctl() functions. */
943234370Sjasone
944234370Sjasone#define	READONLY()	do {						\
945234370Sjasone	if (newp != NULL || newlen != 0) {				\
946234370Sjasone		ret = EPERM;						\
947235238Sjasone		goto label_return;					\
948234370Sjasone	}								\
949234370Sjasone} while (0)
950234370Sjasone
951234370Sjasone#define	WRITEONLY()	do {						\
952234370Sjasone	if (oldp != NULL || oldlenp != NULL) {				\
953234370Sjasone		ret = EPERM;						\
954235238Sjasone		goto label_return;					\
955234370Sjasone	}								\
956234370Sjasone} while (0)
957234370Sjasone
958234370Sjasone#define	READ(v, t)	do {						\
959234370Sjasone	if (oldp != NULL && oldlenp != NULL) {				\
960234370Sjasone		if (*oldlenp != sizeof(t)) {				\
961234370Sjasone			size_t	copylen = (sizeof(t) <= *oldlenp)	\
962234370Sjasone			    ? sizeof(t) : *oldlenp;			\
963245868Sjasone			memcpy(oldp, (void *)&(v), copylen);		\
964234370Sjasone			ret = EINVAL;					\
965235238Sjasone			goto label_return;				\
966234370Sjasone		} else							\
967245868Sjasone			*(t *)oldp = (v);				\
968234370Sjasone	}								\
969234370Sjasone} while (0)
970234370Sjasone
971234370Sjasone#define	WRITE(v, t)	do {						\
972234370Sjasone	if (newp != NULL) {						\
973234370Sjasone		if (newlen != sizeof(t)) {				\
974234370Sjasone			ret = EINVAL;					\
975235238Sjasone			goto label_return;				\
976234370Sjasone		}							\
977245868Sjasone		(v) = *(t *)newp;					\
978234370Sjasone	}								\
979234370Sjasone} while (0)
980234370Sjasone
981234370Sjasone/*
982234370Sjasone * There's a lot of code duplication in the following macros due to limitations
983234370Sjasone * in how nested cpp macros are expanded.
984234370Sjasone */
985234370Sjasone#define	CTL_RO_CLGEN(c, l, n, v, t)					\
986234370Sjasonestatic int								\
987234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
988234370Sjasone    void *newp, size_t newlen)						\
989234370Sjasone{									\
990234370Sjasone	int ret;							\
991234370Sjasone	t oldval;							\
992234370Sjasone									\
993234370Sjasone	if ((c) == false)						\
994234370Sjasone		return (ENOENT);					\
995234370Sjasone	if (l)								\
996234370Sjasone		malloc_mutex_lock(&ctl_mtx);				\
997234370Sjasone	READONLY();							\
998245868Sjasone	oldval = (v);							\
999234370Sjasone	READ(oldval, t);						\
1000234370Sjasone									\
1001234370Sjasone	ret = 0;							\
1002235238Sjasonelabel_return:								\
1003234370Sjasone	if (l)								\
1004234370Sjasone		malloc_mutex_unlock(&ctl_mtx);				\
1005234370Sjasone	return (ret);							\
1006234370Sjasone}
1007234370Sjasone
1008234370Sjasone#define	CTL_RO_CGEN(c, n, v, t)						\
1009234370Sjasonestatic int								\
1010234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1011234370Sjasone    void *newp, size_t newlen)						\
1012234370Sjasone{									\
1013234370Sjasone	int ret;							\
1014234370Sjasone	t oldval;							\
1015234370Sjasone									\
1016234370Sjasone	if ((c) == false)						\
1017234370Sjasone		return (ENOENT);					\
1018234370Sjasone	malloc_mutex_lock(&ctl_mtx);					\
1019234370Sjasone	READONLY();							\
1020245868Sjasone	oldval = (v);							\
1021234370Sjasone	READ(oldval, t);						\
1022234370Sjasone									\
1023234370Sjasone	ret = 0;							\
1024235238Sjasonelabel_return:								\
1025234370Sjasone	malloc_mutex_unlock(&ctl_mtx);					\
1026234370Sjasone	return (ret);							\
1027234370Sjasone}
1028234370Sjasone
1029234370Sjasone#define	CTL_RO_GEN(n, v, t)						\
1030234370Sjasonestatic int								\
1031234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1032234370Sjasone    void *newp, size_t newlen)						\
1033234370Sjasone{									\
1034234370Sjasone	int ret;							\
1035234370Sjasone	t oldval;							\
1036234370Sjasone									\
1037234370Sjasone	malloc_mutex_lock(&ctl_mtx);					\
1038234370Sjasone	READONLY();							\
1039245868Sjasone	oldval = (v);							\
1040234370Sjasone	READ(oldval, t);						\
1041234370Sjasone									\
1042234370Sjasone	ret = 0;							\
1043235238Sjasonelabel_return:								\
1044234370Sjasone	malloc_mutex_unlock(&ctl_mtx);					\
1045234370Sjasone	return (ret);							\
1046234370Sjasone}
1047234370Sjasone
1048234370Sjasone/*
1049234370Sjasone * ctl_mtx is not acquired, under the assumption that no pertinent data will
1050234370Sjasone * mutate during the call.
1051234370Sjasone */
1052234370Sjasone#define	CTL_RO_NL_CGEN(c, n, v, t)					\
1053234370Sjasonestatic int								\
1054234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1055234370Sjasone    void *newp, size_t newlen)						\
1056234370Sjasone{									\
1057234370Sjasone	int ret;							\
1058234370Sjasone	t oldval;							\
1059234370Sjasone									\
1060234370Sjasone	if ((c) == false)						\
1061234370Sjasone		return (ENOENT);					\
1062234370Sjasone	READONLY();							\
1063245868Sjasone	oldval = (v);							\
1064234370Sjasone	READ(oldval, t);						\
1065234370Sjasone									\
1066234370Sjasone	ret = 0;							\
1067235238Sjasonelabel_return:								\
1068234370Sjasone	return (ret);							\
1069234370Sjasone}
1070234370Sjasone
1071234370Sjasone#define	CTL_RO_NL_GEN(n, v, t)						\
1072234370Sjasonestatic int								\
1073234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1074234370Sjasone    void *newp, size_t newlen)						\
1075234370Sjasone{									\
1076234370Sjasone	int ret;							\
1077234370Sjasone	t oldval;							\
1078234370Sjasone									\
1079234370Sjasone	READONLY();							\
1080245868Sjasone	oldval = (v);							\
1081234370Sjasone	READ(oldval, t);						\
1082234370Sjasone									\
1083234370Sjasone	ret = 0;							\
1084235238Sjasonelabel_return:								\
1085234370Sjasone	return (ret);							\
1086234370Sjasone}
1087234370Sjasone
1088234370Sjasone#define	CTL_RO_BOOL_CONFIG_GEN(n)					\
1089234370Sjasonestatic int								\
1090234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1091234370Sjasone    void *newp, size_t newlen)						\
1092234370Sjasone{									\
1093234370Sjasone	int ret;							\
1094234370Sjasone	bool oldval;							\
1095234370Sjasone									\
1096234370Sjasone	READONLY();							\
1097234370Sjasone	oldval = n;							\
1098234370Sjasone	READ(oldval, bool);						\
1099234370Sjasone									\
1100234370Sjasone	ret = 0;							\
1101235238Sjasonelabel_return:								\
1102234370Sjasone	return (ret);							\
1103234370Sjasone}
1104234370Sjasone
1105234370SjasoneCTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
1106234370Sjasone
1107234370Sjasonestatic int
1108234370Sjasoneepoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1109234370Sjasone    void *newp, size_t newlen)
1110234370Sjasone{
1111234370Sjasone	int ret;
1112234370Sjasone	uint64_t newval;
1113234370Sjasone
1114234370Sjasone	malloc_mutex_lock(&ctl_mtx);
1115234370Sjasone	WRITE(newval, uint64_t);
1116235238Sjasone	if (newp != NULL)
1117234370Sjasone		ctl_refresh();
1118234370Sjasone	READ(ctl_epoch, uint64_t);
1119234370Sjasone
1120234370Sjasone	ret = 0;
1121234370Sjasonelabel_return:
1122234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1123234370Sjasone	return (ret);
1124234370Sjasone}
1125234370Sjasone
1126234370Sjasonestatic int
1127234370Sjasonethread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp,
1128234370Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1129234370Sjasone{
1130234370Sjasone	int ret;
1131234370Sjasone	bool oldval;
1132234370Sjasone
1133234370Sjasone	if (config_tcache == false)
1134234370Sjasone		return (ENOENT);
1135234370Sjasone
1136234370Sjasone	oldval = tcache_enabled_get();
1137234370Sjasone	if (newp != NULL) {
1138234370Sjasone		if (newlen != sizeof(bool)) {
1139234370Sjasone			ret = EINVAL;
1140234370Sjasone			goto label_return;
1141234370Sjasone		}
1142234370Sjasone		tcache_enabled_set(*(bool *)newp);
1143234370Sjasone	}
1144234370Sjasone	READ(oldval, bool);
1145234370Sjasone
1146242844Sjasone	ret = 0;
1147234370Sjasonelabel_return:
1148234370Sjasone	return (ret);
1149234370Sjasone}
1150234370Sjasone
1151234370Sjasonestatic int
1152234370Sjasonethread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp,
1153234370Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1154234370Sjasone{
1155234370Sjasone	int ret;
1156234370Sjasone
1157234370Sjasone	if (config_tcache == false)
1158234370Sjasone		return (ENOENT);
1159234370Sjasone
1160235238Sjasone	READONLY();
1161235238Sjasone	WRITEONLY();
1162234370Sjasone
1163234370Sjasone	tcache_flush();
1164234370Sjasone
1165234370Sjasone	ret = 0;
1166234370Sjasonelabel_return:
1167234370Sjasone	return (ret);
1168234370Sjasone}
1169234370Sjasone
1170234370Sjasonestatic int
1171234370Sjasonethread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1172234370Sjasone    void *newp, size_t newlen)
1173234370Sjasone{
1174234370Sjasone	int ret;
1175234370Sjasone	unsigned newind, oldind;
1176234370Sjasone
1177242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1178234370Sjasone	newind = oldind = choose_arena(NULL)->ind;
1179234370Sjasone	WRITE(newind, unsigned);
1180234370Sjasone	READ(oldind, unsigned);
1181234370Sjasone	if (newind != oldind) {
1182234370Sjasone		arena_t *arena;
1183234370Sjasone
1184242844Sjasone		if (newind >= ctl_stats.narenas) {
1185234370Sjasone			/* New arena index is out of range. */
1186234370Sjasone			ret = EFAULT;
1187234370Sjasone			goto label_return;
1188234370Sjasone		}
1189234370Sjasone
1190234370Sjasone		/* Initialize arena if necessary. */
1191234370Sjasone		malloc_mutex_lock(&arenas_lock);
1192234370Sjasone		if ((arena = arenas[newind]) == NULL && (arena =
1193234370Sjasone		    arenas_extend(newind)) == NULL) {
1194234370Sjasone			malloc_mutex_unlock(&arenas_lock);
1195234370Sjasone			ret = EAGAIN;
1196234370Sjasone			goto label_return;
1197234370Sjasone		}
1198234370Sjasone		assert(arena == arenas[newind]);
1199234370Sjasone		arenas[oldind]->nthreads--;
1200234370Sjasone		arenas[newind]->nthreads++;
1201234370Sjasone		malloc_mutex_unlock(&arenas_lock);
1202234370Sjasone
1203234370Sjasone		/* Set new arena association. */
1204234370Sjasone		if (config_tcache) {
1205234370Sjasone			tcache_t *tcache;
1206234370Sjasone			if ((uintptr_t)(tcache = *tcache_tsd_get()) >
1207234370Sjasone			    (uintptr_t)TCACHE_STATE_MAX) {
1208234370Sjasone				tcache_arena_dissociate(tcache);
1209234370Sjasone				tcache_arena_associate(tcache, arena);
1210234370Sjasone			}
1211234370Sjasone		}
1212234370Sjasone		arenas_tsd_set(&arena);
1213234370Sjasone	}
1214234370Sjasone
1215234370Sjasone	ret = 0;
1216234370Sjasonelabel_return:
1217242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1218234370Sjasone	return (ret);
1219234370Sjasone}
1220234370Sjasone
1221234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_allocated,
1222234370Sjasone    thread_allocated_tsd_get()->allocated, uint64_t)
1223234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_allocatedp,
1224234370Sjasone    &thread_allocated_tsd_get()->allocated, uint64_t *)
1225234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_deallocated,
1226234370Sjasone    thread_allocated_tsd_get()->deallocated, uint64_t)
1227234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_deallocatedp,
1228234370Sjasone    &thread_allocated_tsd_get()->deallocated, uint64_t *)
1229234370Sjasone
1230234370Sjasone/******************************************************************************/
1231234370Sjasone
1232234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_debug)
1233234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_dss)
1234234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_fill)
1235234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_lazy_lock)
1236235238SjasoneCTL_RO_BOOL_CONFIG_GEN(config_mremap)
1237234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_munmap)
1238234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof)
1239234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc)
1240234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof_libunwind)
1241234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_stats)
1242234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_tcache)
1243234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_tls)
1244234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_utrace)
1245234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_valgrind)
1246234370SjasoneCTL_RO_BOOL_CONFIG_GEN(config_xmalloc)
1247234370Sjasone
1248234370Sjasone/******************************************************************************/
1249234370Sjasone
1250234370SjasoneCTL_RO_NL_GEN(opt_abort, opt_abort, bool)
1251242844SjasoneCTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
1252234370SjasoneCTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
1253234370SjasoneCTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t)
1254234370SjasoneCTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
1255234370SjasoneCTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
1256234370SjasoneCTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, bool)
1257234370SjasoneCTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
1258234370SjasoneCTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t)
1259234370SjasoneCTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool)
1260234370SjasoneCTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
1261234370SjasoneCTL_RO_NL_CGEN(config_valgrind, opt_valgrind, opt_valgrind, bool)
1262234370SjasoneCTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
1263234370SjasoneCTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
1264234370SjasoneCTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
1265234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
1266234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
1267234370SjasoneCTL_RO_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) /* Mutable. */
1268234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
1269234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
1270234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
1271234543SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
1272234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
1273234370SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
1274234370Sjasone
1275234370Sjasone/******************************************************************************/
1276234370Sjasone
1277242844Sjasone/* ctl_mutex must be held during execution of this function. */
1278242844Sjasonestatic void
1279242844Sjasonearena_purge(unsigned arena_ind)
1280242844Sjasone{
1281242844Sjasone	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
1282242844Sjasone
1283242844Sjasone	malloc_mutex_lock(&arenas_lock);
1284242844Sjasone	memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
1285242844Sjasone	malloc_mutex_unlock(&arenas_lock);
1286242844Sjasone
1287242844Sjasone	if (arena_ind == ctl_stats.narenas) {
1288242844Sjasone		unsigned i;
1289242844Sjasone		for (i = 0; i < ctl_stats.narenas; i++) {
1290242844Sjasone			if (tarenas[i] != NULL)
1291242844Sjasone				arena_purge_all(tarenas[i]);
1292242844Sjasone		}
1293242844Sjasone	} else {
1294242844Sjasone		assert(arena_ind < ctl_stats.narenas);
1295242844Sjasone		if (tarenas[arena_ind] != NULL)
1296242844Sjasone			arena_purge_all(tarenas[arena_ind]);
1297242844Sjasone	}
1298242844Sjasone}
1299242844Sjasone
1300242844Sjasonestatic int
1301242844Sjasonearena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1302242844Sjasone    void *newp, size_t newlen)
1303242844Sjasone{
1304242844Sjasone	int ret;
1305242844Sjasone
1306242844Sjasone	READONLY();
1307242844Sjasone	WRITEONLY();
1308242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1309242844Sjasone	arena_purge(mib[1]);
1310242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1311242844Sjasone
1312242844Sjasone	ret = 0;
1313242844Sjasonelabel_return:
1314242844Sjasone	return (ret);
1315242844Sjasone}
1316242844Sjasone
1317242844Sjasonestatic int
1318242844Sjasonearena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1319242844Sjasone    void *newp, size_t newlen)
1320242844Sjasone{
1321242844Sjasone	int ret, i;
1322242844Sjasone	bool match, err;
1323242844Sjasone	const char *dss;
1324242844Sjasone	unsigned arena_ind = mib[1];
1325242844Sjasone	dss_prec_t dss_prec_old = dss_prec_limit;
1326242844Sjasone	dss_prec_t dss_prec = dss_prec_limit;
1327242844Sjasone
1328242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1329242844Sjasone	WRITE(dss, const char *);
1330242844Sjasone	match = false;
1331242844Sjasone	for (i = 0; i < dss_prec_limit; i++) {
1332242844Sjasone		if (strcmp(dss_prec_names[i], dss) == 0) {
1333242844Sjasone			dss_prec = i;
1334242844Sjasone			match = true;
1335242844Sjasone			break;
1336242844Sjasone		}
1337242844Sjasone	}
1338242844Sjasone	if (match == false) {
1339242844Sjasone		ret = EINVAL;
1340242844Sjasone		goto label_return;
1341242844Sjasone	}
1342242844Sjasone
1343242844Sjasone	if (arena_ind < ctl_stats.narenas) {
1344242844Sjasone		arena_t *arena = arenas[arena_ind];
1345242844Sjasone		if (arena != NULL) {
1346242844Sjasone			dss_prec_old = arena_dss_prec_get(arena);
1347242844Sjasone			arena_dss_prec_set(arena, dss_prec);
1348242844Sjasone			err = false;
1349242844Sjasone		} else
1350242844Sjasone			err = true;
1351242844Sjasone	} else {
1352242844Sjasone		dss_prec_old = chunk_dss_prec_get();
1353242844Sjasone		err = chunk_dss_prec_set(dss_prec);
1354242844Sjasone	}
1355242844Sjasone	dss = dss_prec_names[dss_prec_old];
1356242844Sjasone	READ(dss, const char *);
1357242844Sjasone	if (err) {
1358242844Sjasone		ret = EFAULT;
1359242844Sjasone		goto label_return;
1360242844Sjasone	}
1361242844Sjasone
1362242844Sjasone	ret = 0;
1363242844Sjasonelabel_return:
1364242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1365242844Sjasone	return (ret);
1366242844Sjasone}
1367242844Sjasone
1368242844Sjasonestatic const ctl_named_node_t *
1369242844Sjasonearena_i_index(const size_t *mib, size_t miblen, size_t i)
1370242844Sjasone{
1371242844Sjasone	const ctl_named_node_t * ret;
1372242844Sjasone
1373242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1374242844Sjasone	if (i > ctl_stats.narenas) {
1375242844Sjasone		ret = NULL;
1376242844Sjasone		goto label_return;
1377242844Sjasone	}
1378242844Sjasone
1379242844Sjasone	ret = super_arena_i_node;
1380242844Sjasonelabel_return:
1381242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1382242844Sjasone	return (ret);
1383242844Sjasone}
1384242844Sjasone
1385242844Sjasone
1386242844Sjasone/******************************************************************************/
1387242844Sjasone
1388234370SjasoneCTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
1389234370SjasoneCTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
1390234370SjasoneCTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
1391242844Sjasonestatic const ctl_named_node_t *
1392234370Sjasonearenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
1393234370Sjasone{
1394234370Sjasone
1395234370Sjasone	if (i > NBINS)
1396234370Sjasone		return (NULL);
1397234370Sjasone	return (super_arenas_bin_i_node);
1398234370Sjasone}
1399234370Sjasone
1400234370SjasoneCTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << LG_PAGE), size_t)
1401242844Sjasonestatic const ctl_named_node_t *
1402234370Sjasonearenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
1403234370Sjasone{
1404234370Sjasone
1405234370Sjasone	if (i > nlclasses)
1406234370Sjasone		return (NULL);
1407234370Sjasone	return (super_arenas_lrun_i_node);
1408234370Sjasone}
1409234370Sjasone
1410242844Sjasonestatic int
1411242844Sjasonearenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp,
1412242844Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1413242844Sjasone{
1414242844Sjasone	int ret;
1415242844Sjasone	unsigned narenas;
1416234370Sjasone
1417242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1418242844Sjasone	READONLY();
1419242844Sjasone	if (*oldlenp != sizeof(unsigned)) {
1420242844Sjasone		ret = EINVAL;
1421242844Sjasone		goto label_return;
1422242844Sjasone	}
1423242844Sjasone	narenas = ctl_stats.narenas;
1424242844Sjasone	READ(narenas, unsigned);
1425242844Sjasone
1426242844Sjasone	ret = 0;
1427242844Sjasonelabel_return:
1428242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1429242844Sjasone	return (ret);
1430242844Sjasone}
1431242844Sjasone
1432234370Sjasonestatic int
1433234370Sjasonearenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
1434234370Sjasone    size_t *oldlenp, void *newp, size_t newlen)
1435234370Sjasone{
1436234370Sjasone	int ret;
1437234370Sjasone	unsigned nread, i;
1438234370Sjasone
1439234370Sjasone	malloc_mutex_lock(&ctl_mtx);
1440234370Sjasone	READONLY();
1441242844Sjasone	if (*oldlenp != ctl_stats.narenas * sizeof(bool)) {
1442234370Sjasone		ret = EINVAL;
1443242844Sjasone		nread = (*oldlenp < ctl_stats.narenas * sizeof(bool))
1444242844Sjasone		    ? (*oldlenp / sizeof(bool)) : ctl_stats.narenas;
1445234370Sjasone	} else {
1446234370Sjasone		ret = 0;
1447242844Sjasone		nread = ctl_stats.narenas;
1448234370Sjasone	}
1449234370Sjasone
1450234370Sjasone	for (i = 0; i < nread; i++)
1451234370Sjasone		((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
1452234370Sjasone
1453234370Sjasonelabel_return:
1454234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1455234370Sjasone	return (ret);
1456234370Sjasone}
1457234370Sjasone
1458234370SjasoneCTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
1459234370SjasoneCTL_RO_NL_GEN(arenas_page, PAGE, size_t)
1460234370SjasoneCTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t)
1461234370SjasoneCTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
1462234370SjasoneCTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned)
1463234370SjasoneCTL_RO_NL_GEN(arenas_nlruns, nlclasses, size_t)
1464234370Sjasone
1465234370Sjasonestatic int
1466234370Sjasonearenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1467234370Sjasone    void *newp, size_t newlen)
1468234370Sjasone{
1469234370Sjasone	int ret;
1470242844Sjasone	unsigned arena_ind;
1471234370Sjasone
1472242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1473234370Sjasone	WRITEONLY();
1474242844Sjasone	arena_ind = UINT_MAX;
1475242844Sjasone	WRITE(arena_ind, unsigned);
1476242844Sjasone	if (newp != NULL && arena_ind >= ctl_stats.narenas)
1477234370Sjasone		ret = EFAULT;
1478242844Sjasone	else {
1479242844Sjasone		if (arena_ind == UINT_MAX)
1480242844Sjasone			arena_ind = ctl_stats.narenas;
1481242844Sjasone		arena_purge(arena_ind);
1482242844Sjasone		ret = 0;
1483242844Sjasone	}
1484234370Sjasone
1485242844Sjasonelabel_return:
1486242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1487242844Sjasone	return (ret);
1488242844Sjasone}
1489234370Sjasone
1490242844Sjasonestatic int
1491242844Sjasonearenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1492242844Sjasone    void *newp, size_t newlen)
1493242844Sjasone{
1494242844Sjasone	int ret;
1495245868Sjasone	unsigned narenas;
1496242844Sjasone
1497242844Sjasone	malloc_mutex_lock(&ctl_mtx);
1498242844Sjasone	READONLY();
1499242844Sjasone	if (ctl_grow()) {
1500242844Sjasone		ret = EAGAIN;
1501242844Sjasone		goto label_return;
1502234370Sjasone	}
1503245868Sjasone	narenas = ctl_stats.narenas - 1;
1504245868Sjasone	READ(narenas, unsigned);
1505234370Sjasone
1506234370Sjasone	ret = 0;
1507234370Sjasonelabel_return:
1508242844Sjasone	malloc_mutex_unlock(&ctl_mtx);
1509234370Sjasone	return (ret);
1510234370Sjasone}
1511234370Sjasone
1512234370Sjasone/******************************************************************************/
1513234370Sjasone
1514234370Sjasonestatic int
1515234370Sjasoneprof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1516234370Sjasone    void *newp, size_t newlen)
1517234370Sjasone{
1518234370Sjasone	int ret;
1519234370Sjasone	bool oldval;
1520234370Sjasone
1521234370Sjasone	if (config_prof == false)
1522234370Sjasone		return (ENOENT);
1523234370Sjasone
1524234370Sjasone	malloc_mutex_lock(&ctl_mtx); /* Protect opt_prof_active. */
1525234370Sjasone	oldval = opt_prof_active;
1526234370Sjasone	if (newp != NULL) {
1527234370Sjasone		/*
1528234370Sjasone		 * The memory barriers will tend to make opt_prof_active
1529234370Sjasone		 * propagate faster on systems with weak memory ordering.
1530234370Sjasone		 */
1531234370Sjasone		mb_write();
1532234370Sjasone		WRITE(opt_prof_active, bool);
1533234370Sjasone		mb_write();
1534234370Sjasone	}
1535234370Sjasone	READ(oldval, bool);
1536234370Sjasone
1537234370Sjasone	ret = 0;
1538234370Sjasonelabel_return:
1539234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1540234370Sjasone	return (ret);
1541234370Sjasone}
1542234370Sjasone
1543234370Sjasonestatic int
1544234370Sjasoneprof_dump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1545234370Sjasone    void *newp, size_t newlen)
1546234370Sjasone{
1547234370Sjasone	int ret;
1548234370Sjasone	const char *filename = NULL;
1549234370Sjasone
1550234370Sjasone	if (config_prof == false)
1551234370Sjasone		return (ENOENT);
1552234370Sjasone
1553234370Sjasone	WRITEONLY();
1554234370Sjasone	WRITE(filename, const char *);
1555234370Sjasone
1556234370Sjasone	if (prof_mdump(filename)) {
1557234370Sjasone		ret = EFAULT;
1558234370Sjasone		goto label_return;
1559234370Sjasone	}
1560234370Sjasone
1561234370Sjasone	ret = 0;
1562234370Sjasonelabel_return:
1563234370Sjasone	return (ret);
1564234370Sjasone}
1565234370Sjasone
1566234370SjasoneCTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
1567234370Sjasone
1568234370Sjasone/******************************************************************************/
1569234370Sjasone
1570234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_current, ctl_stats.chunks.current,
1571234370Sjasone    size_t)
1572234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_total, ctl_stats.chunks.total, uint64_t)
1573234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_high, ctl_stats.chunks.high, size_t)
1574234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_allocated, huge_allocated, size_t)
1575234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_nmalloc, huge_nmalloc, uint64_t)
1576234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_ndalloc, huge_ndalloc, uint64_t)
1577234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
1578234370Sjasone    ctl_stats.arenas[mib[2]].allocated_small, size_t)
1579234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
1580234370Sjasone    ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t)
1581234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
1582234370Sjasone    ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t)
1583234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
1584234370Sjasone    ctl_stats.arenas[mib[2]].nrequests_small, uint64_t)
1585234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
1586234370Sjasone    ctl_stats.arenas[mib[2]].astats.allocated_large, size_t)
1587234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
1588234370Sjasone    ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t)
1589234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
1590234370Sjasone    ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t)
1591234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
1592234370Sjasone    ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t)
1593234370Sjasone
1594234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_allocated,
1595234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].allocated, size_t)
1596234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
1597234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t)
1598234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
1599234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t)
1600234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
1601234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t)
1602234370SjasoneCTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills,
1603234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t)
1604234370SjasoneCTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes,
1605234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t)
1606234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns,
1607234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t)
1608234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns,
1609234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t)
1610234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns,
1611234370Sjasone    ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t)
1612234370Sjasone
1613242844Sjasonestatic const ctl_named_node_t *
1614234370Sjasonestats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j)
1615234370Sjasone{
1616234370Sjasone
1617234370Sjasone	if (j > NBINS)
1618234370Sjasone		return (NULL);
1619234370Sjasone	return (super_stats_arenas_i_bins_j_node);
1620234370Sjasone}
1621234370Sjasone
1622234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc,
1623234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t)
1624234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc,
1625234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t)
1626234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests,
1627234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t)
1628234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns,
1629234370Sjasone    ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t)
1630234370Sjasone
1631242844Sjasonestatic const ctl_named_node_t *
1632234370Sjasonestats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
1633234370Sjasone{
1634234370Sjasone
1635234370Sjasone	if (j > nlclasses)
1636234370Sjasone		return (NULL);
1637234370Sjasone	return (super_stats_arenas_i_lruns_j_node);
1638234370Sjasone}
1639234370Sjasone
1640234370SjasoneCTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
1641242844SjasoneCTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *)
1642234370SjasoneCTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
1643234370SjasoneCTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
1644234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
1645234370Sjasone    ctl_stats.arenas[mib[2]].astats.mapped, size_t)
1646234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_npurge,
1647234370Sjasone    ctl_stats.arenas[mib[2]].astats.npurge, uint64_t)
1648234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise,
1649234370Sjasone    ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t)
1650234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_purged,
1651234370Sjasone    ctl_stats.arenas[mib[2]].astats.purged, uint64_t)
1652234370Sjasone
1653242844Sjasonestatic const ctl_named_node_t *
1654234370Sjasonestats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
1655234370Sjasone{
1656235238Sjasone	const ctl_named_node_t * ret;
1657234370Sjasone
1658234370Sjasone	malloc_mutex_lock(&ctl_mtx);
1659242844Sjasone	if (i > ctl_stats.narenas || ctl_stats.arenas[i].initialized == false) {
1660234370Sjasone		ret = NULL;
1661234370Sjasone		goto label_return;
1662234370Sjasone	}
1663234370Sjasone
1664234370Sjasone	ret = super_stats_arenas_i_node;
1665234370Sjasonelabel_return:
1666234370Sjasone	malloc_mutex_unlock(&ctl_mtx);
1667234370Sjasone	return (ret);
1668234370Sjasone}
1669234370Sjasone
1670234370SjasoneCTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *)
1671234370SjasoneCTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t)
1672234370SjasoneCTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t)
1673234370SjasoneCTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t)
1674