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