ctl.c revision 286866
1#define	JEMALLOC_CTL_C_
2#include "jemalloc/internal/jemalloc_internal.h"
3
4/******************************************************************************/
5/* Data. */
6
7/*
8 * ctl_mtx protects the following:
9 * - ctl_stats.*
10 */
11static malloc_mutex_t	ctl_mtx;
12static bool		ctl_initialized;
13static uint64_t		ctl_epoch;
14static ctl_stats_t	ctl_stats;
15
16/******************************************************************************/
17/* Helpers for named and indexed nodes. */
18
19JEMALLOC_INLINE_C const ctl_named_node_t *
20ctl_named_node(const ctl_node_t *node)
21{
22
23	return ((node->named) ? (const ctl_named_node_t *)node : NULL);
24}
25
26JEMALLOC_INLINE_C const ctl_named_node_t *
27ctl_named_children(const ctl_named_node_t *node, int index)
28{
29	const ctl_named_node_t *children = ctl_named_node(node->children);
30
31	return (children ? &children[index] : NULL);
32}
33
34JEMALLOC_INLINE_C const ctl_indexed_node_t *
35ctl_indexed_node(const ctl_node_t *node)
36{
37
38	return (!node->named ? (const ctl_indexed_node_t *)node : NULL);
39}
40
41/******************************************************************************/
42/* Function prototypes for non-inline static functions. */
43
44#define	CTL_PROTO(n)							\
45static int	n##_ctl(const size_t *mib, size_t miblen, void *oldp,	\
46    size_t *oldlenp, void *newp, size_t newlen);
47
48#define	INDEX_PROTO(n)							\
49static const ctl_named_node_t	*n##_index(const size_t *mib,		\
50    size_t miblen, size_t i);
51
52static bool	ctl_arena_init(ctl_arena_stats_t *astats);
53static void	ctl_arena_clear(ctl_arena_stats_t *astats);
54static void	ctl_arena_stats_amerge(ctl_arena_stats_t *cstats,
55    arena_t *arena);
56static void	ctl_arena_stats_smerge(ctl_arena_stats_t *sstats,
57    ctl_arena_stats_t *astats);
58static void	ctl_arena_refresh(arena_t *arena, unsigned i);
59static bool	ctl_grow(void);
60static void	ctl_refresh(void);
61static bool	ctl_init(void);
62static int	ctl_lookup(const char *name, ctl_node_t const **nodesp,
63    size_t *mibp, size_t *depthp);
64
65CTL_PROTO(version)
66CTL_PROTO(epoch)
67CTL_PROTO(thread_tcache_enabled)
68CTL_PROTO(thread_tcache_flush)
69CTL_PROTO(thread_prof_name)
70CTL_PROTO(thread_prof_active)
71CTL_PROTO(thread_arena)
72CTL_PROTO(thread_allocated)
73CTL_PROTO(thread_allocatedp)
74CTL_PROTO(thread_deallocated)
75CTL_PROTO(thread_deallocatedp)
76CTL_PROTO(config_cache_oblivious)
77CTL_PROTO(config_debug)
78CTL_PROTO(config_fill)
79CTL_PROTO(config_lazy_lock)
80CTL_PROTO(config_munmap)
81CTL_PROTO(config_prof)
82CTL_PROTO(config_prof_libgcc)
83CTL_PROTO(config_prof_libunwind)
84CTL_PROTO(config_stats)
85CTL_PROTO(config_tcache)
86CTL_PROTO(config_tls)
87CTL_PROTO(config_utrace)
88CTL_PROTO(config_valgrind)
89CTL_PROTO(config_xmalloc)
90CTL_PROTO(opt_abort)
91CTL_PROTO(opt_dss)
92CTL_PROTO(opt_lg_chunk)
93CTL_PROTO(opt_narenas)
94CTL_PROTO(opt_lg_dirty_mult)
95CTL_PROTO(opt_stats_print)
96CTL_PROTO(opt_junk)
97CTL_PROTO(opt_zero)
98CTL_PROTO(opt_quarantine)
99CTL_PROTO(opt_redzone)
100CTL_PROTO(opt_utrace)
101CTL_PROTO(opt_xmalloc)
102CTL_PROTO(opt_tcache)
103CTL_PROTO(opt_lg_tcache_max)
104CTL_PROTO(opt_prof)
105CTL_PROTO(opt_prof_prefix)
106CTL_PROTO(opt_prof_active)
107CTL_PROTO(opt_prof_thread_active_init)
108CTL_PROTO(opt_lg_prof_sample)
109CTL_PROTO(opt_lg_prof_interval)
110CTL_PROTO(opt_prof_gdump)
111CTL_PROTO(opt_prof_final)
112CTL_PROTO(opt_prof_leak)
113CTL_PROTO(opt_prof_accum)
114CTL_PROTO(tcache_create)
115CTL_PROTO(tcache_flush)
116CTL_PROTO(tcache_destroy)
117CTL_PROTO(arena_i_purge)
118static void	arena_purge(unsigned arena_ind);
119CTL_PROTO(arena_i_dss)
120CTL_PROTO(arena_i_lg_dirty_mult)
121CTL_PROTO(arena_i_chunk_hooks)
122INDEX_PROTO(arena_i)
123CTL_PROTO(arenas_bin_i_size)
124CTL_PROTO(arenas_bin_i_nregs)
125CTL_PROTO(arenas_bin_i_run_size)
126INDEX_PROTO(arenas_bin_i)
127CTL_PROTO(arenas_lrun_i_size)
128INDEX_PROTO(arenas_lrun_i)
129CTL_PROTO(arenas_hchunk_i_size)
130INDEX_PROTO(arenas_hchunk_i)
131CTL_PROTO(arenas_narenas)
132CTL_PROTO(arenas_initialized)
133CTL_PROTO(arenas_lg_dirty_mult)
134CTL_PROTO(arenas_quantum)
135CTL_PROTO(arenas_page)
136CTL_PROTO(arenas_tcache_max)
137CTL_PROTO(arenas_nbins)
138CTL_PROTO(arenas_nhbins)
139CTL_PROTO(arenas_nlruns)
140CTL_PROTO(arenas_nhchunks)
141CTL_PROTO(arenas_extend)
142CTL_PROTO(prof_thread_active_init)
143CTL_PROTO(prof_active)
144CTL_PROTO(prof_dump)
145CTL_PROTO(prof_gdump)
146CTL_PROTO(prof_reset)
147CTL_PROTO(prof_interval)
148CTL_PROTO(lg_prof_sample)
149CTL_PROTO(stats_arenas_i_small_allocated)
150CTL_PROTO(stats_arenas_i_small_nmalloc)
151CTL_PROTO(stats_arenas_i_small_ndalloc)
152CTL_PROTO(stats_arenas_i_small_nrequests)
153CTL_PROTO(stats_arenas_i_large_allocated)
154CTL_PROTO(stats_arenas_i_large_nmalloc)
155CTL_PROTO(stats_arenas_i_large_ndalloc)
156CTL_PROTO(stats_arenas_i_large_nrequests)
157CTL_PROTO(stats_arenas_i_huge_allocated)
158CTL_PROTO(stats_arenas_i_huge_nmalloc)
159CTL_PROTO(stats_arenas_i_huge_ndalloc)
160CTL_PROTO(stats_arenas_i_huge_nrequests)
161CTL_PROTO(stats_arenas_i_bins_j_nmalloc)
162CTL_PROTO(stats_arenas_i_bins_j_ndalloc)
163CTL_PROTO(stats_arenas_i_bins_j_nrequests)
164CTL_PROTO(stats_arenas_i_bins_j_curregs)
165CTL_PROTO(stats_arenas_i_bins_j_nfills)
166CTL_PROTO(stats_arenas_i_bins_j_nflushes)
167CTL_PROTO(stats_arenas_i_bins_j_nruns)
168CTL_PROTO(stats_arenas_i_bins_j_nreruns)
169CTL_PROTO(stats_arenas_i_bins_j_curruns)
170INDEX_PROTO(stats_arenas_i_bins_j)
171CTL_PROTO(stats_arenas_i_lruns_j_nmalloc)
172CTL_PROTO(stats_arenas_i_lruns_j_ndalloc)
173CTL_PROTO(stats_arenas_i_lruns_j_nrequests)
174CTL_PROTO(stats_arenas_i_lruns_j_curruns)
175INDEX_PROTO(stats_arenas_i_lruns_j)
176CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc)
177CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc)
178CTL_PROTO(stats_arenas_i_hchunks_j_nrequests)
179CTL_PROTO(stats_arenas_i_hchunks_j_curhchunks)
180INDEX_PROTO(stats_arenas_i_hchunks_j)
181CTL_PROTO(stats_arenas_i_nthreads)
182CTL_PROTO(stats_arenas_i_dss)
183CTL_PROTO(stats_arenas_i_lg_dirty_mult)
184CTL_PROTO(stats_arenas_i_pactive)
185CTL_PROTO(stats_arenas_i_pdirty)
186CTL_PROTO(stats_arenas_i_mapped)
187CTL_PROTO(stats_arenas_i_npurge)
188CTL_PROTO(stats_arenas_i_nmadvise)
189CTL_PROTO(stats_arenas_i_purged)
190CTL_PROTO(stats_arenas_i_metadata_mapped)
191CTL_PROTO(stats_arenas_i_metadata_allocated)
192INDEX_PROTO(stats_arenas_i)
193CTL_PROTO(stats_cactive)
194CTL_PROTO(stats_allocated)
195CTL_PROTO(stats_active)
196CTL_PROTO(stats_metadata)
197CTL_PROTO(stats_resident)
198CTL_PROTO(stats_mapped)
199
200/******************************************************************************/
201/* mallctl tree. */
202
203/* Maximum tree depth. */
204#define	CTL_MAX_DEPTH	6
205
206#define	NAME(n)	{true},	n
207#define	CHILD(t, c)							\
208	sizeof(c##_node) / sizeof(ctl_##t##_node_t),			\
209	(ctl_node_t *)c##_node,						\
210	NULL
211#define	CTL(c)	0, NULL, c##_ctl
212
213/*
214 * Only handles internal indexed nodes, since there are currently no external
215 * ones.
216 */
217#define	INDEX(i)	{false},	i##_index
218
219static const ctl_named_node_t	thread_tcache_node[] = {
220	{NAME("enabled"),	CTL(thread_tcache_enabled)},
221	{NAME("flush"),		CTL(thread_tcache_flush)}
222};
223
224static const ctl_named_node_t	thread_prof_node[] = {
225	{NAME("name"),		CTL(thread_prof_name)},
226	{NAME("active"),	CTL(thread_prof_active)}
227};
228
229static const ctl_named_node_t	thread_node[] = {
230	{NAME("arena"),		CTL(thread_arena)},
231	{NAME("allocated"),	CTL(thread_allocated)},
232	{NAME("allocatedp"),	CTL(thread_allocatedp)},
233	{NAME("deallocated"),	CTL(thread_deallocated)},
234	{NAME("deallocatedp"),	CTL(thread_deallocatedp)},
235	{NAME("tcache"),	CHILD(named, thread_tcache)},
236	{NAME("prof"),		CHILD(named, thread_prof)}
237};
238
239static const ctl_named_node_t	config_node[] = {
240	{NAME("cache_oblivious"), CTL(config_cache_oblivious)},
241	{NAME("debug"),		CTL(config_debug)},
242	{NAME("fill"),		CTL(config_fill)},
243	{NAME("lazy_lock"),	CTL(config_lazy_lock)},
244	{NAME("munmap"),	CTL(config_munmap)},
245	{NAME("prof"),		CTL(config_prof)},
246	{NAME("prof_libgcc"),	CTL(config_prof_libgcc)},
247	{NAME("prof_libunwind"), CTL(config_prof_libunwind)},
248	{NAME("stats"),		CTL(config_stats)},
249	{NAME("tcache"),	CTL(config_tcache)},
250	{NAME("tls"),		CTL(config_tls)},
251	{NAME("utrace"),	CTL(config_utrace)},
252	{NAME("valgrind"),	CTL(config_valgrind)},
253	{NAME("xmalloc"),	CTL(config_xmalloc)}
254};
255
256static const ctl_named_node_t opt_node[] = {
257	{NAME("abort"),		CTL(opt_abort)},
258	{NAME("dss"),		CTL(opt_dss)},
259	{NAME("lg_chunk"),	CTL(opt_lg_chunk)},
260	{NAME("narenas"),	CTL(opt_narenas)},
261	{NAME("lg_dirty_mult"),	CTL(opt_lg_dirty_mult)},
262	{NAME("stats_print"),	CTL(opt_stats_print)},
263	{NAME("junk"),		CTL(opt_junk)},
264	{NAME("zero"),		CTL(opt_zero)},
265	{NAME("quarantine"),	CTL(opt_quarantine)},
266	{NAME("redzone"),	CTL(opt_redzone)},
267	{NAME("utrace"),	CTL(opt_utrace)},
268	{NAME("xmalloc"),	CTL(opt_xmalloc)},
269	{NAME("tcache"),	CTL(opt_tcache)},
270	{NAME("lg_tcache_max"),	CTL(opt_lg_tcache_max)},
271	{NAME("prof"),		CTL(opt_prof)},
272	{NAME("prof_prefix"),	CTL(opt_prof_prefix)},
273	{NAME("prof_active"),	CTL(opt_prof_active)},
274	{NAME("prof_thread_active_init"), CTL(opt_prof_thread_active_init)},
275	{NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)},
276	{NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)},
277	{NAME("prof_gdump"),	CTL(opt_prof_gdump)},
278	{NAME("prof_final"),	CTL(opt_prof_final)},
279	{NAME("prof_leak"),	CTL(opt_prof_leak)},
280	{NAME("prof_accum"),	CTL(opt_prof_accum)}
281};
282
283static const ctl_named_node_t	tcache_node[] = {
284	{NAME("create"),	CTL(tcache_create)},
285	{NAME("flush"),		CTL(tcache_flush)},
286	{NAME("destroy"),	CTL(tcache_destroy)}
287};
288
289static const ctl_named_node_t arena_i_node[] = {
290	{NAME("purge"),		CTL(arena_i_purge)},
291	{NAME("dss"),		CTL(arena_i_dss)},
292	{NAME("lg_dirty_mult"),	CTL(arena_i_lg_dirty_mult)},
293	{NAME("chunk_hooks"),	CTL(arena_i_chunk_hooks)}
294};
295static const ctl_named_node_t super_arena_i_node[] = {
296	{NAME(""),		CHILD(named, arena_i)}
297};
298
299static const ctl_indexed_node_t arena_node[] = {
300	{INDEX(arena_i)}
301};
302
303static const ctl_named_node_t arenas_bin_i_node[] = {
304	{NAME("size"),		CTL(arenas_bin_i_size)},
305	{NAME("nregs"),		CTL(arenas_bin_i_nregs)},
306	{NAME("run_size"),	CTL(arenas_bin_i_run_size)}
307};
308static const ctl_named_node_t super_arenas_bin_i_node[] = {
309	{NAME(""),		CHILD(named, arenas_bin_i)}
310};
311
312static const ctl_indexed_node_t arenas_bin_node[] = {
313	{INDEX(arenas_bin_i)}
314};
315
316static const ctl_named_node_t arenas_lrun_i_node[] = {
317	{NAME("size"),		CTL(arenas_lrun_i_size)}
318};
319static const ctl_named_node_t super_arenas_lrun_i_node[] = {
320	{NAME(""),		CHILD(named, arenas_lrun_i)}
321};
322
323static const ctl_indexed_node_t arenas_lrun_node[] = {
324	{INDEX(arenas_lrun_i)}
325};
326
327static const ctl_named_node_t arenas_hchunk_i_node[] = {
328	{NAME("size"),		CTL(arenas_hchunk_i_size)}
329};
330static const ctl_named_node_t super_arenas_hchunk_i_node[] = {
331	{NAME(""),		CHILD(named, arenas_hchunk_i)}
332};
333
334static const ctl_indexed_node_t arenas_hchunk_node[] = {
335	{INDEX(arenas_hchunk_i)}
336};
337
338static const ctl_named_node_t arenas_node[] = {
339	{NAME("narenas"),	CTL(arenas_narenas)},
340	{NAME("initialized"),	CTL(arenas_initialized)},
341	{NAME("lg_dirty_mult"),	CTL(arenas_lg_dirty_mult)},
342	{NAME("quantum"),	CTL(arenas_quantum)},
343	{NAME("page"),		CTL(arenas_page)},
344	{NAME("tcache_max"),	CTL(arenas_tcache_max)},
345	{NAME("nbins"),		CTL(arenas_nbins)},
346	{NAME("nhbins"),	CTL(arenas_nhbins)},
347	{NAME("bin"),		CHILD(indexed, arenas_bin)},
348	{NAME("nlruns"),	CTL(arenas_nlruns)},
349	{NAME("lrun"),		CHILD(indexed, arenas_lrun)},
350	{NAME("nhchunks"),	CTL(arenas_nhchunks)},
351	{NAME("hchunk"),	CHILD(indexed, arenas_hchunk)},
352	{NAME("extend"),	CTL(arenas_extend)}
353};
354
355static const ctl_named_node_t	prof_node[] = {
356	{NAME("thread_active_init"), CTL(prof_thread_active_init)},
357	{NAME("active"),	CTL(prof_active)},
358	{NAME("dump"),		CTL(prof_dump)},
359	{NAME("gdump"),		CTL(prof_gdump)},
360	{NAME("reset"),		CTL(prof_reset)},
361	{NAME("interval"),	CTL(prof_interval)},
362	{NAME("lg_sample"),	CTL(lg_prof_sample)}
363};
364
365static const ctl_named_node_t stats_arenas_i_metadata_node[] = {
366	{NAME("mapped"),	CTL(stats_arenas_i_metadata_mapped)},
367	{NAME("allocated"),	CTL(stats_arenas_i_metadata_allocated)}
368};
369
370static const ctl_named_node_t stats_arenas_i_small_node[] = {
371	{NAME("allocated"),	CTL(stats_arenas_i_small_allocated)},
372	{NAME("nmalloc"),	CTL(stats_arenas_i_small_nmalloc)},
373	{NAME("ndalloc"),	CTL(stats_arenas_i_small_ndalloc)},
374	{NAME("nrequests"),	CTL(stats_arenas_i_small_nrequests)}
375};
376
377static const ctl_named_node_t stats_arenas_i_large_node[] = {
378	{NAME("allocated"),	CTL(stats_arenas_i_large_allocated)},
379	{NAME("nmalloc"),	CTL(stats_arenas_i_large_nmalloc)},
380	{NAME("ndalloc"),	CTL(stats_arenas_i_large_ndalloc)},
381	{NAME("nrequests"),	CTL(stats_arenas_i_large_nrequests)}
382};
383
384static const ctl_named_node_t stats_arenas_i_huge_node[] = {
385	{NAME("allocated"),	CTL(stats_arenas_i_huge_allocated)},
386	{NAME("nmalloc"),	CTL(stats_arenas_i_huge_nmalloc)},
387	{NAME("ndalloc"),	CTL(stats_arenas_i_huge_ndalloc)},
388	{NAME("nrequests"),	CTL(stats_arenas_i_huge_nrequests)}
389};
390
391static const ctl_named_node_t stats_arenas_i_bins_j_node[] = {
392	{NAME("nmalloc"),	CTL(stats_arenas_i_bins_j_nmalloc)},
393	{NAME("ndalloc"),	CTL(stats_arenas_i_bins_j_ndalloc)},
394	{NAME("nrequests"),	CTL(stats_arenas_i_bins_j_nrequests)},
395	{NAME("curregs"),	CTL(stats_arenas_i_bins_j_curregs)},
396	{NAME("nfills"),	CTL(stats_arenas_i_bins_j_nfills)},
397	{NAME("nflushes"),	CTL(stats_arenas_i_bins_j_nflushes)},
398	{NAME("nruns"),		CTL(stats_arenas_i_bins_j_nruns)},
399	{NAME("nreruns"),	CTL(stats_arenas_i_bins_j_nreruns)},
400	{NAME("curruns"),	CTL(stats_arenas_i_bins_j_curruns)}
401};
402static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = {
403	{NAME(""),		CHILD(named, stats_arenas_i_bins_j)}
404};
405
406static const ctl_indexed_node_t stats_arenas_i_bins_node[] = {
407	{INDEX(stats_arenas_i_bins_j)}
408};
409
410static const ctl_named_node_t stats_arenas_i_lruns_j_node[] = {
411	{NAME("nmalloc"),	CTL(stats_arenas_i_lruns_j_nmalloc)},
412	{NAME("ndalloc"),	CTL(stats_arenas_i_lruns_j_ndalloc)},
413	{NAME("nrequests"),	CTL(stats_arenas_i_lruns_j_nrequests)},
414	{NAME("curruns"),	CTL(stats_arenas_i_lruns_j_curruns)}
415};
416static const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = {
417	{NAME(""),		CHILD(named, stats_arenas_i_lruns_j)}
418};
419
420static const ctl_indexed_node_t stats_arenas_i_lruns_node[] = {
421	{INDEX(stats_arenas_i_lruns_j)}
422};
423
424static const ctl_named_node_t stats_arenas_i_hchunks_j_node[] = {
425	{NAME("nmalloc"),	CTL(stats_arenas_i_hchunks_j_nmalloc)},
426	{NAME("ndalloc"),	CTL(stats_arenas_i_hchunks_j_ndalloc)},
427	{NAME("nrequests"),	CTL(stats_arenas_i_hchunks_j_nrequests)},
428	{NAME("curhchunks"),	CTL(stats_arenas_i_hchunks_j_curhchunks)}
429};
430static const ctl_named_node_t super_stats_arenas_i_hchunks_j_node[] = {
431	{NAME(""),		CHILD(named, stats_arenas_i_hchunks_j)}
432};
433
434static const ctl_indexed_node_t stats_arenas_i_hchunks_node[] = {
435	{INDEX(stats_arenas_i_hchunks_j)}
436};
437
438static const ctl_named_node_t stats_arenas_i_node[] = {
439	{NAME("nthreads"),	CTL(stats_arenas_i_nthreads)},
440	{NAME("dss"),		CTL(stats_arenas_i_dss)},
441	{NAME("lg_dirty_mult"),	CTL(stats_arenas_i_lg_dirty_mult)},
442	{NAME("pactive"),	CTL(stats_arenas_i_pactive)},
443	{NAME("pdirty"),	CTL(stats_arenas_i_pdirty)},
444	{NAME("mapped"),	CTL(stats_arenas_i_mapped)},
445	{NAME("npurge"),	CTL(stats_arenas_i_npurge)},
446	{NAME("nmadvise"),	CTL(stats_arenas_i_nmadvise)},
447	{NAME("purged"),	CTL(stats_arenas_i_purged)},
448	{NAME("metadata"),	CHILD(named, stats_arenas_i_metadata)},
449	{NAME("small"),		CHILD(named, stats_arenas_i_small)},
450	{NAME("large"),		CHILD(named, stats_arenas_i_large)},
451	{NAME("huge"),		CHILD(named, stats_arenas_i_huge)},
452	{NAME("bins"),		CHILD(indexed, stats_arenas_i_bins)},
453	{NAME("lruns"),		CHILD(indexed, stats_arenas_i_lruns)},
454	{NAME("hchunks"),	CHILD(indexed, stats_arenas_i_hchunks)}
455};
456static const ctl_named_node_t super_stats_arenas_i_node[] = {
457	{NAME(""),		CHILD(named, stats_arenas_i)}
458};
459
460static const ctl_indexed_node_t stats_arenas_node[] = {
461	{INDEX(stats_arenas_i)}
462};
463
464static const ctl_named_node_t stats_node[] = {
465	{NAME("cactive"),	CTL(stats_cactive)},
466	{NAME("allocated"),	CTL(stats_allocated)},
467	{NAME("active"),	CTL(stats_active)},
468	{NAME("metadata"),	CTL(stats_metadata)},
469	{NAME("resident"),	CTL(stats_resident)},
470	{NAME("mapped"),	CTL(stats_mapped)},
471	{NAME("arenas"),	CHILD(indexed, stats_arenas)}
472};
473
474static const ctl_named_node_t	root_node[] = {
475	{NAME("version"),	CTL(version)},
476	{NAME("epoch"),		CTL(epoch)},
477	{NAME("thread"),	CHILD(named, thread)},
478	{NAME("config"),	CHILD(named, config)},
479	{NAME("opt"),		CHILD(named, opt)},
480	{NAME("tcache"),	CHILD(named, tcache)},
481	{NAME("arena"),		CHILD(indexed, arena)},
482	{NAME("arenas"),	CHILD(named, arenas)},
483	{NAME("prof"),		CHILD(named, prof)},
484	{NAME("stats"),		CHILD(named, stats)}
485};
486static const ctl_named_node_t super_root_node[] = {
487	{NAME(""),		CHILD(named, root)}
488};
489
490#undef NAME
491#undef CHILD
492#undef CTL
493#undef INDEX
494
495/******************************************************************************/
496
497static bool
498ctl_arena_init(ctl_arena_stats_t *astats)
499{
500
501	if (astats->lstats == NULL) {
502		astats->lstats = (malloc_large_stats_t *)a0malloc(nlclasses *
503		    sizeof(malloc_large_stats_t));
504		if (astats->lstats == NULL)
505			return (true);
506	}
507
508	if (astats->hstats == NULL) {
509		astats->hstats = (malloc_huge_stats_t *)a0malloc(nhclasses *
510		    sizeof(malloc_huge_stats_t));
511		if (astats->hstats == NULL)
512			return (true);
513	}
514
515	return (false);
516}
517
518static void
519ctl_arena_clear(ctl_arena_stats_t *astats)
520{
521
522	astats->dss = dss_prec_names[dss_prec_limit];
523	astats->lg_dirty_mult = -1;
524	astats->pactive = 0;
525	astats->pdirty = 0;
526	if (config_stats) {
527		memset(&astats->astats, 0, sizeof(arena_stats_t));
528		astats->allocated_small = 0;
529		astats->nmalloc_small = 0;
530		astats->ndalloc_small = 0;
531		astats->nrequests_small = 0;
532		memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t));
533		memset(astats->lstats, 0, nlclasses *
534		    sizeof(malloc_large_stats_t));
535		memset(astats->hstats, 0, nhclasses *
536		    sizeof(malloc_huge_stats_t));
537	}
538}
539
540static void
541ctl_arena_stats_amerge(ctl_arena_stats_t *cstats, arena_t *arena)
542{
543	unsigned i;
544
545	arena_stats_merge(arena, &cstats->dss, &cstats->lg_dirty_mult,
546	    &cstats->pactive, &cstats->pdirty, &cstats->astats, cstats->bstats,
547	    cstats->lstats, cstats->hstats);
548
549	for (i = 0; i < NBINS; i++) {
550		cstats->allocated_small += cstats->bstats[i].curregs *
551		    index2size(i);
552		cstats->nmalloc_small += cstats->bstats[i].nmalloc;
553		cstats->ndalloc_small += cstats->bstats[i].ndalloc;
554		cstats->nrequests_small += cstats->bstats[i].nrequests;
555	}
556}
557
558static void
559ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats)
560{
561	unsigned i;
562
563	sstats->pactive += astats->pactive;
564	sstats->pdirty += astats->pdirty;
565
566	sstats->astats.mapped += astats->astats.mapped;
567	sstats->astats.npurge += astats->astats.npurge;
568	sstats->astats.nmadvise += astats->astats.nmadvise;
569	sstats->astats.purged += astats->astats.purged;
570
571	sstats->astats.metadata_mapped += astats->astats.metadata_mapped;
572	sstats->astats.metadata_allocated += astats->astats.metadata_allocated;
573
574	sstats->allocated_small += astats->allocated_small;
575	sstats->nmalloc_small += astats->nmalloc_small;
576	sstats->ndalloc_small += astats->ndalloc_small;
577	sstats->nrequests_small += astats->nrequests_small;
578
579	sstats->astats.allocated_large += astats->astats.allocated_large;
580	sstats->astats.nmalloc_large += astats->astats.nmalloc_large;
581	sstats->astats.ndalloc_large += astats->astats.ndalloc_large;
582	sstats->astats.nrequests_large += astats->astats.nrequests_large;
583
584	sstats->astats.allocated_huge += astats->astats.allocated_huge;
585	sstats->astats.nmalloc_huge += astats->astats.nmalloc_huge;
586	sstats->astats.ndalloc_huge += astats->astats.ndalloc_huge;
587
588	for (i = 0; i < NBINS; i++) {
589		sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc;
590		sstats->bstats[i].ndalloc += astats->bstats[i].ndalloc;
591		sstats->bstats[i].nrequests += astats->bstats[i].nrequests;
592		sstats->bstats[i].curregs += astats->bstats[i].curregs;
593		if (config_tcache) {
594			sstats->bstats[i].nfills += astats->bstats[i].nfills;
595			sstats->bstats[i].nflushes +=
596			    astats->bstats[i].nflushes;
597		}
598		sstats->bstats[i].nruns += astats->bstats[i].nruns;
599		sstats->bstats[i].reruns += astats->bstats[i].reruns;
600		sstats->bstats[i].curruns += astats->bstats[i].curruns;
601	}
602
603	for (i = 0; i < nlclasses; i++) {
604		sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc;
605		sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc;
606		sstats->lstats[i].nrequests += astats->lstats[i].nrequests;
607		sstats->lstats[i].curruns += astats->lstats[i].curruns;
608	}
609
610	for (i = 0; i < nhclasses; i++) {
611		sstats->hstats[i].nmalloc += astats->hstats[i].nmalloc;
612		sstats->hstats[i].ndalloc += astats->hstats[i].ndalloc;
613		sstats->hstats[i].curhchunks += astats->hstats[i].curhchunks;
614	}
615}
616
617static void
618ctl_arena_refresh(arena_t *arena, unsigned i)
619{
620	ctl_arena_stats_t *astats = &ctl_stats.arenas[i];
621	ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas];
622
623	ctl_arena_clear(astats);
624
625	sstats->nthreads += astats->nthreads;
626	if (config_stats) {
627		ctl_arena_stats_amerge(astats, arena);
628		/* Merge into sum stats as well. */
629		ctl_arena_stats_smerge(sstats, astats);
630	} else {
631		astats->pactive += arena->nactive;
632		astats->pdirty += arena->ndirty;
633		/* Merge into sum stats as well. */
634		sstats->pactive += arena->nactive;
635		sstats->pdirty += arena->ndirty;
636	}
637}
638
639static bool
640ctl_grow(void)
641{
642	ctl_arena_stats_t *astats;
643
644	/* Initialize new arena. */
645	if (arena_init(ctl_stats.narenas) == NULL)
646		return (true);
647
648	/* Allocate extended arena stats. */
649	astats = (ctl_arena_stats_t *)a0malloc((ctl_stats.narenas + 2) *
650	    sizeof(ctl_arena_stats_t));
651	if (astats == NULL)
652		return (true);
653
654	/* Initialize the new astats element. */
655	memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) *
656	    sizeof(ctl_arena_stats_t));
657	memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t));
658	if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) {
659		a0dalloc(astats);
660		return (true);
661	}
662	/* Swap merged stats to their new location. */
663	{
664		ctl_arena_stats_t tstats;
665		memcpy(&tstats, &astats[ctl_stats.narenas],
666		    sizeof(ctl_arena_stats_t));
667		memcpy(&astats[ctl_stats.narenas],
668		    &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t));
669		memcpy(&astats[ctl_stats.narenas + 1], &tstats,
670		    sizeof(ctl_arena_stats_t));
671	}
672	a0dalloc(ctl_stats.arenas);
673	ctl_stats.arenas = astats;
674	ctl_stats.narenas++;
675
676	return (false);
677}
678
679static void
680ctl_refresh(void)
681{
682	tsd_t *tsd;
683	unsigned i;
684	bool refreshed;
685	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
686
687	/*
688	 * Clear sum stats, since they will be merged into by
689	 * ctl_arena_refresh().
690	 */
691	ctl_stats.arenas[ctl_stats.narenas].nthreads = 0;
692	ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]);
693
694	tsd = tsd_fetch();
695	for (i = 0, refreshed = false; i < ctl_stats.narenas; i++) {
696		tarenas[i] = arena_get(tsd, i, false, false);
697		if (tarenas[i] == NULL && !refreshed) {
698			tarenas[i] = arena_get(tsd, i, false, true);
699			refreshed = true;
700		}
701	}
702
703	for (i = 0; i < ctl_stats.narenas; i++) {
704		if (tarenas[i] != NULL)
705			ctl_stats.arenas[i].nthreads = arena_nbound(i);
706		else
707			ctl_stats.arenas[i].nthreads = 0;
708	}
709
710	for (i = 0; i < ctl_stats.narenas; i++) {
711		bool initialized = (tarenas[i] != NULL);
712
713		ctl_stats.arenas[i].initialized = initialized;
714		if (initialized)
715			ctl_arena_refresh(tarenas[i], i);
716	}
717
718	if (config_stats) {
719		size_t base_allocated, base_resident, base_mapped;
720		base_stats_get(&base_allocated, &base_resident, &base_mapped);
721		ctl_stats.allocated =
722		    ctl_stats.arenas[ctl_stats.narenas].allocated_small +
723		    ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large +
724		    ctl_stats.arenas[ctl_stats.narenas].astats.allocated_huge;
725		ctl_stats.active =
726		    (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE);
727		ctl_stats.metadata = base_allocated +
728		    ctl_stats.arenas[ctl_stats.narenas].astats.metadata_mapped +
729		    ctl_stats.arenas[ctl_stats.narenas].astats
730		    .metadata_allocated;
731		ctl_stats.resident = base_resident +
732		    ctl_stats.arenas[ctl_stats.narenas].astats.metadata_mapped +
733		    ((ctl_stats.arenas[ctl_stats.narenas].pactive +
734		    ctl_stats.arenas[ctl_stats.narenas].pdirty) << LG_PAGE);
735		ctl_stats.mapped = base_mapped +
736		    ctl_stats.arenas[ctl_stats.narenas].astats.mapped;
737	}
738
739	ctl_epoch++;
740}
741
742static bool
743ctl_init(void)
744{
745	bool ret;
746
747	malloc_mutex_lock(&ctl_mtx);
748	if (!ctl_initialized) {
749		/*
750		 * Allocate space for one extra arena stats element, which
751		 * contains summed stats across all arenas.
752		 */
753		ctl_stats.narenas = narenas_total_get();
754		ctl_stats.arenas = (ctl_arena_stats_t *)a0malloc(
755		    (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t));
756		if (ctl_stats.arenas == NULL) {
757			ret = true;
758			goto label_return;
759		}
760		memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) *
761		    sizeof(ctl_arena_stats_t));
762
763		/*
764		 * Initialize all stats structures, regardless of whether they
765		 * ever get used.  Lazy initialization would allow errors to
766		 * cause inconsistent state to be viewable by the application.
767		 */
768		if (config_stats) {
769			unsigned i;
770			for (i = 0; i <= ctl_stats.narenas; i++) {
771				if (ctl_arena_init(&ctl_stats.arenas[i])) {
772					unsigned j;
773					for (j = 0; j < i; j++) {
774						a0dalloc(
775						    ctl_stats.arenas[j].lstats);
776						a0dalloc(
777						    ctl_stats.arenas[j].hstats);
778					}
779					a0dalloc(ctl_stats.arenas);
780					ctl_stats.arenas = NULL;
781					ret = true;
782					goto label_return;
783				}
784			}
785		}
786		ctl_stats.arenas[ctl_stats.narenas].initialized = true;
787
788		ctl_epoch = 0;
789		ctl_refresh();
790		ctl_initialized = true;
791	}
792
793	ret = false;
794label_return:
795	malloc_mutex_unlock(&ctl_mtx);
796	return (ret);
797}
798
799static int
800ctl_lookup(const char *name, ctl_node_t const **nodesp, size_t *mibp,
801    size_t *depthp)
802{
803	int ret;
804	const char *elm, *tdot, *dot;
805	size_t elen, i, j;
806	const ctl_named_node_t *node;
807
808	elm = name;
809	/* Equivalent to strchrnul(). */
810	dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0');
811	elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
812	if (elen == 0) {
813		ret = ENOENT;
814		goto label_return;
815	}
816	node = super_root_node;
817	for (i = 0; i < *depthp; i++) {
818		assert(node);
819		assert(node->nchildren > 0);
820		if (ctl_named_node(node->children) != NULL) {
821			const ctl_named_node_t *pnode = node;
822
823			/* Children are named. */
824			for (j = 0; j < node->nchildren; j++) {
825				const ctl_named_node_t *child =
826				    ctl_named_children(node, j);
827				if (strlen(child->name) == elen &&
828				    strncmp(elm, child->name, elen) == 0) {
829					node = child;
830					if (nodesp != NULL)
831						nodesp[i] =
832						    (const ctl_node_t *)node;
833					mibp[i] = j;
834					break;
835				}
836			}
837			if (node == pnode) {
838				ret = ENOENT;
839				goto label_return;
840			}
841		} else {
842			uintmax_t index;
843			const ctl_indexed_node_t *inode;
844
845			/* Children are indexed. */
846			index = malloc_strtoumax(elm, NULL, 10);
847			if (index == UINTMAX_MAX || index > SIZE_T_MAX) {
848				ret = ENOENT;
849				goto label_return;
850			}
851
852			inode = ctl_indexed_node(node->children);
853			node = inode->index(mibp, *depthp, (size_t)index);
854			if (node == NULL) {
855				ret = ENOENT;
856				goto label_return;
857			}
858
859			if (nodesp != NULL)
860				nodesp[i] = (const ctl_node_t *)node;
861			mibp[i] = (size_t)index;
862		}
863
864		if (node->ctl != NULL) {
865			/* Terminal node. */
866			if (*dot != '\0') {
867				/*
868				 * The name contains more elements than are
869				 * in this path through the tree.
870				 */
871				ret = ENOENT;
872				goto label_return;
873			}
874			/* Complete lookup successful. */
875			*depthp = i + 1;
876			break;
877		}
878
879		/* Update elm. */
880		if (*dot == '\0') {
881			/* No more elements. */
882			ret = ENOENT;
883			goto label_return;
884		}
885		elm = &dot[1];
886		dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot :
887		    strchr(elm, '\0');
888		elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
889	}
890
891	ret = 0;
892label_return:
893	return (ret);
894}
895
896int
897ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
898    size_t newlen)
899{
900	int ret;
901	size_t depth;
902	ctl_node_t const *nodes[CTL_MAX_DEPTH];
903	size_t mib[CTL_MAX_DEPTH];
904	const ctl_named_node_t *node;
905
906	if (!ctl_initialized && ctl_init()) {
907		ret = EAGAIN;
908		goto label_return;
909	}
910
911	depth = CTL_MAX_DEPTH;
912	ret = ctl_lookup(name, nodes, mib, &depth);
913	if (ret != 0)
914		goto label_return;
915
916	node = ctl_named_node(nodes[depth-1]);
917	if (node != NULL && node->ctl)
918		ret = node->ctl(mib, depth, oldp, oldlenp, newp, newlen);
919	else {
920		/* The name refers to a partial path through the ctl tree. */
921		ret = ENOENT;
922	}
923
924label_return:
925	return(ret);
926}
927
928int
929ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp)
930{
931	int ret;
932
933	if (!ctl_initialized && ctl_init()) {
934		ret = EAGAIN;
935		goto label_return;
936	}
937
938	ret = ctl_lookup(name, NULL, mibp, miblenp);
939label_return:
940	return(ret);
941}
942
943int
944ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
945    void *newp, size_t newlen)
946{
947	int ret;
948	const ctl_named_node_t *node;
949	size_t i;
950
951	if (!ctl_initialized && ctl_init()) {
952		ret = EAGAIN;
953		goto label_return;
954	}
955
956	/* Iterate down the tree. */
957	node = super_root_node;
958	for (i = 0; i < miblen; i++) {
959		assert(node);
960		assert(node->nchildren > 0);
961		if (ctl_named_node(node->children) != NULL) {
962			/* Children are named. */
963			if (node->nchildren <= mib[i]) {
964				ret = ENOENT;
965				goto label_return;
966			}
967			node = ctl_named_children(node, mib[i]);
968		} else {
969			const ctl_indexed_node_t *inode;
970
971			/* Indexed element. */
972			inode = ctl_indexed_node(node->children);
973			node = inode->index(mib, miblen, mib[i]);
974			if (node == NULL) {
975				ret = ENOENT;
976				goto label_return;
977			}
978		}
979	}
980
981	/* Call the ctl function. */
982	if (node && node->ctl)
983		ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen);
984	else {
985		/* Partial MIB. */
986		ret = ENOENT;
987	}
988
989label_return:
990	return(ret);
991}
992
993bool
994ctl_boot(void)
995{
996
997	if (malloc_mutex_init(&ctl_mtx))
998		return (true);
999
1000	ctl_initialized = false;
1001
1002	return (false);
1003}
1004
1005void
1006ctl_prefork(void)
1007{
1008
1009	malloc_mutex_prefork(&ctl_mtx);
1010}
1011
1012void
1013ctl_postfork_parent(void)
1014{
1015
1016	malloc_mutex_postfork_parent(&ctl_mtx);
1017}
1018
1019void
1020ctl_postfork_child(void)
1021{
1022
1023	malloc_mutex_postfork_child(&ctl_mtx);
1024}
1025
1026/******************************************************************************/
1027/* *_ctl() functions. */
1028
1029#define	READONLY()	do {						\
1030	if (newp != NULL || newlen != 0) {				\
1031		ret = EPERM;						\
1032		goto label_return;					\
1033	}								\
1034} while (0)
1035
1036#define	WRITEONLY()	do {						\
1037	if (oldp != NULL || oldlenp != NULL) {				\
1038		ret = EPERM;						\
1039		goto label_return;					\
1040	}								\
1041} while (0)
1042
1043#define	READ_XOR_WRITE()	do {					\
1044	if ((oldp != NULL && oldlenp != NULL) && (newp != NULL ||	\
1045	    newlen != 0)) {						\
1046		ret = EPERM;						\
1047		goto label_return;					\
1048	}								\
1049} while (0)
1050
1051#define	READ(v, t)	do {						\
1052	if (oldp != NULL && oldlenp != NULL) {				\
1053		if (*oldlenp != sizeof(t)) {				\
1054			size_t	copylen = (sizeof(t) <= *oldlenp)	\
1055			    ? sizeof(t) : *oldlenp;			\
1056			memcpy(oldp, (void *)&(v), copylen);		\
1057			ret = EINVAL;					\
1058			goto label_return;				\
1059		}							\
1060		*(t *)oldp = (v);					\
1061	}								\
1062} while (0)
1063
1064#define	WRITE(v, t)	do {						\
1065	if (newp != NULL) {						\
1066		if (newlen != sizeof(t)) {				\
1067			ret = EINVAL;					\
1068			goto label_return;				\
1069		}							\
1070		(v) = *(t *)newp;					\
1071	}								\
1072} while (0)
1073
1074/*
1075 * There's a lot of code duplication in the following macros due to limitations
1076 * in how nested cpp macros are expanded.
1077 */
1078#define	CTL_RO_CLGEN(c, l, n, v, t)					\
1079static int								\
1080n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1081    void *newp, size_t newlen)						\
1082{									\
1083	int ret;							\
1084	t oldval;							\
1085									\
1086	if (!(c))							\
1087		return (ENOENT);					\
1088	if (l)								\
1089		malloc_mutex_lock(&ctl_mtx);				\
1090	READONLY();							\
1091	oldval = (v);							\
1092	READ(oldval, t);						\
1093									\
1094	ret = 0;							\
1095label_return:								\
1096	if (l)								\
1097		malloc_mutex_unlock(&ctl_mtx);				\
1098	return (ret);							\
1099}
1100
1101#define	CTL_RO_CGEN(c, n, v, t)						\
1102static int								\
1103n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1104    void *newp, size_t newlen)						\
1105{									\
1106	int ret;							\
1107	t oldval;							\
1108									\
1109	if (!(c))							\
1110		return (ENOENT);					\
1111	malloc_mutex_lock(&ctl_mtx);					\
1112	READONLY();							\
1113	oldval = (v);							\
1114	READ(oldval, t);						\
1115									\
1116	ret = 0;							\
1117label_return:								\
1118	malloc_mutex_unlock(&ctl_mtx);					\
1119	return (ret);							\
1120}
1121
1122#define	CTL_RO_GEN(n, v, t)						\
1123static int								\
1124n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1125    void *newp, size_t newlen)						\
1126{									\
1127	int ret;							\
1128	t oldval;							\
1129									\
1130	malloc_mutex_lock(&ctl_mtx);					\
1131	READONLY();							\
1132	oldval = (v);							\
1133	READ(oldval, t);						\
1134									\
1135	ret = 0;							\
1136label_return:								\
1137	malloc_mutex_unlock(&ctl_mtx);					\
1138	return (ret);							\
1139}
1140
1141/*
1142 * ctl_mtx is not acquired, under the assumption that no pertinent data will
1143 * mutate during the call.
1144 */
1145#define	CTL_RO_NL_CGEN(c, n, v, t)					\
1146static int								\
1147n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1148    void *newp, size_t newlen)						\
1149{									\
1150	int ret;							\
1151	t oldval;							\
1152									\
1153	if (!(c))							\
1154		return (ENOENT);					\
1155	READONLY();							\
1156	oldval = (v);							\
1157	READ(oldval, t);						\
1158									\
1159	ret = 0;							\
1160label_return:								\
1161	return (ret);							\
1162}
1163
1164#define	CTL_RO_NL_GEN(n, v, t)						\
1165static int								\
1166n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1167    void *newp, size_t newlen)						\
1168{									\
1169	int ret;							\
1170	t oldval;							\
1171									\
1172	READONLY();							\
1173	oldval = (v);							\
1174	READ(oldval, t);						\
1175									\
1176	ret = 0;							\
1177label_return:								\
1178	return (ret);							\
1179}
1180
1181#define	CTL_TSD_RO_NL_CGEN(c, n, m, t)					\
1182static int								\
1183n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1184    void *newp, size_t newlen)						\
1185{									\
1186	int ret;							\
1187	t oldval;							\
1188	tsd_t *tsd;							\
1189									\
1190	if (!(c))							\
1191		return (ENOENT);					\
1192	READONLY();							\
1193	tsd = tsd_fetch();						\
1194	oldval = (m(tsd));						\
1195	READ(oldval, t);						\
1196									\
1197	ret = 0;							\
1198label_return:								\
1199	return (ret);							\
1200}
1201
1202#define	CTL_RO_BOOL_CONFIG_GEN(n)					\
1203static int								\
1204n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,	\
1205    void *newp, size_t newlen)						\
1206{									\
1207	int ret;							\
1208	bool oldval;							\
1209									\
1210	READONLY();							\
1211	oldval = n;							\
1212	READ(oldval, bool);						\
1213									\
1214	ret = 0;							\
1215label_return:								\
1216	return (ret);							\
1217}
1218
1219/******************************************************************************/
1220
1221CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
1222
1223static int
1224epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1225    void *newp, size_t newlen)
1226{
1227	int ret;
1228	UNUSED uint64_t newval;
1229
1230	malloc_mutex_lock(&ctl_mtx);
1231	WRITE(newval, uint64_t);
1232	if (newp != NULL)
1233		ctl_refresh();
1234	READ(ctl_epoch, uint64_t);
1235
1236	ret = 0;
1237label_return:
1238	malloc_mutex_unlock(&ctl_mtx);
1239	return (ret);
1240}
1241
1242/******************************************************************************/
1243
1244CTL_RO_BOOL_CONFIG_GEN(config_cache_oblivious)
1245CTL_RO_BOOL_CONFIG_GEN(config_debug)
1246CTL_RO_BOOL_CONFIG_GEN(config_fill)
1247CTL_RO_BOOL_CONFIG_GEN(config_lazy_lock)
1248CTL_RO_BOOL_CONFIG_GEN(config_munmap)
1249CTL_RO_BOOL_CONFIG_GEN(config_prof)
1250CTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc)
1251CTL_RO_BOOL_CONFIG_GEN(config_prof_libunwind)
1252CTL_RO_BOOL_CONFIG_GEN(config_stats)
1253CTL_RO_BOOL_CONFIG_GEN(config_tcache)
1254CTL_RO_BOOL_CONFIG_GEN(config_tls)
1255CTL_RO_BOOL_CONFIG_GEN(config_utrace)
1256CTL_RO_BOOL_CONFIG_GEN(config_valgrind)
1257CTL_RO_BOOL_CONFIG_GEN(config_xmalloc)
1258
1259/******************************************************************************/
1260
1261CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
1262CTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
1263CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
1264CTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t)
1265CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
1266CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
1267CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *)
1268CTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t)
1269CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool)
1270CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
1271CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
1272CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
1273CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
1274CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
1275CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
1276CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
1277CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool)
1278CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init,
1279    opt_prof_thread_active_init, bool)
1280CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
1281CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
1282CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
1283CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
1284CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
1285CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
1286
1287/******************************************************************************/
1288
1289static int
1290thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1291    void *newp, size_t newlen)
1292{
1293	int ret;
1294	tsd_t *tsd;
1295	arena_t *oldarena;
1296	unsigned newind, oldind;
1297
1298	tsd = tsd_fetch();
1299	oldarena = arena_choose(tsd, NULL);
1300	if (oldarena == NULL)
1301		return (EAGAIN);
1302
1303	malloc_mutex_lock(&ctl_mtx);
1304	newind = oldind = oldarena->ind;
1305	WRITE(newind, unsigned);
1306	READ(oldind, unsigned);
1307	if (newind != oldind) {
1308		arena_t *newarena;
1309
1310		if (newind >= ctl_stats.narenas) {
1311			/* New arena index is out of range. */
1312			ret = EFAULT;
1313			goto label_return;
1314		}
1315
1316		/* Initialize arena if necessary. */
1317		newarena = arena_get(tsd, newind, true, true);
1318		if (newarena == NULL) {
1319			ret = EAGAIN;
1320			goto label_return;
1321		}
1322		/* Set new arena/tcache associations. */
1323		arena_migrate(tsd, oldind, newind);
1324		if (config_tcache) {
1325			tcache_t *tcache = tsd_tcache_get(tsd);
1326			if (tcache != NULL) {
1327				tcache_arena_reassociate(tcache, oldarena,
1328				    newarena);
1329			}
1330		}
1331	}
1332
1333	ret = 0;
1334label_return:
1335	malloc_mutex_unlock(&ctl_mtx);
1336	return (ret);
1337}
1338
1339CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get,
1340    uint64_t)
1341CTL_TSD_RO_NL_CGEN(config_stats, thread_allocatedp, tsd_thread_allocatedp_get,
1342    uint64_t *)
1343CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocated, tsd_thread_deallocated_get,
1344    uint64_t)
1345CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp,
1346    tsd_thread_deallocatedp_get, uint64_t *)
1347
1348static int
1349thread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp,
1350    size_t *oldlenp, void *newp, size_t newlen)
1351{
1352	int ret;
1353	bool oldval;
1354
1355	if (!config_tcache)
1356		return (ENOENT);
1357
1358	oldval = tcache_enabled_get();
1359	if (newp != NULL) {
1360		if (newlen != sizeof(bool)) {
1361			ret = EINVAL;
1362			goto label_return;
1363		}
1364		tcache_enabled_set(*(bool *)newp);
1365	}
1366	READ(oldval, bool);
1367
1368	ret = 0;
1369label_return:
1370	return (ret);
1371}
1372
1373static int
1374thread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp,
1375    size_t *oldlenp, void *newp, size_t newlen)
1376{
1377	int ret;
1378
1379	if (!config_tcache)
1380		return (ENOENT);
1381
1382	READONLY();
1383	WRITEONLY();
1384
1385	tcache_flush();
1386
1387	ret = 0;
1388label_return:
1389	return (ret);
1390}
1391
1392static int
1393thread_prof_name_ctl(const size_t *mib, size_t miblen, void *oldp,
1394    size_t *oldlenp, void *newp, size_t newlen)
1395{
1396	int ret;
1397
1398	if (!config_prof)
1399		return (ENOENT);
1400
1401	READ_XOR_WRITE();
1402
1403	if (newp != NULL) {
1404		tsd_t *tsd;
1405
1406		if (newlen != sizeof(const char *)) {
1407			ret = EINVAL;
1408			goto label_return;
1409		}
1410
1411		tsd = tsd_fetch();
1412
1413		if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) !=
1414		    0)
1415			goto label_return;
1416	} else {
1417		const char *oldname = prof_thread_name_get();
1418		READ(oldname, const char *);
1419	}
1420
1421	ret = 0;
1422label_return:
1423	return (ret);
1424}
1425
1426static int
1427thread_prof_active_ctl(const size_t *mib, size_t miblen, void *oldp,
1428    size_t *oldlenp, void *newp, size_t newlen)
1429{
1430	int ret;
1431	bool oldval;
1432
1433	if (!config_prof)
1434		return (ENOENT);
1435
1436	oldval = prof_thread_active_get();
1437	if (newp != NULL) {
1438		if (newlen != sizeof(bool)) {
1439			ret = EINVAL;
1440			goto label_return;
1441		}
1442		if (prof_thread_active_set(*(bool *)newp)) {
1443			ret = EAGAIN;
1444			goto label_return;
1445		}
1446	}
1447	READ(oldval, bool);
1448
1449	ret = 0;
1450label_return:
1451	return (ret);
1452}
1453
1454/******************************************************************************/
1455
1456static int
1457tcache_create_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1458    void *newp, size_t newlen)
1459{
1460	int ret;
1461	tsd_t *tsd;
1462	unsigned tcache_ind;
1463
1464	if (!config_tcache)
1465		return (ENOENT);
1466
1467	tsd = tsd_fetch();
1468
1469	malloc_mutex_lock(&ctl_mtx);
1470	READONLY();
1471	if (tcaches_create(tsd, &tcache_ind)) {
1472		ret = EFAULT;
1473		goto label_return;
1474	}
1475	READ(tcache_ind, unsigned);
1476
1477	ret = 0;
1478label_return:
1479	malloc_mutex_unlock(&ctl_mtx);
1480	return (ret);
1481}
1482
1483static int
1484tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1485    void *newp, size_t newlen)
1486{
1487	int ret;
1488	tsd_t *tsd;
1489	unsigned tcache_ind;
1490
1491	if (!config_tcache)
1492		return (ENOENT);
1493
1494	tsd = tsd_fetch();
1495
1496	WRITEONLY();
1497	tcache_ind = UINT_MAX;
1498	WRITE(tcache_ind, unsigned);
1499	if (tcache_ind == UINT_MAX) {
1500		ret = EFAULT;
1501		goto label_return;
1502	}
1503	tcaches_flush(tsd, tcache_ind);
1504
1505	ret = 0;
1506label_return:
1507	return (ret);
1508}
1509
1510static int
1511tcache_destroy_ctl(const size_t *mib, size_t miblen, void *oldp,
1512    size_t *oldlenp, void *newp, size_t newlen)
1513{
1514	int ret;
1515	tsd_t *tsd;
1516	unsigned tcache_ind;
1517
1518	if (!config_tcache)
1519		return (ENOENT);
1520
1521	tsd = tsd_fetch();
1522
1523	WRITEONLY();
1524	tcache_ind = UINT_MAX;
1525	WRITE(tcache_ind, unsigned);
1526	if (tcache_ind == UINT_MAX) {
1527		ret = EFAULT;
1528		goto label_return;
1529	}
1530	tcaches_destroy(tsd, tcache_ind);
1531
1532	ret = 0;
1533label_return:
1534	return (ret);
1535}
1536
1537/******************************************************************************/
1538
1539/* ctl_mutex must be held during execution of this function. */
1540static void
1541arena_purge(unsigned arena_ind)
1542{
1543	tsd_t *tsd;
1544	unsigned i;
1545	bool refreshed;
1546	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
1547
1548	tsd = tsd_fetch();
1549	for (i = 0, refreshed = false; i < ctl_stats.narenas; i++) {
1550		tarenas[i] = arena_get(tsd, i, false, false);
1551		if (tarenas[i] == NULL && !refreshed) {
1552			tarenas[i] = arena_get(tsd, i, false, true);
1553			refreshed = true;
1554		}
1555	}
1556
1557	if (arena_ind == ctl_stats.narenas) {
1558		unsigned i;
1559		for (i = 0; i < ctl_stats.narenas; i++) {
1560			if (tarenas[i] != NULL)
1561				arena_purge_all(tarenas[i]);
1562		}
1563	} else {
1564		assert(arena_ind < ctl_stats.narenas);
1565		if (tarenas[arena_ind] != NULL)
1566			arena_purge_all(tarenas[arena_ind]);
1567	}
1568}
1569
1570static int
1571arena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1572    void *newp, size_t newlen)
1573{
1574	int ret;
1575
1576	READONLY();
1577	WRITEONLY();
1578	malloc_mutex_lock(&ctl_mtx);
1579	arena_purge(mib[1]);
1580	malloc_mutex_unlock(&ctl_mtx);
1581
1582	ret = 0;
1583label_return:
1584	return (ret);
1585}
1586
1587static int
1588arena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1589    void *newp, size_t newlen)
1590{
1591	int ret;
1592	const char *dss = NULL;
1593	unsigned arena_ind = mib[1];
1594	dss_prec_t dss_prec_old = dss_prec_limit;
1595	dss_prec_t dss_prec = dss_prec_limit;
1596
1597	malloc_mutex_lock(&ctl_mtx);
1598	WRITE(dss, const char *);
1599	if (dss != NULL) {
1600		int i;
1601		bool match = false;
1602
1603		for (i = 0; i < dss_prec_limit; i++) {
1604			if (strcmp(dss_prec_names[i], dss) == 0) {
1605				dss_prec = i;
1606				match = true;
1607				break;
1608			}
1609		}
1610
1611		if (!match) {
1612			ret = EINVAL;
1613			goto label_return;
1614		}
1615	}
1616
1617	if (arena_ind < ctl_stats.narenas) {
1618		arena_t *arena = arena_get(tsd_fetch(), arena_ind, false, true);
1619		if (arena == NULL || (dss_prec != dss_prec_limit &&
1620		    arena_dss_prec_set(arena, dss_prec))) {
1621			ret = EFAULT;
1622			goto label_return;
1623		}
1624		dss_prec_old = arena_dss_prec_get(arena);
1625	} else {
1626		if (dss_prec != dss_prec_limit &&
1627		    chunk_dss_prec_set(dss_prec)) {
1628			ret = EFAULT;
1629			goto label_return;
1630		}
1631		dss_prec_old = chunk_dss_prec_get();
1632	}
1633
1634	dss = dss_prec_names[dss_prec_old];
1635	READ(dss, const char *);
1636
1637	ret = 0;
1638label_return:
1639	malloc_mutex_unlock(&ctl_mtx);
1640	return (ret);
1641}
1642
1643static int
1644arena_i_lg_dirty_mult_ctl(const size_t *mib, size_t miblen, void *oldp,
1645    size_t *oldlenp, void *newp, size_t newlen)
1646{
1647	int ret;
1648	unsigned arena_ind = mib[1];
1649	arena_t *arena;
1650
1651	arena = arena_get(tsd_fetch(), arena_ind, false, true);
1652	if (arena == NULL) {
1653		ret = EFAULT;
1654		goto label_return;
1655	}
1656
1657	if (oldp != NULL && oldlenp != NULL) {
1658		size_t oldval = arena_lg_dirty_mult_get(arena);
1659		READ(oldval, ssize_t);
1660	}
1661	if (newp != NULL) {
1662		if (newlen != sizeof(ssize_t)) {
1663			ret = EINVAL;
1664			goto label_return;
1665		}
1666		if (arena_lg_dirty_mult_set(arena, *(ssize_t *)newp)) {
1667			ret = EFAULT;
1668			goto label_return;
1669		}
1670	}
1671
1672	ret = 0;
1673label_return:
1674	return (ret);
1675}
1676
1677static int
1678arena_i_chunk_hooks_ctl(const size_t *mib, size_t miblen, void *oldp,
1679    size_t *oldlenp, void *newp, size_t newlen)
1680{
1681	int ret;
1682	unsigned arena_ind = mib[1];
1683	arena_t *arena;
1684
1685	malloc_mutex_lock(&ctl_mtx);
1686	if (arena_ind < narenas_total_get() && (arena =
1687	    arena_get(tsd_fetch(), arena_ind, false, true)) != NULL) {
1688		if (newp != NULL) {
1689			chunk_hooks_t old_chunk_hooks, new_chunk_hooks;
1690			WRITE(new_chunk_hooks, chunk_hooks_t);
1691			old_chunk_hooks = chunk_hooks_set(arena,
1692			    &new_chunk_hooks);
1693			READ(old_chunk_hooks, chunk_hooks_t);
1694		} else {
1695			chunk_hooks_t old_chunk_hooks = chunk_hooks_get(arena);
1696			READ(old_chunk_hooks, chunk_hooks_t);
1697		}
1698	} else {
1699		ret = EFAULT;
1700		goto label_return;
1701	}
1702	ret = 0;
1703label_return:
1704	malloc_mutex_unlock(&ctl_mtx);
1705	return (ret);
1706}
1707
1708static const ctl_named_node_t *
1709arena_i_index(const size_t *mib, size_t miblen, size_t i)
1710{
1711	const ctl_named_node_t * ret;
1712
1713	malloc_mutex_lock(&ctl_mtx);
1714	if (i > ctl_stats.narenas) {
1715		ret = NULL;
1716		goto label_return;
1717	}
1718
1719	ret = super_arena_i_node;
1720label_return:
1721	malloc_mutex_unlock(&ctl_mtx);
1722	return (ret);
1723}
1724
1725/******************************************************************************/
1726
1727static int
1728arenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp,
1729    size_t *oldlenp, void *newp, size_t newlen)
1730{
1731	int ret;
1732	unsigned narenas;
1733
1734	malloc_mutex_lock(&ctl_mtx);
1735	READONLY();
1736	if (*oldlenp != sizeof(unsigned)) {
1737		ret = EINVAL;
1738		goto label_return;
1739	}
1740	narenas = ctl_stats.narenas;
1741	READ(narenas, unsigned);
1742
1743	ret = 0;
1744label_return:
1745	malloc_mutex_unlock(&ctl_mtx);
1746	return (ret);
1747}
1748
1749static int
1750arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
1751    size_t *oldlenp, void *newp, size_t newlen)
1752{
1753	int ret;
1754	unsigned nread, i;
1755
1756	malloc_mutex_lock(&ctl_mtx);
1757	READONLY();
1758	if (*oldlenp != ctl_stats.narenas * sizeof(bool)) {
1759		ret = EINVAL;
1760		nread = (*oldlenp < ctl_stats.narenas * sizeof(bool))
1761		    ? (*oldlenp / sizeof(bool)) : ctl_stats.narenas;
1762	} else {
1763		ret = 0;
1764		nread = ctl_stats.narenas;
1765	}
1766
1767	for (i = 0; i < nread; i++)
1768		((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
1769
1770label_return:
1771	malloc_mutex_unlock(&ctl_mtx);
1772	return (ret);
1773}
1774
1775static int
1776arenas_lg_dirty_mult_ctl(const size_t *mib, size_t miblen, void *oldp,
1777    size_t *oldlenp, void *newp, size_t newlen)
1778{
1779	int ret;
1780
1781	if (oldp != NULL && oldlenp != NULL) {
1782		size_t oldval = arena_lg_dirty_mult_default_get();
1783		READ(oldval, ssize_t);
1784	}
1785	if (newp != NULL) {
1786		if (newlen != sizeof(ssize_t)) {
1787			ret = EINVAL;
1788			goto label_return;
1789		}
1790		if (arena_lg_dirty_mult_default_set(*(ssize_t *)newp)) {
1791			ret = EFAULT;
1792			goto label_return;
1793		}
1794	}
1795
1796	ret = 0;
1797label_return:
1798	return (ret);
1799}
1800
1801CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
1802CTL_RO_NL_GEN(arenas_page, PAGE, size_t)
1803CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t)
1804CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
1805CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned)
1806CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
1807CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
1808CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
1809static const ctl_named_node_t *
1810arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
1811{
1812
1813	if (i > NBINS)
1814		return (NULL);
1815	return (super_arenas_bin_i_node);
1816}
1817
1818CTL_RO_NL_GEN(arenas_nlruns, nlclasses, unsigned)
1819CTL_RO_NL_GEN(arenas_lrun_i_size, index2size(NBINS+mib[2]), size_t)
1820static const ctl_named_node_t *
1821arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
1822{
1823
1824	if (i > nlclasses)
1825		return (NULL);
1826	return (super_arenas_lrun_i_node);
1827}
1828
1829CTL_RO_NL_GEN(arenas_nhchunks, nhclasses, unsigned)
1830CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+nlclasses+mib[2]), size_t)
1831static const ctl_named_node_t *
1832arenas_hchunk_i_index(const size_t *mib, size_t miblen, size_t i)
1833{
1834
1835	if (i > nhclasses)
1836		return (NULL);
1837	return (super_arenas_hchunk_i_node);
1838}
1839
1840static int
1841arenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1842    void *newp, size_t newlen)
1843{
1844	int ret;
1845	unsigned narenas;
1846
1847	malloc_mutex_lock(&ctl_mtx);
1848	READONLY();
1849	if (ctl_grow()) {
1850		ret = EAGAIN;
1851		goto label_return;
1852	}
1853	narenas = ctl_stats.narenas - 1;
1854	READ(narenas, unsigned);
1855
1856	ret = 0;
1857label_return:
1858	malloc_mutex_unlock(&ctl_mtx);
1859	return (ret);
1860}
1861
1862/******************************************************************************/
1863
1864static int
1865prof_thread_active_init_ctl(const size_t *mib, size_t miblen, void *oldp,
1866    size_t *oldlenp, void *newp, size_t newlen)
1867{
1868	int ret;
1869	bool oldval;
1870
1871	if (!config_prof)
1872		return (ENOENT);
1873
1874	if (newp != NULL) {
1875		if (newlen != sizeof(bool)) {
1876			ret = EINVAL;
1877			goto label_return;
1878		}
1879		oldval = prof_thread_active_init_set(*(bool *)newp);
1880	} else
1881		oldval = prof_thread_active_init_get();
1882	READ(oldval, bool);
1883
1884	ret = 0;
1885label_return:
1886	return (ret);
1887}
1888
1889static int
1890prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1891    void *newp, size_t newlen)
1892{
1893	int ret;
1894	bool oldval;
1895
1896	if (!config_prof)
1897		return (ENOENT);
1898
1899	if (newp != NULL) {
1900		if (newlen != sizeof(bool)) {
1901			ret = EINVAL;
1902			goto label_return;
1903		}
1904		oldval = prof_active_set(*(bool *)newp);
1905	} else
1906		oldval = prof_active_get();
1907	READ(oldval, bool);
1908
1909	ret = 0;
1910label_return:
1911	return (ret);
1912}
1913
1914static int
1915prof_dump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1916    void *newp, size_t newlen)
1917{
1918	int ret;
1919	const char *filename = NULL;
1920
1921	if (!config_prof)
1922		return (ENOENT);
1923
1924	WRITEONLY();
1925	WRITE(filename, const char *);
1926
1927	if (prof_mdump(filename)) {
1928		ret = EFAULT;
1929		goto label_return;
1930	}
1931
1932	ret = 0;
1933label_return:
1934	return (ret);
1935}
1936
1937static int
1938prof_gdump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1939    void *newp, size_t newlen)
1940{
1941	int ret;
1942	bool oldval;
1943
1944	if (!config_prof)
1945		return (ENOENT);
1946
1947	if (newp != NULL) {
1948		if (newlen != sizeof(bool)) {
1949			ret = EINVAL;
1950			goto label_return;
1951		}
1952		oldval = prof_gdump_set(*(bool *)newp);
1953	} else
1954		oldval = prof_gdump_get();
1955	READ(oldval, bool);
1956
1957	ret = 0;
1958label_return:
1959	return (ret);
1960}
1961
1962static int
1963prof_reset_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
1964    void *newp, size_t newlen)
1965{
1966	int ret;
1967	size_t lg_sample = lg_prof_sample;
1968	tsd_t *tsd;
1969
1970	if (!config_prof)
1971		return (ENOENT);
1972
1973	WRITEONLY();
1974	WRITE(lg_sample, size_t);
1975	if (lg_sample >= (sizeof(uint64_t) << 3))
1976		lg_sample = (sizeof(uint64_t) << 3) - 1;
1977
1978	tsd = tsd_fetch();
1979
1980	prof_reset(tsd, lg_sample);
1981
1982	ret = 0;
1983label_return:
1984	return (ret);
1985}
1986
1987CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
1988CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t)
1989
1990/******************************************************************************/
1991
1992CTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *)
1993CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t)
1994CTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t)
1995CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats.metadata, size_t)
1996CTL_RO_CGEN(config_stats, stats_resident, ctl_stats.resident, size_t)
1997CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t)
1998
1999CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *)
2000CTL_RO_GEN(stats_arenas_i_lg_dirty_mult, ctl_stats.arenas[mib[2]].lg_dirty_mult,
2001    ssize_t)
2002CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
2003CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
2004CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
2005CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
2006    ctl_stats.arenas[mib[2]].astats.mapped, size_t)
2007CTL_RO_CGEN(config_stats, stats_arenas_i_npurge,
2008    ctl_stats.arenas[mib[2]].astats.npurge, uint64_t)
2009CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise,
2010    ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t)
2011CTL_RO_CGEN(config_stats, stats_arenas_i_purged,
2012    ctl_stats.arenas[mib[2]].astats.purged, uint64_t)
2013CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_mapped,
2014    ctl_stats.arenas[mib[2]].astats.metadata_mapped, size_t)
2015CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_allocated,
2016    ctl_stats.arenas[mib[2]].astats.metadata_allocated, size_t)
2017
2018CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
2019    ctl_stats.arenas[mib[2]].allocated_small, size_t)
2020CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
2021    ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t)
2022CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
2023    ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t)
2024CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
2025    ctl_stats.arenas[mib[2]].nrequests_small, uint64_t)
2026CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
2027    ctl_stats.arenas[mib[2]].astats.allocated_large, size_t)
2028CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
2029    ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t)
2030CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
2031    ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t)
2032CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
2033    ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t)
2034CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated,
2035    ctl_stats.arenas[mib[2]].astats.allocated_huge, size_t)
2036CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc,
2037    ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t)
2038CTL_RO_CGEN(config_stats, stats_arenas_i_huge_ndalloc,
2039    ctl_stats.arenas[mib[2]].astats.ndalloc_huge, uint64_t)
2040CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nrequests,
2041    ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) /* Intentional. */
2042
2043CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
2044    ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t)
2045CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
2046    ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t)
2047CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
2048    ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t)
2049CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs,
2050    ctl_stats.arenas[mib[2]].bstats[mib[4]].curregs, size_t)
2051CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills,
2052    ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t)
2053CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes,
2054    ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t)
2055CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns,
2056    ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t)
2057CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns,
2058    ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t)
2059CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns,
2060    ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t)
2061
2062static const ctl_named_node_t *
2063stats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j)
2064{
2065
2066	if (j > NBINS)
2067		return (NULL);
2068	return (super_stats_arenas_i_bins_j_node);
2069}
2070
2071CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc,
2072    ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t)
2073CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc,
2074    ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t)
2075CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests,
2076    ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t)
2077CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns,
2078    ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t)
2079
2080static const ctl_named_node_t *
2081stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
2082{
2083
2084	if (j > nlclasses)
2085		return (NULL);
2086	return (super_stats_arenas_i_lruns_j_node);
2087}
2088
2089CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nmalloc,
2090    ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, uint64_t)
2091CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_ndalloc,
2092    ctl_stats.arenas[mib[2]].hstats[mib[4]].ndalloc, uint64_t)
2093CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nrequests,
2094    ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, /* Intentional. */
2095    uint64_t)
2096CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_curhchunks,
2097    ctl_stats.arenas[mib[2]].hstats[mib[4]].curhchunks, size_t)
2098
2099static const ctl_named_node_t *
2100stats_arenas_i_hchunks_j_index(const size_t *mib, size_t miblen, size_t j)
2101{
2102
2103	if (j > nhclasses)
2104		return (NULL);
2105	return (super_stats_arenas_i_hchunks_j_node);
2106}
2107
2108static const ctl_named_node_t *
2109stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
2110{
2111	const ctl_named_node_t * ret;
2112
2113	malloc_mutex_lock(&ctl_mtx);
2114	if (i > ctl_stats.narenas || !ctl_stats.arenas[i].initialized) {
2115		ret = NULL;
2116		goto label_return;
2117	}
2118
2119	ret = super_stats_arenas_i_node;
2120label_return:
2121	malloc_mutex_unlock(&ctl_mtx);
2122	return (ret);
2123}
2124