]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/jemalloc/src/ctl.c
Use the new insecure-lan-zones option instead of listing each AS112 zone
[FreeBSD/FreeBSD.git] / contrib / jemalloc / src / ctl.c
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  */
11 static malloc_mutex_t   ctl_mtx;
12 static bool             ctl_initialized;
13 static uint64_t         ctl_epoch;
14 static ctl_stats_t      ctl_stats;
15
16 /******************************************************************************/
17 /* Helpers for named and indexed nodes. */
18
19 JEMALLOC_INLINE_C const ctl_named_node_t *
20 ctl_named_node(const ctl_node_t *node)
21 {
22
23         return ((node->named) ? (const ctl_named_node_t *)node : NULL);
24 }
25
26 JEMALLOC_INLINE_C const ctl_named_node_t *
27 ctl_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
34 JEMALLOC_INLINE_C const ctl_indexed_node_t *
35 ctl_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)                                                    \
45 static 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)                                                  \
49 static const ctl_named_node_t   *n##_index(const size_t *mib,           \
50     size_t miblen, size_t i);
51
52 static bool     ctl_arena_init(ctl_arena_stats_t *astats);
53 static void     ctl_arena_clear(ctl_arena_stats_t *astats);
54 static void     ctl_arena_stats_amerge(ctl_arena_stats_t *cstats,
55     arena_t *arena);
56 static void     ctl_arena_stats_smerge(ctl_arena_stats_t *sstats,
57     ctl_arena_stats_t *astats);
58 static void     ctl_arena_refresh(arena_t *arena, unsigned i);
59 static bool     ctl_grow(void);
60 static void     ctl_refresh(void);
61 static bool     ctl_init(void);
62 static int      ctl_lookup(const char *name, ctl_node_t const **nodesp,
63     size_t *mibp, size_t *depthp);
64
65 CTL_PROTO(version)
66 CTL_PROTO(epoch)
67 CTL_PROTO(thread_tcache_enabled)
68 CTL_PROTO(thread_tcache_flush)
69 CTL_PROTO(thread_prof_name)
70 CTL_PROTO(thread_prof_active)
71 CTL_PROTO(thread_arena)
72 CTL_PROTO(thread_allocated)
73 CTL_PROTO(thread_allocatedp)
74 CTL_PROTO(thread_deallocated)
75 CTL_PROTO(thread_deallocatedp)
76 CTL_PROTO(config_cache_oblivious)
77 CTL_PROTO(config_debug)
78 CTL_PROTO(config_fill)
79 CTL_PROTO(config_lazy_lock)
80 CTL_PROTO(config_munmap)
81 CTL_PROTO(config_prof)
82 CTL_PROTO(config_prof_libgcc)
83 CTL_PROTO(config_prof_libunwind)
84 CTL_PROTO(config_stats)
85 CTL_PROTO(config_tcache)
86 CTL_PROTO(config_tls)
87 CTL_PROTO(config_utrace)
88 CTL_PROTO(config_valgrind)
89 CTL_PROTO(config_xmalloc)
90 CTL_PROTO(opt_abort)
91 CTL_PROTO(opt_dss)
92 CTL_PROTO(opt_lg_chunk)
93 CTL_PROTO(opt_narenas)
94 CTL_PROTO(opt_lg_dirty_mult)
95 CTL_PROTO(opt_stats_print)
96 CTL_PROTO(opt_junk)
97 CTL_PROTO(opt_zero)
98 CTL_PROTO(opt_quarantine)
99 CTL_PROTO(opt_redzone)
100 CTL_PROTO(opt_utrace)
101 CTL_PROTO(opt_xmalloc)
102 CTL_PROTO(opt_tcache)
103 CTL_PROTO(opt_lg_tcache_max)
104 CTL_PROTO(opt_prof)
105 CTL_PROTO(opt_prof_prefix)
106 CTL_PROTO(opt_prof_active)
107 CTL_PROTO(opt_prof_thread_active_init)
108 CTL_PROTO(opt_lg_prof_sample)
109 CTL_PROTO(opt_lg_prof_interval)
110 CTL_PROTO(opt_prof_gdump)
111 CTL_PROTO(opt_prof_final)
112 CTL_PROTO(opt_prof_leak)
113 CTL_PROTO(opt_prof_accum)
114 CTL_PROTO(tcache_create)
115 CTL_PROTO(tcache_flush)
116 CTL_PROTO(tcache_destroy)
117 CTL_PROTO(arena_i_purge)
118 static void     arena_purge(unsigned arena_ind);
119 CTL_PROTO(arena_i_dss)
120 CTL_PROTO(arena_i_lg_dirty_mult)
121 CTL_PROTO(arena_i_chunk_hooks)
122 INDEX_PROTO(arena_i)
123 CTL_PROTO(arenas_bin_i_size)
124 CTL_PROTO(arenas_bin_i_nregs)
125 CTL_PROTO(arenas_bin_i_run_size)
126 INDEX_PROTO(arenas_bin_i)
127 CTL_PROTO(arenas_lrun_i_size)
128 INDEX_PROTO(arenas_lrun_i)
129 CTL_PROTO(arenas_hchunk_i_size)
130 INDEX_PROTO(arenas_hchunk_i)
131 CTL_PROTO(arenas_narenas)
132 CTL_PROTO(arenas_initialized)
133 CTL_PROTO(arenas_lg_dirty_mult)
134 CTL_PROTO(arenas_quantum)
135 CTL_PROTO(arenas_page)
136 CTL_PROTO(arenas_tcache_max)
137 CTL_PROTO(arenas_nbins)
138 CTL_PROTO(arenas_nhbins)
139 CTL_PROTO(arenas_nlruns)
140 CTL_PROTO(arenas_nhchunks)
141 CTL_PROTO(arenas_extend)
142 CTL_PROTO(prof_thread_active_init)
143 CTL_PROTO(prof_active)
144 CTL_PROTO(prof_dump)
145 CTL_PROTO(prof_gdump)
146 CTL_PROTO(prof_reset)
147 CTL_PROTO(prof_interval)
148 CTL_PROTO(lg_prof_sample)
149 CTL_PROTO(stats_arenas_i_small_allocated)
150 CTL_PROTO(stats_arenas_i_small_nmalloc)
151 CTL_PROTO(stats_arenas_i_small_ndalloc)
152 CTL_PROTO(stats_arenas_i_small_nrequests)
153 CTL_PROTO(stats_arenas_i_large_allocated)
154 CTL_PROTO(stats_arenas_i_large_nmalloc)
155 CTL_PROTO(stats_arenas_i_large_ndalloc)
156 CTL_PROTO(stats_arenas_i_large_nrequests)
157 CTL_PROTO(stats_arenas_i_huge_allocated)
158 CTL_PROTO(stats_arenas_i_huge_nmalloc)
159 CTL_PROTO(stats_arenas_i_huge_ndalloc)
160 CTL_PROTO(stats_arenas_i_huge_nrequests)
161 CTL_PROTO(stats_arenas_i_bins_j_nmalloc)
162 CTL_PROTO(stats_arenas_i_bins_j_ndalloc)
163 CTL_PROTO(stats_arenas_i_bins_j_nrequests)
164 CTL_PROTO(stats_arenas_i_bins_j_curregs)
165 CTL_PROTO(stats_arenas_i_bins_j_nfills)
166 CTL_PROTO(stats_arenas_i_bins_j_nflushes)
167 CTL_PROTO(stats_arenas_i_bins_j_nruns)
168 CTL_PROTO(stats_arenas_i_bins_j_nreruns)
169 CTL_PROTO(stats_arenas_i_bins_j_curruns)
170 INDEX_PROTO(stats_arenas_i_bins_j)
171 CTL_PROTO(stats_arenas_i_lruns_j_nmalloc)
172 CTL_PROTO(stats_arenas_i_lruns_j_ndalloc)
173 CTL_PROTO(stats_arenas_i_lruns_j_nrequests)
174 CTL_PROTO(stats_arenas_i_lruns_j_curruns)
175 INDEX_PROTO(stats_arenas_i_lruns_j)
176 CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc)
177 CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc)
178 CTL_PROTO(stats_arenas_i_hchunks_j_nrequests)
179 CTL_PROTO(stats_arenas_i_hchunks_j_curhchunks)
180 INDEX_PROTO(stats_arenas_i_hchunks_j)
181 CTL_PROTO(stats_arenas_i_nthreads)
182 CTL_PROTO(stats_arenas_i_dss)
183 CTL_PROTO(stats_arenas_i_lg_dirty_mult)
184 CTL_PROTO(stats_arenas_i_pactive)
185 CTL_PROTO(stats_arenas_i_pdirty)
186 CTL_PROTO(stats_arenas_i_mapped)
187 CTL_PROTO(stats_arenas_i_npurge)
188 CTL_PROTO(stats_arenas_i_nmadvise)
189 CTL_PROTO(stats_arenas_i_purged)
190 CTL_PROTO(stats_arenas_i_metadata_mapped)
191 CTL_PROTO(stats_arenas_i_metadata_allocated)
192 INDEX_PROTO(stats_arenas_i)
193 CTL_PROTO(stats_cactive)
194 CTL_PROTO(stats_allocated)
195 CTL_PROTO(stats_active)
196 CTL_PROTO(stats_metadata)
197 CTL_PROTO(stats_resident)
198 CTL_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
219 static const ctl_named_node_t   thread_tcache_node[] = {
220         {NAME("enabled"),       CTL(thread_tcache_enabled)},
221         {NAME("flush"),         CTL(thread_tcache_flush)}
222 };
223
224 static const ctl_named_node_t   thread_prof_node[] = {
225         {NAME("name"),          CTL(thread_prof_name)},
226         {NAME("active"),        CTL(thread_prof_active)}
227 };
228
229 static 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
239 static 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
256 static 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
283 static 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
289 static 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 };
295 static const ctl_named_node_t super_arena_i_node[] = {
296         {NAME(""),              CHILD(named, arena_i)}
297 };
298
299 static const ctl_indexed_node_t arena_node[] = {
300         {INDEX(arena_i)}
301 };
302
303 static 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 };
308 static const ctl_named_node_t super_arenas_bin_i_node[] = {
309         {NAME(""),              CHILD(named, arenas_bin_i)}
310 };
311
312 static const ctl_indexed_node_t arenas_bin_node[] = {
313         {INDEX(arenas_bin_i)}
314 };
315
316 static const ctl_named_node_t arenas_lrun_i_node[] = {
317         {NAME("size"),          CTL(arenas_lrun_i_size)}
318 };
319 static const ctl_named_node_t super_arenas_lrun_i_node[] = {
320         {NAME(""),              CHILD(named, arenas_lrun_i)}
321 };
322
323 static const ctl_indexed_node_t arenas_lrun_node[] = {
324         {INDEX(arenas_lrun_i)}
325 };
326
327 static const ctl_named_node_t arenas_hchunk_i_node[] = {
328         {NAME("size"),          CTL(arenas_hchunk_i_size)}
329 };
330 static const ctl_named_node_t super_arenas_hchunk_i_node[] = {
331         {NAME(""),              CHILD(named, arenas_hchunk_i)}
332 };
333
334 static const ctl_indexed_node_t arenas_hchunk_node[] = {
335         {INDEX(arenas_hchunk_i)}
336 };
337
338 static 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
355 static 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
365 static 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
370 static 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
377 static 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
384 static 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
391 static 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 };
402 static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = {
403         {NAME(""),              CHILD(named, stats_arenas_i_bins_j)}
404 };
405
406 static const ctl_indexed_node_t stats_arenas_i_bins_node[] = {
407         {INDEX(stats_arenas_i_bins_j)}
408 };
409
410 static 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 };
416 static const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = {
417         {NAME(""),              CHILD(named, stats_arenas_i_lruns_j)}
418 };
419
420 static const ctl_indexed_node_t stats_arenas_i_lruns_node[] = {
421         {INDEX(stats_arenas_i_lruns_j)}
422 };
423
424 static 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 };
430 static const ctl_named_node_t super_stats_arenas_i_hchunks_j_node[] = {
431         {NAME(""),              CHILD(named, stats_arenas_i_hchunks_j)}
432 };
433
434 static const ctl_indexed_node_t stats_arenas_i_hchunks_node[] = {
435         {INDEX(stats_arenas_i_hchunks_j)}
436 };
437
438 static 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 };
456 static const ctl_named_node_t super_stats_arenas_i_node[] = {
457         {NAME(""),              CHILD(named, stats_arenas_i)}
458 };
459
460 static const ctl_indexed_node_t stats_arenas_node[] = {
461         {INDEX(stats_arenas_i)}
462 };
463
464 static 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
474 static 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 };
486 static 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
497 static bool
498 ctl_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
518 static void
519 ctl_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
540 static void
541 ctl_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
558 static void
559 ctl_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
617 static void
618 ctl_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
639 static bool
640 ctl_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
679 static void
680 ctl_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
742 static bool
743 ctl_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;
794 label_return:
795         malloc_mutex_unlock(&ctl_mtx);
796         return (ret);
797 }
798
799 static int
800 ctl_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;
892 label_return:
893         return (ret);
894 }
895
896 int
897 ctl_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
924 label_return:
925         return(ret);
926 }
927
928 int
929 ctl_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);
939 label_return:
940         return(ret);
941 }
942
943 int
944 ctl_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
989 label_return:
990         return(ret);
991 }
992
993 bool
994 ctl_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
1005 void
1006 ctl_prefork(void)
1007 {
1008
1009         malloc_mutex_prefork(&ctl_mtx);
1010 }
1011
1012 void
1013 ctl_postfork_parent(void)
1014 {
1015
1016         malloc_mutex_postfork_parent(&ctl_mtx);
1017 }
1018
1019 void
1020 ctl_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)                                     \
1079 static int                                                              \
1080 n##_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;                                                        \
1095 label_return:                                                           \
1096         if (l)                                                          \
1097                 malloc_mutex_unlock(&ctl_mtx);                          \
1098         return (ret);                                                   \
1099 }
1100
1101 #define CTL_RO_CGEN(c, n, v, t)                                         \
1102 static int                                                              \
1103 n##_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;                                                        \
1117 label_return:                                                           \
1118         malloc_mutex_unlock(&ctl_mtx);                                  \
1119         return (ret);                                                   \
1120 }
1121
1122 #define CTL_RO_GEN(n, v, t)                                             \
1123 static int                                                              \
1124 n##_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;                                                        \
1136 label_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)                                      \
1146 static int                                                              \
1147 n##_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;                                                        \
1160 label_return:                                                           \
1161         return (ret);                                                   \
1162 }
1163
1164 #define CTL_RO_NL_GEN(n, v, t)                                          \
1165 static int                                                              \
1166 n##_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;                                                        \
1177 label_return:                                                           \
1178         return (ret);                                                   \
1179 }
1180
1181 #define CTL_TSD_RO_NL_CGEN(c, n, m, t)                                  \
1182 static int                                                              \
1183 n##_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;                                                        \
1198 label_return:                                                           \
1199         return (ret);                                                   \
1200 }
1201
1202 #define CTL_RO_BOOL_CONFIG_GEN(n)                                       \
1203 static int                                                              \
1204 n##_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;                                                        \
1215 label_return:                                                           \
1216         return (ret);                                                   \
1217 }
1218
1219 /******************************************************************************/
1220
1221 CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
1222
1223 static int
1224 epoch_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;
1237 label_return:
1238         malloc_mutex_unlock(&ctl_mtx);
1239         return (ret);
1240 }
1241
1242 /******************************************************************************/
1243
1244 CTL_RO_BOOL_CONFIG_GEN(config_cache_oblivious)
1245 CTL_RO_BOOL_CONFIG_GEN(config_debug)
1246 CTL_RO_BOOL_CONFIG_GEN(config_fill)
1247 CTL_RO_BOOL_CONFIG_GEN(config_lazy_lock)
1248 CTL_RO_BOOL_CONFIG_GEN(config_munmap)
1249 CTL_RO_BOOL_CONFIG_GEN(config_prof)
1250 CTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc)
1251 CTL_RO_BOOL_CONFIG_GEN(config_prof_libunwind)
1252 CTL_RO_BOOL_CONFIG_GEN(config_stats)
1253 CTL_RO_BOOL_CONFIG_GEN(config_tcache)
1254 CTL_RO_BOOL_CONFIG_GEN(config_tls)
1255 CTL_RO_BOOL_CONFIG_GEN(config_utrace)
1256 CTL_RO_BOOL_CONFIG_GEN(config_valgrind)
1257 CTL_RO_BOOL_CONFIG_GEN(config_xmalloc)
1258
1259 /******************************************************************************/
1260
1261 CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
1262 CTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
1263 CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
1264 CTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t)
1265 CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
1266 CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
1267 CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *)
1268 CTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t)
1269 CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool)
1270 CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
1271 CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
1272 CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
1273 CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
1274 CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
1275 CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
1276 CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
1277 CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool)
1278 CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init,
1279     opt_prof_thread_active_init, bool)
1280 CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
1281 CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
1282 CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
1283 CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
1284 CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
1285 CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
1286
1287 /******************************************************************************/
1288
1289 static int
1290 thread_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;
1334 label_return:
1335         malloc_mutex_unlock(&ctl_mtx);
1336         return (ret);
1337 }
1338
1339 CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get,
1340     uint64_t)
1341 CTL_TSD_RO_NL_CGEN(config_stats, thread_allocatedp, tsd_thread_allocatedp_get,
1342     uint64_t *)
1343 CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocated, tsd_thread_deallocated_get,
1344     uint64_t)
1345 CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp,
1346     tsd_thread_deallocatedp_get, uint64_t *)
1347
1348 static int
1349 thread_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;
1369 label_return:
1370         return (ret);
1371 }
1372
1373 static int
1374 thread_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;
1388 label_return:
1389         return (ret);
1390 }
1391
1392 static int
1393 thread_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;
1422 label_return:
1423         return (ret);
1424 }
1425
1426 static int
1427 thread_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;
1450 label_return:
1451         return (ret);
1452 }
1453
1454 /******************************************************************************/
1455
1456 static int
1457 tcache_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;
1478 label_return:
1479         malloc_mutex_unlock(&ctl_mtx);
1480         return (ret);
1481 }
1482
1483 static int
1484 tcache_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;
1506 label_return:
1507         return (ret);
1508 }
1509
1510 static int
1511 tcache_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;
1533 label_return:
1534         return (ret);
1535 }
1536
1537 /******************************************************************************/
1538
1539 /* ctl_mutex must be held during execution of this function. */
1540 static void
1541 arena_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
1570 static int
1571 arena_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;
1583 label_return:
1584         return (ret);
1585 }
1586
1587 static int
1588 arena_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;
1638 label_return:
1639         malloc_mutex_unlock(&ctl_mtx);
1640         return (ret);
1641 }
1642
1643 static int
1644 arena_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;
1673 label_return:
1674         return (ret);
1675 }
1676
1677 static int
1678 arena_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;
1703 label_return:
1704         malloc_mutex_unlock(&ctl_mtx);
1705         return (ret);
1706 }
1707
1708 static const ctl_named_node_t *
1709 arena_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;
1720 label_return:
1721         malloc_mutex_unlock(&ctl_mtx);
1722         return (ret);
1723 }
1724
1725 /******************************************************************************/
1726
1727 static int
1728 arenas_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;
1744 label_return:
1745         malloc_mutex_unlock(&ctl_mtx);
1746         return (ret);
1747 }
1748
1749 static int
1750 arenas_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
1770 label_return:
1771         malloc_mutex_unlock(&ctl_mtx);
1772         return (ret);
1773 }
1774
1775 static int
1776 arenas_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;
1797 label_return:
1798         return (ret);
1799 }
1800
1801 CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
1802 CTL_RO_NL_GEN(arenas_page, PAGE, size_t)
1803 CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t)
1804 CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
1805 CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned)
1806 CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
1807 CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
1808 CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
1809 static const ctl_named_node_t *
1810 arenas_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
1818 CTL_RO_NL_GEN(arenas_nlruns, nlclasses, unsigned)
1819 CTL_RO_NL_GEN(arenas_lrun_i_size, index2size(NBINS+mib[2]), size_t)
1820 static const ctl_named_node_t *
1821 arenas_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
1829 CTL_RO_NL_GEN(arenas_nhchunks, nhclasses, unsigned)
1830 CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+nlclasses+mib[2]), size_t)
1831 static const ctl_named_node_t *
1832 arenas_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
1840 static int
1841 arenas_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;
1857 label_return:
1858         malloc_mutex_unlock(&ctl_mtx);
1859         return (ret);
1860 }
1861
1862 /******************************************************************************/
1863
1864 static int
1865 prof_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;
1885 label_return:
1886         return (ret);
1887 }
1888
1889 static int
1890 prof_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;
1910 label_return:
1911         return (ret);
1912 }
1913
1914 static int
1915 prof_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;
1933 label_return:
1934         return (ret);
1935 }
1936
1937 static int
1938 prof_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;
1958 label_return:
1959         return (ret);
1960 }
1961
1962 static int
1963 prof_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;
1983 label_return:
1984         return (ret);
1985 }
1986
1987 CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
1988 CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t)
1989
1990 /******************************************************************************/
1991
1992 CTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *)
1993 CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t)
1994 CTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t)
1995 CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats.metadata, size_t)
1996 CTL_RO_CGEN(config_stats, stats_resident, ctl_stats.resident, size_t)
1997 CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t)
1998
1999 CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *)
2000 CTL_RO_GEN(stats_arenas_i_lg_dirty_mult, ctl_stats.arenas[mib[2]].lg_dirty_mult,
2001     ssize_t)
2002 CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
2003 CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
2004 CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
2005 CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
2006     ctl_stats.arenas[mib[2]].astats.mapped, size_t)
2007 CTL_RO_CGEN(config_stats, stats_arenas_i_npurge,
2008     ctl_stats.arenas[mib[2]].astats.npurge, uint64_t)
2009 CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise,
2010     ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t)
2011 CTL_RO_CGEN(config_stats, stats_arenas_i_purged,
2012     ctl_stats.arenas[mib[2]].astats.purged, uint64_t)
2013 CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_mapped,
2014     ctl_stats.arenas[mib[2]].astats.metadata_mapped, size_t)
2015 CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_allocated,
2016     ctl_stats.arenas[mib[2]].astats.metadata_allocated, size_t)
2017
2018 CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
2019     ctl_stats.arenas[mib[2]].allocated_small, size_t)
2020 CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
2021     ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t)
2022 CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
2023     ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t)
2024 CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
2025     ctl_stats.arenas[mib[2]].nrequests_small, uint64_t)
2026 CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
2027     ctl_stats.arenas[mib[2]].astats.allocated_large, size_t)
2028 CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
2029     ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t)
2030 CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
2031     ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t)
2032 CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
2033     ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t)
2034 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated,
2035     ctl_stats.arenas[mib[2]].astats.allocated_huge, size_t)
2036 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc,
2037     ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t)
2038 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_ndalloc,
2039     ctl_stats.arenas[mib[2]].astats.ndalloc_huge, uint64_t)
2040 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nrequests,
2041     ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) /* Intentional. */
2042
2043 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
2044     ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t)
2045 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
2046     ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t)
2047 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
2048     ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t)
2049 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs,
2050     ctl_stats.arenas[mib[2]].bstats[mib[4]].curregs, size_t)
2051 CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills,
2052     ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t)
2053 CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes,
2054     ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t)
2055 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns,
2056     ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t)
2057 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns,
2058     ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t)
2059 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns,
2060     ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t)
2061
2062 static const ctl_named_node_t *
2063 stats_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
2071 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc,
2072     ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t)
2073 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc,
2074     ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t)
2075 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests,
2076     ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t)
2077 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns,
2078     ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t)
2079
2080 static const ctl_named_node_t *
2081 stats_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
2089 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nmalloc,
2090     ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, uint64_t)
2091 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_ndalloc,
2092     ctl_stats.arenas[mib[2]].hstats[mib[4]].ndalloc, uint64_t)
2093 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nrequests,
2094     ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, /* Intentional. */
2095     uint64_t)
2096 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_curhchunks,
2097     ctl_stats.arenas[mib[2]].hstats[mib[4]].curhchunks, size_t)
2098
2099 static const ctl_named_node_t *
2100 stats_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
2108 static const ctl_named_node_t *
2109 stats_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;
2120 label_return:
2121         malloc_mutex_unlock(&ctl_mtx);
2122         return (ret);
2123 }