blob: 2ed9491d4984e6cef0e6a56de8d14461b311fd6e [file] [log] [blame]
Jason Evans289053c2009-06-22 12:08:42 -07001/*-
Jason Evans804c9ec2009-06-22 17:44:33 -07002 * Copyright (C) 2009 Facebook, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * * Neither the name of Facebook, Inc. nor the names of its contributors may
13 * be used to endorse or promote products derived from this software without
14 * specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 *******************************************************************************
29 *
Jason Evans289053c2009-06-22 12:08:42 -070030 * Copyright (C) 2006-2008 Jason Evans <jasone@FreeBSD.org>.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice(s), this list of conditions and the following disclaimer as
38 * the first lines of this file unmodified other than the possible
39 * addition of one or more copyright notices.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice(s), this list of conditions and the following disclaimer in
42 * the documentation and/or other materials provided with the
43 * distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
46 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
49 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
52 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
54 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
55 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 *
57 *******************************************************************************
58 *
59 * This allocator implementation is designed to provide scalable performance
60 * for multi-threaded programs on multi-processor systems. The following
61 * features are included for this purpose:
62 *
63 * + Multiple arenas are used if there are multiple CPUs, which reduces lock
64 * contention and cache sloshing.
65 *
66 * + Thread-specific caching is used if there are multiple threads, which
67 * reduces the amount of locking.
68 *
69 * + Cache line sharing between arenas is avoided for internal data
70 * structures.
71 *
72 * + Memory is managed in chunks and runs (chunks can be split into runs),
73 * rather than as individual pages. This provides a constant-time
74 * mechanism for associating allocations with particular arenas.
75 *
76 * Allocation requests are rounded up to the nearest size class, and no record
77 * of the original request size is maintained. Allocations are broken into
78 * categories according to size class. Assuming runtime defaults, 4 kB pages
79 * and a 16 byte quantum on a 32-bit system, the size classes in each category
80 * are as follows:
81 *
82 * |=======================================|
83 * | Category | Subcategory | Size |
84 * |=======================================|
85 * | Small | Tiny | 2 |
86 * | | | 4 |
87 * | | | 8 |
88 * | |------------------+---------|
89 * | | Quantum-spaced | 16 |
90 * | | | 32 |
91 * | | | 48 |
92 * | | | ... |
93 * | | | 96 |
94 * | | | 112 |
95 * | | | 128 |
96 * | |------------------+---------|
97 * | | Cacheline-spaced | 192 |
98 * | | | 256 |
99 * | | | 320 |
100 * | | | 384 |
101 * | | | 448 |
102 * | | | 512 |
103 * | |------------------+---------|
104 * | | Sub-page | 760 |
105 * | | | 1024 |
106 * | | | 1280 |
107 * | | | ... |
108 * | | | 3328 |
109 * | | | 3584 |
110 * | | | 3840 |
111 * |=======================================|
112 * | Large | 4 kB |
113 * | | 8 kB |
114 * | | 12 kB |
115 * | | ... |
116 * | | 1012 kB |
117 * | | 1016 kB |
118 * | | 1020 kB |
119 * |=======================================|
120 * | Huge | 1 MB |
121 * | | 2 MB |
122 * | | 3 MB |
123 * | | ... |
124 * |=======================================|
125 *
126 * A different mechanism is used for each category:
127 *
128 * Small : Each size class is segregated into its own set of runs. Each run
129 * maintains a bitmap of which regions are free/allocated.
130 *
131 * Large : Each allocation is backed by a dedicated run. Metadata are stored
132 * in the associated arena chunk header maps.
133 *
134 * Huge : Each allocation is backed by a dedicated contiguous set of chunks.
135 * Metadata are stored in a separate red-black tree.
136 *
137 *******************************************************************************
138 */
139
Jason Evansb7924f52009-06-23 19:01:18 -0700140#include "jemalloc_defs.h"
141
142#if 0
143__FBSDID("$FreeBSD: src/lib/libc/stdlib/malloc.c,v 1.183 2008/12/01 10:20:59 jasone Exp $");
Jason Evansc9658dd2009-06-22 14:44:08 -0700144#endif
145
Jason Evans289053c2009-06-22 12:08:42 -0700146#include <sys/mman.h>
147#include <sys/param.h>
Jason Evans289053c2009-06-22 12:08:42 -0700148#include <sys/time.h>
149#include <sys/types.h>
150#include <sys/sysctl.h>
151#include <sys/uio.h>
Jason Evans289053c2009-06-22 12:08:42 -0700152
153#include <errno.h>
154#include <limits.h>
Jason Evansc9658dd2009-06-22 14:44:08 -0700155#ifndef SIZE_T_MAX
156# define SIZE_T_MAX SIZE_MAX
157#endif
Jason Evans289053c2009-06-22 12:08:42 -0700158#include <pthread.h>
159#include <sched.h>
160#include <stdarg.h>
161#include <stdbool.h>
162#include <stdio.h>
163#include <stdint.h>
164#include <stdlib.h>
165#include <string.h>
166#include <strings.h>
167#include <unistd.h>
Jason Evansc9658dd2009-06-22 14:44:08 -0700168#include <fcntl.h>
169#include <pthread.h>
Jason Evansb7924f52009-06-23 19:01:18 -0700170#ifdef JEMALLOC_LAZY_LOCK
171#include <dlfcn.h>
172#endif
173
174#ifndef __DECONST
175# define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
176#endif
Jason Evans289053c2009-06-22 12:08:42 -0700177
178#include "rb.h"
179
Jason Evansb7924f52009-06-23 19:01:18 -0700180#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -0700181 /* Disable inlining to make debugging easier. */
182# define inline
183#endif
184
185/* Size of stack-allocated buffer passed to strerror_r(). */
186#define STRERROR_BUF 64
187
188/*
189 * Minimum alignment of allocations is 2^QUANTUM_2POW bytes.
190 */
191#ifdef __i386__
192# define QUANTUM_2POW 4
Jason Evans289053c2009-06-22 12:08:42 -0700193#endif
194#ifdef __ia64__
195# define QUANTUM_2POW 4
Jason Evans289053c2009-06-22 12:08:42 -0700196#endif
197#ifdef __alpha__
198# define QUANTUM_2POW 4
Jason Evans289053c2009-06-22 12:08:42 -0700199#endif
200#ifdef __sparc64__
201# define QUANTUM_2POW 4
Jason Evans289053c2009-06-22 12:08:42 -0700202#endif
203#ifdef __amd64__
204# define QUANTUM_2POW 4
Jason Evans289053c2009-06-22 12:08:42 -0700205#endif
206#ifdef __arm__
207# define QUANTUM_2POW 3
Jason Evans289053c2009-06-22 12:08:42 -0700208#endif
209#ifdef __mips__
210# define QUANTUM_2POW 3
Jason Evans289053c2009-06-22 12:08:42 -0700211#endif
212#ifdef __powerpc__
213# define QUANTUM_2POW 4
Jason Evans289053c2009-06-22 12:08:42 -0700214#endif
215
216#define QUANTUM ((size_t)(1U << QUANTUM_2POW))
217#define QUANTUM_MASK (QUANTUM - 1)
218
219#define SIZEOF_PTR (1U << SIZEOF_PTR_2POW)
220
221/* sizeof(int) == (1U << SIZEOF_INT_2POW). */
222#ifndef SIZEOF_INT_2POW
223# define SIZEOF_INT_2POW 2
224#endif
225
226/* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */
227#if (!defined(PIC) && !defined(NO_TLS))
228# define NO_TLS
229#endif
230
231#ifdef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -0700232 /* JEMALLOC_MAG requires TLS. */
233# ifdef JEMALLOC_MAG
234# undef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700235# endif
Jason Evansb7924f52009-06-23 19:01:18 -0700236 /* JEMALLOC_BALANCE requires TLS. */
237# ifdef JEMALLOC_BALANCE
238# undef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -0700239# endif
240#endif
241
242/*
243 * Size and alignment of memory chunks that are allocated by the OS's virtual
244 * memory system.
245 */
246#define CHUNK_2POW_DEFAULT 20
247
248/* Maximum number of dirty pages per arena. */
249#define DIRTY_MAX_DEFAULT (1U << 9)
250
251/*
252 * Maximum size of L1 cache line. This is used to avoid cache line aliasing.
253 * In addition, this controls the spacing of cacheline-spaced size classes.
254 */
255#define CACHELINE_2POW 6
256#define CACHELINE ((size_t)(1U << CACHELINE_2POW))
257#define CACHELINE_MASK (CACHELINE - 1)
258
259/*
260 * Subpages are an artificially designated partitioning of pages. Their only
261 * purpose is to support subpage-spaced size classes.
262 *
263 * There must be at least 4 subpages per page, due to the way size classes are
264 * handled.
265 */
266#define SUBPAGE_2POW 8
267#define SUBPAGE ((size_t)(1U << SUBPAGE_2POW))
268#define SUBPAGE_MASK (SUBPAGE - 1)
269
Jason Evansb7924f52009-06-23 19:01:18 -0700270#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700271 /* Smallest size class to support. */
272# define TINY_MIN_2POW 1
273#endif
274
275/*
276 * Maximum size class that is a multiple of the quantum, but not (necessarily)
277 * a power of 2. Above this size, allocations are rounded up to the nearest
278 * power of 2.
279 */
280#define QSPACE_MAX_2POW_DEFAULT 7
281
282/*
283 * Maximum size class that is a multiple of the cacheline, but not (necessarily)
284 * a power of 2. Above this size, allocations are rounded up to the nearest
285 * power of 2.
286 */
287#define CSPACE_MAX_2POW_DEFAULT 9
288
289/*
290 * RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized
291 * as small as possible such that this setting is still honored, without
292 * violating other constraints. The goal is to make runs as small as possible
293 * without exceeding a per run external fragmentation threshold.
294 *
295 * We use binary fixed point math for overhead computations, where the binary
296 * point is implicitly RUN_BFP bits to the left.
297 *
298 * Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be
299 * honored for some/all object sizes, since there is one bit of header overhead
300 * per object (plus a constant). This constraint is relaxed (ignored) for runs
301 * that are so small that the per-region overhead is greater than:
302 *
303 * (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
304 */
305#define RUN_BFP 12
306/* \/ Implicit binary fixed point. */
307#define RUN_MAX_OVRHD 0x0000003dU
308#define RUN_MAX_OVRHD_RELAX 0x00001800U
309
310/* Put a cap on small object run size. This overrides RUN_MAX_OVRHD. */
311#define RUN_MAX_SMALL (12 * PAGE_SIZE)
312
313/*
Jason Evans289053c2009-06-22 12:08:42 -0700314 * Adaptive spinning must eventually switch to blocking, in order to avoid the
315 * potential for priority inversion deadlock. Backing off past a certain point
316 * can actually waste time.
317 */
318#define SPIN_LIMIT_2POW 11
319
320/*
321 * Conversion from spinning to blocking is expensive; we use (1U <<
322 * BLOCK_COST_2POW) to estimate how many more times costly blocking is than
323 * worst-case spinning.
324 */
325#define BLOCK_COST_2POW 4
326
Jason Evansb7924f52009-06-23 19:01:18 -0700327#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700328 /*
329 * Default magazine size, in bytes. max_rounds is calculated to make
330 * optimal use of the space, leaving just enough room for the magazine
331 * header.
332 */
333# define MAG_SIZE_2POW_DEFAULT 9
334#endif
335
Jason Evansb7924f52009-06-23 19:01:18 -0700336#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -0700337 /*
338 * We use an exponential moving average to track recent lock contention,
339 * where the size of the history window is N, and alpha=2/(N+1).
340 *
341 * Due to integer math rounding, very small values here can cause
342 * substantial degradation in accuracy, thus making the moving average decay
343 * faster than it would with precise calculation.
344 */
345# define BALANCE_ALPHA_INV_2POW 9
346
347 /*
348 * Threshold value for the exponential moving contention average at which to
349 * re-assign a thread.
350 */
351# define BALANCE_THRESHOLD_DEFAULT (1U << (SPIN_LIMIT_2POW-4))
352#endif
353
354/******************************************************************************/
355
Jason Evansc9658dd2009-06-22 14:44:08 -0700356typedef pthread_mutex_t malloc_mutex_t;
357typedef pthread_mutex_t malloc_spinlock_t;
Jason Evans289053c2009-06-22 12:08:42 -0700358
359/* Set to true once the allocator has been initialized. */
360static bool malloc_initialized = false;
361
Jason Evansb7924f52009-06-23 19:01:18 -0700362/* Used to let the initializing thread recursively allocate. */
363static pthread_t malloc_initializer = (unsigned long)0;
364
Jason Evans289053c2009-06-22 12:08:42 -0700365/* Used to avoid initialization races. */
Jason Evansc9658dd2009-06-22 14:44:08 -0700366static malloc_mutex_t init_lock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
Jason Evans289053c2009-06-22 12:08:42 -0700367
368/******************************************************************************/
369/*
370 * Statistics data structures.
371 */
372
Jason Evansb7924f52009-06-23 19:01:18 -0700373#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700374
375typedef struct malloc_bin_stats_s malloc_bin_stats_t;
376struct malloc_bin_stats_s {
377 /*
378 * Number of allocation requests that corresponded to the size of this
379 * bin.
380 */
381 uint64_t nrequests;
382
Jason Evansb7924f52009-06-23 19:01:18 -0700383#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700384 /* Number of magazine reloads from this bin. */
385 uint64_t nmags;
386#endif
387
388 /* Total number of runs created for this bin's size class. */
389 uint64_t nruns;
390
391 /*
392 * Total number of runs reused by extracting them from the runs tree for
393 * this bin's size class.
394 */
395 uint64_t reruns;
396
397 /* High-water mark for this bin. */
398 unsigned long highruns;
399
400 /* Current number of runs in this bin. */
401 unsigned long curruns;
402};
403
404typedef struct arena_stats_s arena_stats_t;
405struct arena_stats_s {
406 /* Number of bytes currently mapped. */
407 size_t mapped;
408
409 /*
410 * Total number of purge sweeps, total number of madvise calls made,
411 * and total pages purged in order to keep dirty unused memory under
412 * control.
413 */
414 uint64_t npurge;
415 uint64_t nmadvise;
416 uint64_t purged;
417
418 /* Per-size-category statistics. */
419 size_t allocated_small;
420 uint64_t nmalloc_small;
421 uint64_t ndalloc_small;
422
423 size_t allocated_large;
424 uint64_t nmalloc_large;
425 uint64_t ndalloc_large;
426
Jason Evansb7924f52009-06-23 19:01:18 -0700427#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -0700428 /* Number of times this arena reassigned a thread due to contention. */
429 uint64_t nbalance;
430#endif
431};
432
433typedef struct chunk_stats_s chunk_stats_t;
434struct chunk_stats_s {
435 /* Number of chunks that were allocated. */
436 uint64_t nchunks;
437
438 /* High-water mark for number of chunks allocated. */
439 unsigned long highchunks;
440
441 /*
442 * Current number of chunks allocated. This value isn't maintained for
443 * any other purpose, so keep track of it in order to be able to set
444 * highchunks.
445 */
446 unsigned long curchunks;
447};
448
Jason Evansb7924f52009-06-23 19:01:18 -0700449#endif /* #ifdef JEMALLOC_STATS */
Jason Evans289053c2009-06-22 12:08:42 -0700450
451/******************************************************************************/
452/*
453 * Extent data structures.
454 */
455
456/* Tree of extents. */
457typedef struct extent_node_s extent_node_t;
458struct extent_node_s {
Jason Evansb7924f52009-06-23 19:01:18 -0700459#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -0700460 /* Linkage for the size/address-ordered tree. */
461 rb_node(extent_node_t) link_szad;
462#endif
463
464 /* Linkage for the address-ordered tree. */
465 rb_node(extent_node_t) link_ad;
466
467 /* Pointer to the extent that this tree node is responsible for. */
468 void *addr;
469
470 /* Total region size. */
471 size_t size;
472};
473typedef rb_tree(extent_node_t) extent_tree_t;
474
475/******************************************************************************/
476/*
477 * Arena data structures.
478 */
479
480typedef struct arena_s arena_t;
481typedef struct arena_bin_s arena_bin_t;
482
483/* Each element of the chunk map corresponds to one page within the chunk. */
484typedef struct arena_chunk_map_s arena_chunk_map_t;
485struct arena_chunk_map_s {
486 /*
487 * Linkage for run trees. There are two disjoint uses:
488 *
489 * 1) arena_t's runs_avail tree.
490 * 2) arena_run_t conceptually uses this linkage for in-use non-full
491 * runs, rather than directly embedding linkage.
492 */
493 rb_node(arena_chunk_map_t) link;
494
495 /*
496 * Run address (or size) and various flags are stored together. The bit
497 * layout looks like (assuming 32-bit system):
498 *
499 * ???????? ???????? ????---- ---kdzla
500 *
501 * ? : Unallocated: Run address for first/last pages, unset for internal
502 * pages.
503 * Small: Run address.
504 * Large: Run size for first page, unset for trailing pages.
505 * - : Unused.
506 * k : key?
507 * d : dirty?
508 * z : zeroed?
509 * l : large?
510 * a : allocated?
511 *
512 * Following are example bit patterns for the three types of runs.
513 *
514 * r : run address
515 * s : run size
516 * x : don't care
517 * - : 0
518 * [dzla] : bit set
519 *
520 * Unallocated:
521 * ssssssss ssssssss ssss---- --------
522 * xxxxxxxx xxxxxxxx xxxx---- ----d---
523 * ssssssss ssssssss ssss---- -----z--
524 *
525 * Small:
526 * rrrrrrrr rrrrrrrr rrrr---- -------a
527 * rrrrrrrr rrrrrrrr rrrr---- -------a
528 * rrrrrrrr rrrrrrrr rrrr---- -------a
529 *
530 * Large:
531 * ssssssss ssssssss ssss---- ------la
532 * -------- -------- -------- ------la
533 * -------- -------- -------- ------la
534 */
535 size_t bits;
536#define CHUNK_MAP_KEY ((size_t)0x10U)
537#define CHUNK_MAP_DIRTY ((size_t)0x08U)
538#define CHUNK_MAP_ZEROED ((size_t)0x04U)
539#define CHUNK_MAP_LARGE ((size_t)0x02U)
540#define CHUNK_MAP_ALLOCATED ((size_t)0x01U)
541};
542typedef rb_tree(arena_chunk_map_t) arena_avail_tree_t;
543typedef rb_tree(arena_chunk_map_t) arena_run_tree_t;
544
545/* Arena chunk header. */
546typedef struct arena_chunk_s arena_chunk_t;
547struct arena_chunk_s {
548 /* Arena that owns the chunk. */
549 arena_t *arena;
550
551 /* Linkage for the arena's chunks_dirty tree. */
552 rb_node(arena_chunk_t) link_dirty;
553
554 /* Number of dirty pages. */
555 size_t ndirty;
556
557 /* Map of pages within chunk that keeps track of free/large/small. */
558 arena_chunk_map_t map[1]; /* Dynamically sized. */
559};
560typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
561
562typedef struct arena_run_s arena_run_t;
563struct arena_run_s {
Jason Evansb7924f52009-06-23 19:01:18 -0700564#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -0700565 uint32_t magic;
566# define ARENA_RUN_MAGIC 0x384adf93
567#endif
568
569 /* Bin this run is associated with. */
570 arena_bin_t *bin;
571
572 /* Index of first element that might have a free region. */
573 unsigned regs_minelm;
574
575 /* Number of free regions in run. */
576 unsigned nfree;
577
578 /* Bitmask of in-use regions (0: in use, 1: free). */
579 unsigned regs_mask[1]; /* Dynamically sized. */
580};
581
582struct arena_bin_s {
583 /*
584 * Current run being used to service allocations of this bin's size
585 * class.
586 */
587 arena_run_t *runcur;
588
589 /*
590 * Tree of non-full runs. This tree is used when looking for an
591 * existing run when runcur is no longer usable. We choose the
592 * non-full run that is lowest in memory; this policy tends to keep
593 * objects packed well, and it can also help reduce the number of
594 * almost-empty chunks.
595 */
596 arena_run_tree_t runs;
597
598 /* Size of regions in a run for this bin's size class. */
599 size_t reg_size;
600
601 /* Total size of a run for this bin's size class. */
602 size_t run_size;
603
604 /* Total number of regions in a run for this bin's size class. */
605 uint32_t nregs;
606
607 /* Number of elements in a run's regs_mask for this bin's size class. */
608 uint32_t regs_mask_nelms;
609
610 /* Offset of first region in a run for this bin's size class. */
611 uint32_t reg0_offset;
612
Jason Evansb7924f52009-06-23 19:01:18 -0700613#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700614 /* Bin statistics. */
615 malloc_bin_stats_t stats;
616#endif
617};
618
619struct arena_s {
Jason Evansb7924f52009-06-23 19:01:18 -0700620#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -0700621 uint32_t magic;
622# define ARENA_MAGIC 0x947d3d24
623#endif
624
625 /* All operations on this arena require that lock be locked. */
626 pthread_mutex_t lock;
627
Jason Evansb7924f52009-06-23 19:01:18 -0700628#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700629 arena_stats_t stats;
630#endif
631
632 /* Tree of dirty-page-containing chunks this arena manages. */
633 arena_chunk_tree_t chunks_dirty;
634
635 /*
636 * In order to avoid rapid chunk allocation/deallocation when an arena
637 * oscillates right on the cusp of needing a new chunk, cache the most
638 * recently freed chunk. The spare is left in the arena's chunk trees
639 * until it is deleted.
640 *
641 * There is one spare chunk per arena, rather than one spare total, in
642 * order to avoid interactions between multiple threads that could make
643 * a single spare inadequate.
644 */
645 arena_chunk_t *spare;
646
647 /*
648 * Current count of pages within unused runs that are potentially
Jason Evansc9658dd2009-06-22 14:44:08 -0700649 * dirty, and for which madvise(... MADV_DONTNEED) has not been called.
650 * By tracking this, we can institute a limit on how much dirty unused
Jason Evans289053c2009-06-22 12:08:42 -0700651 * memory is mapped for each arena.
652 */
653 size_t ndirty;
654
655 /*
656 * Size/address-ordered tree of this arena's available runs. This tree
657 * is used for first-best-fit run allocation.
658 */
659 arena_avail_tree_t runs_avail;
660
Jason Evansb7924f52009-06-23 19:01:18 -0700661#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -0700662 /*
663 * The arena load balancing machinery needs to keep track of how much
664 * lock contention there is. This value is exponentially averaged.
665 */
666 uint32_t contention;
667#endif
668
669 /*
670 * bins is used to store rings of free regions of the following sizes,
671 * assuming a 16-byte quantum, 4kB page size, and default
Jason Evans804c9ec2009-06-22 17:44:33 -0700672 * JEMALLOC_OPTIONS.
Jason Evans289053c2009-06-22 12:08:42 -0700673 *
674 * bins[i] | size |
675 * --------+------+
676 * 0 | 2 |
677 * 1 | 4 |
678 * 2 | 8 |
679 * --------+------+
680 * 3 | 16 |
681 * 4 | 32 |
682 * 5 | 48 |
Jason Evans289053c2009-06-22 12:08:42 -0700683 * : :
Jason Evansa9b01252009-06-26 16:34:13 -0700684 * 8 | 96 |
685 * 9 | 112 |
686 * 10 | 128 |
Jason Evans289053c2009-06-22 12:08:42 -0700687 * --------+------+
Jason Evansa9b01252009-06-26 16:34:13 -0700688 * 11 | 192 |
689 * 12 | 256 |
690 * 13 | 320 |
691 * 14 | 384 |
692 * 15 | 448 |
693 * 16 | 512 |
694 * --------+------+
695 * 17 | 768 |
696 * 18 | 1024 |
697 * 19 | 1280 |
698 * : :
699 * 27 | 3328 |
700 * 28 | 3584 |
701 * 29 | 3840 |
Jason Evans289053c2009-06-22 12:08:42 -0700702 * --------+------+
703 */
704 arena_bin_t bins[1]; /* Dynamically sized. */
705};
706
707/******************************************************************************/
708/*
709 * Magazine data structures.
710 */
711
Jason Evansb7924f52009-06-23 19:01:18 -0700712#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700713typedef struct mag_s mag_t;
714struct mag_s {
715 size_t binind; /* Index of associated bin. */
716 size_t nrounds;
717 void *rounds[1]; /* Dynamically sized. */
718};
719
720/*
721 * Magazines are lazily allocated, but once created, they remain until the
722 * associated mag_rack is destroyed.
723 */
724typedef struct bin_mags_s bin_mags_t;
725struct bin_mags_s {
726 mag_t *curmag;
727 mag_t *sparemag;
728};
729
730typedef struct mag_rack_s mag_rack_t;
731struct mag_rack_s {
732 bin_mags_t bin_mags[1]; /* Dynamically sized. */
733};
734#endif
735
736/******************************************************************************/
737/*
738 * Data.
739 */
740
Jason Evansb7924f52009-06-23 19:01:18 -0700741#ifdef JEMALLOC_LAZY_LOCK
742static bool isthreaded = false;
743#else
744# define isthreaded true
745#endif
746
Jason Evans289053c2009-06-22 12:08:42 -0700747/* Number of CPUs. */
748static unsigned ncpus;
749
Jason Evansb7924f52009-06-23 19:01:18 -0700750/*
751 * Page size. STATIC_PAGE_SHIFT is determined by the configure script. If
752 * DYNAMIC_PAGE_SHIFT is enabled, only use the STATIC_PAGE_* macros where
753 * compile-time values are required for the purposes of defining data
754 * structures.
755 */
756#define STATIC_PAGE_SIZE ((size_t)(1U << STATIC_PAGE_SHIFT))
757#define STATIC_PAGE_MASK ((size_t)(STATIC_PAGE_SIZE - 1))
758
759#ifdef DYNAMIC_PAGE_SHIFT
760static size_t pagesize;
761static size_t pagesize_mask;
762static size_t pagesize_2pow;
763# define PAGE_SHIFT pagesize_2pow
764# define PAGE_SIZE pagesize
765# define PAGE_MASK pagesize_mask
766#else
767# define PAGE_SHIFT STATIC_PAGE_SHIFT
768# define PAGE_SIZE STATIC_PAGE_SIZE
769# define PAGE_MASK STATIC_PAGE_MASK
770#endif
771
Jason Evans289053c2009-06-22 12:08:42 -0700772/* Various bin-related settings. */
Jason Evansb7924f52009-06-23 19:01:18 -0700773#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
Jason Evans289053c2009-06-22 12:08:42 -0700774# define ntbins ((unsigned)(QUANTUM_2POW - TINY_MIN_2POW))
775#else
776# define ntbins 0
777#endif
778static unsigned nqbins; /* Number of quantum-spaced bins. */
779static unsigned ncbins; /* Number of cacheline-spaced bins. */
780static unsigned nsbins; /* Number of subpage-spaced bins. */
781static unsigned nbins;
Jason Evansb7924f52009-06-23 19:01:18 -0700782#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700783# define tspace_max ((size_t)(QUANTUM >> 1))
784#endif
785#define qspace_min QUANTUM
786static size_t qspace_max;
787static size_t cspace_min;
788static size_t cspace_max;
789static size_t sspace_min;
790static size_t sspace_max;
791#define bin_maxclass sspace_max
792
793static uint8_t const *size2bin;
794/*
795 * const_size2bin is a static constant lookup table that in the common case can
796 * be used as-is for size2bin. For dynamically linked programs, this avoids
797 * a page of memory overhead per process.
798 */
799#define S2B_1(i) i,
800#define S2B_2(i) S2B_1(i) S2B_1(i)
801#define S2B_4(i) S2B_2(i) S2B_2(i)
802#define S2B_8(i) S2B_4(i) S2B_4(i)
803#define S2B_16(i) S2B_8(i) S2B_8(i)
804#define S2B_32(i) S2B_16(i) S2B_16(i)
805#define S2B_64(i) S2B_32(i) S2B_32(i)
806#define S2B_128(i) S2B_64(i) S2B_64(i)
807#define S2B_256(i) S2B_128(i) S2B_128(i)
Jason Evansb7924f52009-06-23 19:01:18 -0700808static const uint8_t const_size2bin[STATIC_PAGE_SIZE - 255] = {
Jason Evans289053c2009-06-22 12:08:42 -0700809 S2B_1(0xffU) /* 0 */
810#if (QUANTUM_2POW == 4)
811/* 64-bit system ************************/
Jason Evansb7924f52009-06-23 19:01:18 -0700812# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700813 S2B_2(0) /* 2 */
814 S2B_2(1) /* 4 */
815 S2B_4(2) /* 8 */
816 S2B_8(3) /* 16 */
817# define S2B_QMIN 3
818# else
819 S2B_16(0) /* 16 */
820# define S2B_QMIN 0
821# endif
822 S2B_16(S2B_QMIN + 1) /* 32 */
823 S2B_16(S2B_QMIN + 2) /* 48 */
824 S2B_16(S2B_QMIN + 3) /* 64 */
825 S2B_16(S2B_QMIN + 4) /* 80 */
826 S2B_16(S2B_QMIN + 5) /* 96 */
827 S2B_16(S2B_QMIN + 6) /* 112 */
828 S2B_16(S2B_QMIN + 7) /* 128 */
829# define S2B_CMIN (S2B_QMIN + 8)
830#else
831/* 32-bit system ************************/
Jason Evansb7924f52009-06-23 19:01:18 -0700832# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700833 S2B_2(0) /* 2 */
834 S2B_2(1) /* 4 */
835 S2B_4(2) /* 8 */
836# define S2B_QMIN 2
837# else
838 S2B_8(0) /* 8 */
839# define S2B_QMIN 0
840# endif
841 S2B_8(S2B_QMIN + 1) /* 16 */
842 S2B_8(S2B_QMIN + 2) /* 24 */
843 S2B_8(S2B_QMIN + 3) /* 32 */
844 S2B_8(S2B_QMIN + 4) /* 40 */
845 S2B_8(S2B_QMIN + 5) /* 48 */
846 S2B_8(S2B_QMIN + 6) /* 56 */
847 S2B_8(S2B_QMIN + 7) /* 64 */
848 S2B_8(S2B_QMIN + 8) /* 72 */
849 S2B_8(S2B_QMIN + 9) /* 80 */
850 S2B_8(S2B_QMIN + 10) /* 88 */
851 S2B_8(S2B_QMIN + 11) /* 96 */
852 S2B_8(S2B_QMIN + 12) /* 104 */
853 S2B_8(S2B_QMIN + 13) /* 112 */
854 S2B_8(S2B_QMIN + 14) /* 120 */
855 S2B_8(S2B_QMIN + 15) /* 128 */
856# define S2B_CMIN (S2B_QMIN + 16)
857#endif
858/****************************************/
859 S2B_64(S2B_CMIN + 0) /* 192 */
860 S2B_64(S2B_CMIN + 1) /* 256 */
861 S2B_64(S2B_CMIN + 2) /* 320 */
862 S2B_64(S2B_CMIN + 3) /* 384 */
863 S2B_64(S2B_CMIN + 4) /* 448 */
864 S2B_64(S2B_CMIN + 5) /* 512 */
865# define S2B_SMIN (S2B_CMIN + 6)
866 S2B_256(S2B_SMIN + 0) /* 768 */
867 S2B_256(S2B_SMIN + 1) /* 1024 */
868 S2B_256(S2B_SMIN + 2) /* 1280 */
869 S2B_256(S2B_SMIN + 3) /* 1536 */
870 S2B_256(S2B_SMIN + 4) /* 1792 */
871 S2B_256(S2B_SMIN + 5) /* 2048 */
872 S2B_256(S2B_SMIN + 6) /* 2304 */
873 S2B_256(S2B_SMIN + 7) /* 2560 */
874 S2B_256(S2B_SMIN + 8) /* 2816 */
875 S2B_256(S2B_SMIN + 9) /* 3072 */
876 S2B_256(S2B_SMIN + 10) /* 3328 */
877 S2B_256(S2B_SMIN + 11) /* 3584 */
878 S2B_256(S2B_SMIN + 12) /* 3840 */
Jason Evansb7924f52009-06-23 19:01:18 -0700879#if (STATIC_PAGE_SHIFT == 13)
Jason Evans289053c2009-06-22 12:08:42 -0700880 S2B_256(S2B_SMIN + 13) /* 4096 */
881 S2B_256(S2B_SMIN + 14) /* 4352 */
882 S2B_256(S2B_SMIN + 15) /* 4608 */
883 S2B_256(S2B_SMIN + 16) /* 4864 */
884 S2B_256(S2B_SMIN + 17) /* 5120 */
885 S2B_256(S2B_SMIN + 18) /* 5376 */
886 S2B_256(S2B_SMIN + 19) /* 5632 */
887 S2B_256(S2B_SMIN + 20) /* 5888 */
888 S2B_256(S2B_SMIN + 21) /* 6144 */
889 S2B_256(S2B_SMIN + 22) /* 6400 */
890 S2B_256(S2B_SMIN + 23) /* 6656 */
891 S2B_256(S2B_SMIN + 24) /* 6912 */
892 S2B_256(S2B_SMIN + 25) /* 7168 */
893 S2B_256(S2B_SMIN + 26) /* 7424 */
894 S2B_256(S2B_SMIN + 27) /* 7680 */
895 S2B_256(S2B_SMIN + 28) /* 7936 */
896#endif
897};
898#undef S2B_1
899#undef S2B_2
900#undef S2B_4
901#undef S2B_8
902#undef S2B_16
903#undef S2B_32
904#undef S2B_64
905#undef S2B_128
906#undef S2B_256
907#undef S2B_QMIN
908#undef S2B_CMIN
909#undef S2B_SMIN
910
Jason Evansb7924f52009-06-23 19:01:18 -0700911#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700912static size_t max_rounds;
913#endif
914
915/* Various chunk-related settings. */
916static size_t chunksize;
917static size_t chunksize_mask; /* (chunksize - 1). */
918static size_t chunk_npages;
919static size_t arena_chunk_header_npages;
920static size_t arena_maxclass; /* Max size class for arenas. */
921
922/********/
923/*
924 * Chunks.
925 */
926
927/* Protects chunk-related data structures. */
928static malloc_mutex_t huge_mtx;
929
930/* Tree of chunks that are stand-alone huge allocations. */
931static extent_tree_t huge;
932
Jason Evansb7924f52009-06-23 19:01:18 -0700933#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -0700934/*
935 * Protects sbrk() calls. This avoids malloc races among threads, though it
936 * does not protect against races with threads that call sbrk() directly.
937 */
938static malloc_mutex_t dss_mtx;
939/* Base address of the DSS. */
940static void *dss_base;
941/* Current end of the DSS, or ((void *)-1) if the DSS is exhausted. */
942static void *dss_prev;
943/* Current upper limit on DSS addresses. */
944static void *dss_max;
945
946/*
947 * Trees of chunks that were previously allocated (trees differ only in node
948 * ordering). These are used when allocating chunks, in an attempt to re-use
949 * address space. Depending on function, different tree orderings are needed,
950 * which is why there are two trees with the same contents.
951 */
952static extent_tree_t dss_chunks_szad;
953static extent_tree_t dss_chunks_ad;
954#endif
955
Jason Evansb7924f52009-06-23 19:01:18 -0700956#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700957/* Huge allocation statistics. */
958static uint64_t huge_nmalloc;
959static uint64_t huge_ndalloc;
960static size_t huge_allocated;
961#endif
962
963/****************************/
964/*
965 * base (internal allocation).
966 */
967
968/*
969 * Current pages that are being used for internal memory allocations. These
970 * pages are carved up in cacheline-size quanta, so that there is no chance of
971 * false cache line sharing.
972 */
973static void *base_pages;
974static void *base_next_addr;
975static void *base_past_addr; /* Addr immediately past base_pages. */
976static extent_node_t *base_nodes;
977static malloc_mutex_t base_mtx;
Jason Evansb7924f52009-06-23 19:01:18 -0700978#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700979static size_t base_mapped;
980#endif
981
982/********/
983/*
984 * Arenas.
985 */
986
987/*
988 * Arenas that are used to service external requests. Not all elements of the
989 * arenas array are necessarily used; arenas are created lazily as needed.
990 */
991static arena_t **arenas;
992static unsigned narenas;
993#ifndef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -0700994# ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -0700995static unsigned narenas_2pow;
996# else
997static unsigned next_arena;
998# endif
999#endif
1000static pthread_mutex_t arenas_lock; /* Protects arenas initialization. */
1001
1002#ifndef NO_TLS
1003/*
1004 * Map of pthread_self() --> arenas[???], used for selecting an arena to use
1005 * for allocations.
1006 */
1007static __thread arena_t *arenas_map;
1008#endif
1009
Jason Evansb7924f52009-06-23 19:01:18 -07001010#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001011/*
1012 * Map of thread-specific magazine racks, used for thread-specific object
1013 * caching.
1014 */
1015static __thread mag_rack_t *mag_rack;
Jason Evansb7924f52009-06-23 19:01:18 -07001016
1017/*
1018 * Same contents as mag_rack, but initialized such that the TSD destructor is
1019 * called when a thread exits, so that the cache can be cleaned up.
1020 */
1021static pthread_key_t mag_rack_tsd;
Jason Evans289053c2009-06-22 12:08:42 -07001022#endif
1023
Jason Evansb7924f52009-06-23 19:01:18 -07001024#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001025/* Chunk statistics. */
1026static chunk_stats_t stats_chunks;
1027#endif
1028
1029/*******************************/
1030/*
1031 * Runtime configuration options.
1032 */
Jason Evans804c9ec2009-06-22 17:44:33 -07001033const char *jemalloc_options;
Jason Evans289053c2009-06-22 12:08:42 -07001034
Jason Evansb7924f52009-06-23 19:01:18 -07001035#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07001036static bool opt_abort = true;
Jason Evansb7924f52009-06-23 19:01:18 -07001037# ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001038static bool opt_junk = true;
Jason Evansb7924f52009-06-23 19:01:18 -07001039# endif
Jason Evans289053c2009-06-22 12:08:42 -07001040#else
1041static bool opt_abort = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001042# ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001043static bool opt_junk = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001044# endif
Jason Evans289053c2009-06-22 12:08:42 -07001045#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001046#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001047static bool opt_dss = true;
1048static bool opt_mmap = true;
1049#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001050#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001051static bool opt_mag = true;
1052static size_t opt_mag_size_2pow = MAG_SIZE_2POW_DEFAULT;
1053#endif
1054static size_t opt_dirty_max = DIRTY_MAX_DEFAULT;
Jason Evansb7924f52009-06-23 19:01:18 -07001055#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001056static uint64_t opt_balance_threshold = BALANCE_THRESHOLD_DEFAULT;
1057#endif
1058static bool opt_print_stats = false;
1059static size_t opt_qspace_max_2pow = QSPACE_MAX_2POW_DEFAULT;
1060static size_t opt_cspace_max_2pow = CSPACE_MAX_2POW_DEFAULT;
1061static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT;
Jason Evansb7924f52009-06-23 19:01:18 -07001062#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001063static bool opt_utrace = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001064#endif
1065#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07001066static bool opt_sysv = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001067#endif
Jason Evans289053c2009-06-22 12:08:42 -07001068static bool opt_xmalloc = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001069#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001070static bool opt_zero = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001071#endif
Jason Evans289053c2009-06-22 12:08:42 -07001072static int opt_narenas_lshift = 0;
1073
Jason Evansb7924f52009-06-23 19:01:18 -07001074#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001075typedef struct {
1076 void *p;
1077 size_t s;
1078 void *r;
1079} malloc_utrace_t;
1080
1081#define UTRACE(a, b, c) \
1082 if (opt_utrace) { \
1083 malloc_utrace_t ut; \
1084 ut.p = (a); \
1085 ut.s = (b); \
1086 ut.r = (c); \
1087 utrace(&ut, sizeof(ut)); \
1088 }
Jason Evansc9658dd2009-06-22 14:44:08 -07001089#else
1090#define UTRACE(a, b, c)
1091#endif
Jason Evans289053c2009-06-22 12:08:42 -07001092
1093/******************************************************************************/
1094/*
1095 * Begin function prototypes for non-inline static functions.
1096 */
1097
Jason Evansc9658dd2009-06-22 14:44:08 -07001098static bool malloc_mutex_init(malloc_mutex_t *mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001099static bool malloc_spin_init(pthread_mutex_t *lock);
1100static void wrtmessage(const char *p1, const char *p2, const char *p3,
1101 const char *p4);
Jason Evansb7924f52009-06-23 19:01:18 -07001102#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001103static void malloc_printf(const char *format, ...);
1104#endif
1105static char *umax2s(uintmax_t x, char *s);
Jason Evansb7924f52009-06-23 19:01:18 -07001106#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001107static bool base_pages_alloc_dss(size_t minsize);
1108#endif
1109static bool base_pages_alloc_mmap(size_t minsize);
1110static bool base_pages_alloc(size_t minsize);
1111static void *base_alloc(size_t size);
1112static void *base_calloc(size_t number, size_t size);
1113static extent_node_t *base_node_alloc(void);
1114static void base_node_dealloc(extent_node_t *node);
Jason Evansb7924f52009-06-23 19:01:18 -07001115#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001116static void stats_print(arena_t *arena);
1117#endif
1118static void *pages_map(void *addr, size_t size);
1119static void pages_unmap(void *addr, size_t size);
Jason Evansb7924f52009-06-23 19:01:18 -07001120#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001121static void *chunk_alloc_dss(size_t size);
1122static void *chunk_recycle_dss(size_t size, bool zero);
1123#endif
1124static void *chunk_alloc_mmap(size_t size);
1125static void *chunk_alloc(size_t size, bool zero);
Jason Evansb7924f52009-06-23 19:01:18 -07001126#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001127static extent_node_t *chunk_dealloc_dss_record(void *chunk, size_t size);
1128static bool chunk_dealloc_dss(void *chunk, size_t size);
1129#endif
1130static void chunk_dealloc_mmap(void *chunk, size_t size);
1131static void chunk_dealloc(void *chunk, size_t size);
1132#ifndef NO_TLS
1133static arena_t *choose_arena_hard(void);
1134#endif
1135static void arena_run_split(arena_t *arena, arena_run_t *run, size_t size,
1136 bool large, bool zero);
1137static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
1138static void arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
1139static arena_run_t *arena_run_alloc(arena_t *arena, size_t size, bool large,
1140 bool zero);
1141static void arena_purge(arena_t *arena);
1142static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty);
1143static void arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk,
1144 arena_run_t *run, size_t oldsize, size_t newsize);
1145static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk,
1146 arena_run_t *run, size_t oldsize, size_t newsize, bool dirty);
1147static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
1148static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
1149static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size);
Jason Evansb7924f52009-06-23 19:01:18 -07001150#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001151static void arena_lock_balance_hard(arena_t *arena);
1152#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001153#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001154static void mag_load(mag_t *mag);
1155#endif
1156static void *arena_malloc_large(arena_t *arena, size_t size, bool zero);
1157static void *arena_palloc(arena_t *arena, size_t alignment, size_t size,
1158 size_t alloc_size);
1159static size_t arena_salloc(const void *ptr);
Jason Evansb7924f52009-06-23 19:01:18 -07001160#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001161static void mag_unload(mag_t *mag);
1162#endif
1163static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk,
1164 void *ptr);
1165static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk,
1166 void *ptr, size_t size, size_t oldsize);
1167static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk,
1168 void *ptr, size_t size, size_t oldsize);
1169static bool arena_ralloc_large(void *ptr, size_t size, size_t oldsize);
1170static void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
1171static bool arena_new(arena_t *arena);
1172static arena_t *arenas_extend(unsigned ind);
Jason Evansb7924f52009-06-23 19:01:18 -07001173#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001174static mag_t *mag_create(arena_t *arena, size_t binind);
1175static void mag_destroy(mag_t *mag);
1176static mag_rack_t *mag_rack_create(arena_t *arena);
1177static void mag_rack_destroy(mag_rack_t *rack);
1178#endif
1179static void *huge_malloc(size_t size, bool zero);
1180static void *huge_palloc(size_t alignment, size_t size);
1181static void *huge_ralloc(void *ptr, size_t size, size_t oldsize);
1182static void huge_dalloc(void *ptr);
1183static void malloc_print_stats(void);
Jason Evansb7924f52009-06-23 19:01:18 -07001184#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07001185static void size2bin_validate(void);
1186#endif
1187static bool size2bin_init(void);
1188static bool size2bin_init_hard(void);
Jason Evansc9658dd2009-06-22 14:44:08 -07001189static unsigned malloc_ncpus(void);
Jason Evans289053c2009-06-22 12:08:42 -07001190static bool malloc_init_hard(void);
Jason Evansb7924f52009-06-23 19:01:18 -07001191static void thread_cleanup(void *arg);
Jason Evanscc00a152009-06-25 18:06:48 -07001192static void jemalloc_prefork(void);
1193static void jemalloc_postfork(void);
Jason Evans289053c2009-06-22 12:08:42 -07001194
1195/*
1196 * End function prototypes.
1197 */
1198/******************************************************************************/
Jason Evans289053c2009-06-22 12:08:42 -07001199
1200static void
Jason Evansc9658dd2009-06-22 14:44:08 -07001201wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
1202{
1203
Jason Evansb7924f52009-06-23 19:01:18 -07001204 if (write(STDERR_FILENO, p1, strlen(p1)) < 0
1205 || write(STDERR_FILENO, p2, strlen(p2)) < 0
1206 || write(STDERR_FILENO, p3, strlen(p3)) < 0
1207 || write(STDERR_FILENO, p4, strlen(p4)) < 0)
1208 return;
Jason Evansc9658dd2009-06-22 14:44:08 -07001209}
1210
Jason Evans804c9ec2009-06-22 17:44:33 -07001211void (*jemalloc_message)(const char *p1, const char *p2, const char *p3,
Jason Evansc9658dd2009-06-22 14:44:08 -07001212 const char *p4) = wrtmessage;
1213
1214/*
1215 * We don't want to depend on vsnprintf() for production builds, since that can
1216 * cause unnecessary bloat for static binaries. umax2s() provides minimal
1217 * integer printing functionality, so that malloc_printf() use can be limited to
Jason Evansb7924f52009-06-23 19:01:18 -07001218 * JEMALLOC_STATS code.
Jason Evansc9658dd2009-06-22 14:44:08 -07001219 */
1220#define UMAX2S_BUFSIZE 21
1221static char *
1222umax2s(uintmax_t x, char *s)
1223{
1224 unsigned i;
1225
1226 i = UMAX2S_BUFSIZE - 1;
1227 s[i] = '\0';
1228 do {
1229 i--;
1230 s[i] = "0123456789"[x % 10];
1231 x /= 10;
1232 } while (x > 0);
1233
1234 return (&s[i]);
1235}
1236
1237/*
1238 * Define a custom assert() in order to reduce the chances of deadlock during
1239 * assertion failure.
1240 */
Jason Evansb7924f52009-06-23 19:01:18 -07001241#ifdef JEMALLOC_DEBUG
Jason Evansc9658dd2009-06-22 14:44:08 -07001242# define assert(e) do { \
1243 if (!(e)) { \
1244 char line_buf[UMAX2S_BUFSIZE]; \
Jason Evanscc00a152009-06-25 18:06:48 -07001245 jemalloc_message("<jemalloc>: ", __FILE__, ":", \
1246 umax2s(__LINE__, line_buf)); \
1247 jemalloc_message(": Failed assertion: ", "\"", #e, \
1248 "\"\n"); \
Jason Evansc9658dd2009-06-22 14:44:08 -07001249 abort(); \
1250 } \
1251} while (0)
1252#else
1253#define assert(e)
1254#endif
1255
Jason Evansb7924f52009-06-23 19:01:18 -07001256#ifdef JEMALLOC_STATS
Jason Evansc9658dd2009-06-22 14:44:08 -07001257static int
1258utrace(const void *addr, size_t len)
1259{
1260 malloc_utrace_t *ut = (malloc_utrace_t *)addr;
1261
1262 assert(len == sizeof(malloc_utrace_t));
1263
1264 if (ut->p == NULL && ut->s == 0 && ut->r == NULL)
Jason Evanscc00a152009-06-25 18:06:48 -07001265 malloc_printf("<jemalloc>:utrace: %d malloc_init()\n",
1266 getpid());
Jason Evansc9658dd2009-06-22 14:44:08 -07001267 else if (ut->p == NULL && ut->r != NULL) {
Jason Evanscc00a152009-06-25 18:06:48 -07001268 malloc_printf("<jemalloc>:utrace: %d %p = malloc(%zu)\n",
1269 getpid(), ut->r, ut->s);
Jason Evansc9658dd2009-06-22 14:44:08 -07001270 } else if (ut->p != NULL && ut->r != NULL) {
Jason Evanscc00a152009-06-25 18:06:48 -07001271 malloc_printf("<jemalloc>:utrace: %d %p = realloc(%p, %zu)\n",
1272 getpid(), ut->r, ut->p, ut->s);
Jason Evansc9658dd2009-06-22 14:44:08 -07001273 } else
Jason Evanscc00a152009-06-25 18:06:48 -07001274 malloc_printf("<jemalloc>:utrace: %d free(%p)\n", getpid(),
1275 ut->p);
Jason Evansc9658dd2009-06-22 14:44:08 -07001276
1277 return (0);
1278}
1279#endif
1280
Jason Evansb7924f52009-06-23 19:01:18 -07001281#ifdef JEMALLOC_STATS
Jason Evansc9658dd2009-06-22 14:44:08 -07001282/*
1283 * Print to stderr in such a way as to (hopefully) avoid memory allocation.
1284 */
1285static void
1286malloc_printf(const char *format, ...)
1287{
1288 char buf[4096];
1289 va_list ap;
1290
1291 va_start(ap, format);
1292 vsnprintf(buf, sizeof(buf), format, ap);
1293 va_end(ap);
Jason Evans804c9ec2009-06-22 17:44:33 -07001294 jemalloc_message(buf, "", "", "");
Jason Evansc9658dd2009-06-22 14:44:08 -07001295}
1296#endif
1297
1298/******************************************************************************/
1299/*
Jason Evansb7924f52009-06-23 19:01:18 -07001300 * Begin pthreads integration. We intercept pthread_create() calls in order
1301 * to toggle isthreaded if the process goes multi-threaded.
1302 */
1303
1304#ifdef JEMALLOC_LAZY_LOCK
1305int (*pthread_create_fptr)(pthread_t *restrict, const pthread_attr_t *,
1306 void *(*)(void *), void *restrict);
1307
1308static void
1309get_pthread_create_fptr(void)
1310{
1311
1312 pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
1313 if (pthread_create_fptr == NULL) {
1314 jemalloc_message("<jemalloc>",
1315 ": Error in dlsym(RTLD_NEXT, \"pthread_create\")\n", "",
1316 "");
1317 abort();
1318 }
1319}
1320
1321int
1322pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,
1323 void *(*start_routine)(void *), void *restrict arg)
1324{
1325 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
1326
1327 pthread_once(&once_control, get_pthread_create_fptr);
1328
1329 isthreaded = true;
1330 return pthread_create_fptr(thread, attr, start_routine, arg);
1331}
1332#endif
1333
1334/******************************************************************************/
1335/*
Jason Evansc9658dd2009-06-22 14:44:08 -07001336 * Begin mutex.
1337 */
1338
1339static bool
Jason Evans289053c2009-06-22 12:08:42 -07001340malloc_mutex_init(malloc_mutex_t *mutex)
1341{
Jason Evansc9658dd2009-06-22 14:44:08 -07001342 pthread_mutexattr_t attr;
Jason Evans289053c2009-06-22 12:08:42 -07001343
Jason Evansc9658dd2009-06-22 14:44:08 -07001344 if (pthread_mutexattr_init(&attr) != 0)
1345 return (true);
1346 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1347 if (pthread_mutex_init(mutex, &attr) != 0) {
1348 pthread_mutexattr_destroy(&attr);
1349 return (true);
1350 }
1351 pthread_mutexattr_destroy(&attr);
1352
1353 return (false);
Jason Evans289053c2009-06-22 12:08:42 -07001354}
1355
1356static inline void
1357malloc_mutex_lock(malloc_mutex_t *mutex)
1358{
1359
Jason Evansb7924f52009-06-23 19:01:18 -07001360 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001361 pthread_mutex_lock(mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001362}
1363
1364static inline void
1365malloc_mutex_unlock(malloc_mutex_t *mutex)
1366{
1367
Jason Evansb7924f52009-06-23 19:01:18 -07001368 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001369 pthread_mutex_unlock(mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001370}
1371
1372/*
1373 * End mutex.
1374 */
1375/******************************************************************************/
1376/*
1377 * Begin spin lock. Spin locks here are actually adaptive mutexes that block
1378 * after a period of spinning, because unbounded spinning would allow for
1379 * priority inversion.
1380 */
1381
Jason Evans289053c2009-06-22 12:08:42 -07001382static bool
1383malloc_spin_init(pthread_mutex_t *lock)
1384{
1385
Jason Evansc9658dd2009-06-22 14:44:08 -07001386 if (pthread_mutex_init(lock, NULL) != 0)
Jason Evans289053c2009-06-22 12:08:42 -07001387 return (true);
1388
1389 return (false);
1390}
1391
1392static inline unsigned
1393malloc_spin_lock(pthread_mutex_t *lock)
1394{
1395 unsigned ret = 0;
1396
Jason Evansb7924f52009-06-23 19:01:18 -07001397 if (isthreaded) {
Jason Evansc9658dd2009-06-22 14:44:08 -07001398 if (pthread_mutex_trylock(lock) != 0) {
Jason Evans289053c2009-06-22 12:08:42 -07001399 /* Exponentially back off if there are multiple CPUs. */
1400 if (ncpus > 1) {
1401 unsigned i;
1402 volatile unsigned j;
1403
1404 for (i = 1; i <= SPIN_LIMIT_2POW; i++) {
1405 for (j = 0; j < (1U << i); j++) {
1406 ret++;
1407 CPU_SPINWAIT;
1408 }
1409
Jason Evansc9658dd2009-06-22 14:44:08 -07001410 if (pthread_mutex_trylock(lock) == 0)
Jason Evans289053c2009-06-22 12:08:42 -07001411 return (ret);
1412 }
1413 }
1414
1415 /*
1416 * Spinning failed. Block until the lock becomes
1417 * available, in order to avoid indefinite priority
1418 * inversion.
1419 */
Jason Evansc9658dd2009-06-22 14:44:08 -07001420 pthread_mutex_lock(lock);
Jason Evans289053c2009-06-22 12:08:42 -07001421 assert((ret << BLOCK_COST_2POW) != 0 || ncpus == 1);
1422 return (ret << BLOCK_COST_2POW);
1423 }
1424 }
1425
1426 return (ret);
1427}
1428
1429static inline void
1430malloc_spin_unlock(pthread_mutex_t *lock)
1431{
1432
Jason Evansb7924f52009-06-23 19:01:18 -07001433 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001434 pthread_mutex_unlock(lock);
Jason Evans289053c2009-06-22 12:08:42 -07001435}
1436
1437/*
1438 * End spin lock.
1439 */
1440/******************************************************************************/
1441/*
1442 * Begin Utility functions/macros.
1443 */
1444
1445/* Return the chunk address for allocation address a. */
1446#define CHUNK_ADDR2BASE(a) \
1447 ((void *)((uintptr_t)(a) & ~chunksize_mask))
1448
1449/* Return the chunk offset of address a. */
1450#define CHUNK_ADDR2OFFSET(a) \
1451 ((size_t)((uintptr_t)(a) & chunksize_mask))
1452
1453/* Return the smallest chunk multiple that is >= s. */
1454#define CHUNK_CEILING(s) \
1455 (((s) + chunksize_mask) & ~chunksize_mask)
1456
1457/* Return the smallest quantum multiple that is >= a. */
1458#define QUANTUM_CEILING(a) \
1459 (((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
1460
1461/* Return the smallest cacheline multiple that is >= s. */
1462#define CACHELINE_CEILING(s) \
1463 (((s) + CACHELINE_MASK) & ~CACHELINE_MASK)
1464
1465/* Return the smallest subpage multiple that is >= s. */
1466#define SUBPAGE_CEILING(s) \
1467 (((s) + SUBPAGE_MASK) & ~SUBPAGE_MASK)
1468
Jason Evansc9658dd2009-06-22 14:44:08 -07001469/* Return the smallest pagesize multiple that is >= s. */
Jason Evans289053c2009-06-22 12:08:42 -07001470#define PAGE_CEILING(s) \
Jason Evansb7924f52009-06-23 19:01:18 -07001471 (((s) + PAGE_MASK) & ~PAGE_MASK)
Jason Evans289053c2009-06-22 12:08:42 -07001472
Jason Evansb7924f52009-06-23 19:01:18 -07001473#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07001474/* Compute the smallest power of 2 that is >= x. */
1475static inline size_t
1476pow2_ceil(size_t x)
1477{
1478
1479 x--;
1480 x |= x >> 1;
1481 x |= x >> 2;
1482 x |= x >> 4;
1483 x |= x >> 8;
1484 x |= x >> 16;
1485#if (SIZEOF_PTR == 8)
1486 x |= x >> 32;
1487#endif
1488 x++;
1489 return (x);
1490}
1491#endif
1492
Jason Evansb7924f52009-06-23 19:01:18 -07001493#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001494/*
1495 * Use a simple linear congruential pseudo-random number generator:
1496 *
1497 * prn(y) = (a*x + c) % m
1498 *
1499 * where the following constants ensure maximal period:
1500 *
1501 * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4.
1502 * c == Odd number (relatively prime to 2^n).
1503 * m == 2^32
1504 *
1505 * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints.
1506 *
1507 * This choice of m has the disadvantage that the quality of the bits is
1508 * proportional to bit position. For example. the lowest bit has a cycle of 2,
1509 * the next has a cycle of 4, etc. For this reason, we prefer to use the upper
1510 * bits.
1511 */
1512# define PRN_DEFINE(suffix, var, a, c) \
1513static inline void \
1514sprn_##suffix(uint32_t seed) \
1515{ \
1516 var = seed; \
1517} \
1518 \
1519static inline uint32_t \
1520prn_##suffix(uint32_t lg_range) \
1521{ \
1522 uint32_t ret, x; \
1523 \
1524 assert(lg_range > 0); \
1525 assert(lg_range <= 32); \
1526 \
1527 x = (var * (a)) + (c); \
1528 var = x; \
1529 ret = x >> (32 - lg_range); \
1530 \
1531 return (ret); \
1532}
1533# define SPRN(suffix, seed) sprn_##suffix(seed)
1534# define PRN(suffix, lg_range) prn_##suffix(lg_range)
1535#endif
1536
Jason Evansb7924f52009-06-23 19:01:18 -07001537#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001538/* Define the PRNG used for arena assignment. */
1539static __thread uint32_t balance_x;
1540PRN_DEFINE(balance, balance_x, 1297, 1301)
1541#endif
1542
Jason Evans289053c2009-06-22 12:08:42 -07001543/******************************************************************************/
1544
Jason Evansb7924f52009-06-23 19:01:18 -07001545#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001546static bool
1547base_pages_alloc_dss(size_t minsize)
1548{
1549
1550 /*
1551 * Do special DSS allocation here, since base allocations don't need to
1552 * be chunk-aligned.
1553 */
1554 malloc_mutex_lock(&dss_mtx);
1555 if (dss_prev != (void *)-1) {
1556 intptr_t incr;
1557 size_t csize = CHUNK_CEILING(minsize);
1558
1559 do {
1560 /* Get the current end of the DSS. */
1561 dss_max = sbrk(0);
1562
1563 /*
1564 * Calculate how much padding is necessary to
1565 * chunk-align the end of the DSS. Don't worry about
1566 * dss_max not being chunk-aligned though.
1567 */
1568 incr = (intptr_t)chunksize
1569 - (intptr_t)CHUNK_ADDR2OFFSET(dss_max);
1570 assert(incr >= 0);
1571 if ((size_t)incr < minsize)
1572 incr += csize;
1573
1574 dss_prev = sbrk(incr);
1575 if (dss_prev == dss_max) {
1576 /* Success. */
1577 dss_max = (void *)((intptr_t)dss_prev + incr);
1578 base_pages = dss_prev;
1579 base_next_addr = base_pages;
1580 base_past_addr = dss_max;
Jason Evansb7924f52009-06-23 19:01:18 -07001581#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001582 base_mapped += incr;
1583#endif
1584 malloc_mutex_unlock(&dss_mtx);
1585 return (false);
1586 }
1587 } while (dss_prev != (void *)-1);
1588 }
1589 malloc_mutex_unlock(&dss_mtx);
1590
1591 return (true);
1592}
1593#endif
1594
1595static bool
1596base_pages_alloc_mmap(size_t minsize)
1597{
1598 size_t csize;
1599
1600 assert(minsize != 0);
1601 csize = PAGE_CEILING(minsize);
1602 base_pages = pages_map(NULL, csize);
1603 if (base_pages == NULL)
1604 return (true);
1605 base_next_addr = base_pages;
1606 base_past_addr = (void *)((uintptr_t)base_pages + csize);
Jason Evansb7924f52009-06-23 19:01:18 -07001607#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001608 base_mapped += csize;
1609#endif
1610
1611 return (false);
1612}
1613
1614static bool
1615base_pages_alloc(size_t minsize)
1616{
1617
Jason Evansb7924f52009-06-23 19:01:18 -07001618#ifdef JEMALLOC_DSS
Jason Evansc9658dd2009-06-22 14:44:08 -07001619 if (opt_dss) {
1620 if (base_pages_alloc_dss(minsize) == false)
1621 return (false);
1622 }
1623
Jason Evans289053c2009-06-22 12:08:42 -07001624 if (opt_mmap && minsize != 0)
1625#endif
1626 {
1627 if (base_pages_alloc_mmap(minsize) == false)
1628 return (false);
1629 }
1630
Jason Evans289053c2009-06-22 12:08:42 -07001631 return (true);
1632}
1633
1634static void *
1635base_alloc(size_t size)
1636{
1637 void *ret;
1638 size_t csize;
1639
1640 /* Round size up to nearest multiple of the cacheline size. */
1641 csize = CACHELINE_CEILING(size);
1642
1643 malloc_mutex_lock(&base_mtx);
1644 /* Make sure there's enough space for the allocation. */
1645 if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
1646 if (base_pages_alloc(csize)) {
1647 malloc_mutex_unlock(&base_mtx);
1648 return (NULL);
1649 }
1650 }
1651 /* Allocate. */
1652 ret = base_next_addr;
1653 base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
1654 malloc_mutex_unlock(&base_mtx);
1655
1656 return (ret);
1657}
1658
1659static void *
1660base_calloc(size_t number, size_t size)
1661{
1662 void *ret;
1663
1664 ret = base_alloc(number * size);
1665 memset(ret, 0, number * size);
1666
1667 return (ret);
1668}
1669
1670static extent_node_t *
1671base_node_alloc(void)
1672{
1673 extent_node_t *ret;
1674
1675 malloc_mutex_lock(&base_mtx);
1676 if (base_nodes != NULL) {
1677 ret = base_nodes;
1678 base_nodes = *(extent_node_t **)ret;
1679 malloc_mutex_unlock(&base_mtx);
1680 } else {
1681 malloc_mutex_unlock(&base_mtx);
1682 ret = (extent_node_t *)base_alloc(sizeof(extent_node_t));
1683 }
1684
1685 return (ret);
1686}
1687
1688static void
1689base_node_dealloc(extent_node_t *node)
1690{
1691
1692 malloc_mutex_lock(&base_mtx);
1693 *(extent_node_t **)node = base_nodes;
1694 base_nodes = node;
1695 malloc_mutex_unlock(&base_mtx);
1696}
1697
1698/******************************************************************************/
1699
Jason Evansb7924f52009-06-23 19:01:18 -07001700#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001701static void
1702stats_print(arena_t *arena)
1703{
1704 unsigned i, gap_start;
1705
1706 malloc_printf("dirty: %zu page%s dirty, %llu sweep%s,"
1707 " %llu madvise%s, %llu page%s purged\n",
1708 arena->ndirty, arena->ndirty == 1 ? "" : "s",
1709 arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s",
1710 arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s",
1711 arena->stats.purged, arena->stats.purged == 1 ? "" : "s");
1712
1713 malloc_printf(" allocated nmalloc ndalloc\n");
1714 malloc_printf("small: %12zu %12llu %12llu\n",
1715 arena->stats.allocated_small, arena->stats.nmalloc_small,
1716 arena->stats.ndalloc_small);
1717 malloc_printf("large: %12zu %12llu %12llu\n",
1718 arena->stats.allocated_large, arena->stats.nmalloc_large,
1719 arena->stats.ndalloc_large);
1720 malloc_printf("total: %12zu %12llu %12llu\n",
1721 arena->stats.allocated_small + arena->stats.allocated_large,
1722 arena->stats.nmalloc_small + arena->stats.nmalloc_large,
1723 arena->stats.ndalloc_small + arena->stats.ndalloc_large);
1724 malloc_printf("mapped: %12zu\n", arena->stats.mapped);
1725
Jason Evansb7924f52009-06-23 19:01:18 -07001726#ifdef JEMALLOC_MAG
1727 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07001728 malloc_printf("bins: bin size regs pgs mags "
1729 "newruns reruns maxruns curruns\n");
1730 } else {
1731#endif
1732 malloc_printf("bins: bin size regs pgs requests "
1733 "newruns reruns maxruns curruns\n");
Jason Evansb7924f52009-06-23 19:01:18 -07001734#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001735 }
1736#endif
1737 for (i = 0, gap_start = UINT_MAX; i < nbins; i++) {
1738 if (arena->bins[i].stats.nruns == 0) {
1739 if (gap_start == UINT_MAX)
1740 gap_start = i;
1741 } else {
1742 if (gap_start != UINT_MAX) {
1743 if (i > gap_start + 1) {
1744 /* Gap of more than one size class. */
1745 malloc_printf("[%u..%u]\n",
1746 gap_start, i - 1);
1747 } else {
1748 /* Gap of one size class. */
1749 malloc_printf("[%u]\n", gap_start);
1750 }
1751 gap_start = UINT_MAX;
1752 }
1753 malloc_printf(
1754 "%13u %1s %4u %4u %3u %9llu %9llu"
1755 " %9llu %7lu %7lu\n",
1756 i,
1757 i < ntbins ? "T" : i < ntbins + nqbins ? "Q" :
1758 i < ntbins + nqbins + ncbins ? "C" : "S",
1759 arena->bins[i].reg_size,
1760 arena->bins[i].nregs,
1761 arena->bins[i].run_size >> PAGE_SHIFT,
Jason Evansb7924f52009-06-23 19:01:18 -07001762#ifdef JEMALLOC_MAG
1763 (opt_mag) ? arena->bins[i].stats.nmags :
Jason Evans289053c2009-06-22 12:08:42 -07001764#endif
1765 arena->bins[i].stats.nrequests,
1766 arena->bins[i].stats.nruns,
1767 arena->bins[i].stats.reruns,
1768 arena->bins[i].stats.highruns,
1769 arena->bins[i].stats.curruns);
1770 }
1771 }
1772 if (gap_start != UINT_MAX) {
1773 if (i > gap_start + 1) {
1774 /* Gap of more than one size class. */
1775 malloc_printf("[%u..%u]\n", gap_start, i - 1);
1776 } else {
1777 /* Gap of one size class. */
1778 malloc_printf("[%u]\n", gap_start);
1779 }
1780 }
1781}
1782#endif
1783
1784/*
1785 * End Utility functions/macros.
1786 */
1787/******************************************************************************/
1788/*
1789 * Begin extent tree code.
1790 */
1791
Jason Evansb7924f52009-06-23 19:01:18 -07001792#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001793static inline int
1794extent_szad_comp(extent_node_t *a, extent_node_t *b)
1795{
1796 int ret;
1797 size_t a_size = a->size;
1798 size_t b_size = b->size;
1799
1800 ret = (a_size > b_size) - (a_size < b_size);
1801 if (ret == 0) {
1802 uintptr_t a_addr = (uintptr_t)a->addr;
1803 uintptr_t b_addr = (uintptr_t)b->addr;
1804
1805 ret = (a_addr > b_addr) - (a_addr < b_addr);
1806 }
1807
1808 return (ret);
1809}
1810
1811/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07001812rb_wrap(static, extent_tree_szad_, extent_tree_t, extent_node_t,
Jason Evans289053c2009-06-22 12:08:42 -07001813 link_szad, extent_szad_comp)
1814#endif
1815
1816static inline int
1817extent_ad_comp(extent_node_t *a, extent_node_t *b)
1818{
1819 uintptr_t a_addr = (uintptr_t)a->addr;
1820 uintptr_t b_addr = (uintptr_t)b->addr;
1821
1822 return ((a_addr > b_addr) - (a_addr < b_addr));
1823}
1824
1825/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07001826rb_wrap(static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
Jason Evans289053c2009-06-22 12:08:42 -07001827 extent_ad_comp)
1828
1829/*
1830 * End extent tree code.
1831 */
1832/******************************************************************************/
1833/*
1834 * Begin chunk management functions.
1835 */
1836
1837static void *
1838pages_map(void *addr, size_t size)
1839{
1840 void *ret;
1841
1842 /*
1843 * We don't use MAP_FIXED here, because it can cause the *replacement*
1844 * of existing mappings, and we only want to create new mappings.
1845 */
1846 ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
1847 -1, 0);
1848 assert(ret != NULL);
1849
1850 if (ret == MAP_FAILED)
1851 ret = NULL;
1852 else if (addr != NULL && ret != addr) {
1853 /*
1854 * We succeeded in mapping memory, but not in the right place.
1855 */
1856 if (munmap(ret, size) == -1) {
1857 char buf[STRERROR_BUF];
1858
1859 strerror_r(errno, buf, sizeof(buf));
Jason Evans804c9ec2009-06-22 17:44:33 -07001860 jemalloc_message("<jemalloc>",
1861 ": Error in munmap(): ", buf, "\n");
Jason Evans289053c2009-06-22 12:08:42 -07001862 if (opt_abort)
1863 abort();
1864 }
1865 ret = NULL;
1866 }
1867
1868 assert(ret == NULL || (addr == NULL && ret != addr)
1869 || (addr != NULL && ret == addr));
1870 return (ret);
1871}
1872
1873static void
1874pages_unmap(void *addr, size_t size)
1875{
1876
1877 if (munmap(addr, size) == -1) {
1878 char buf[STRERROR_BUF];
1879
1880 strerror_r(errno, buf, sizeof(buf));
Jason Evans804c9ec2009-06-22 17:44:33 -07001881 jemalloc_message("<jemalloc>",
1882 ": Error in munmap(): ", buf, "\n");
Jason Evans289053c2009-06-22 12:08:42 -07001883 if (opt_abort)
1884 abort();
1885 }
1886}
1887
Jason Evansb7924f52009-06-23 19:01:18 -07001888#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001889static void *
1890chunk_alloc_dss(size_t size)
1891{
1892
1893 /*
1894 * sbrk() uses a signed increment argument, so take care not to
1895 * interpret a huge allocation request as a negative increment.
1896 */
1897 if ((intptr_t)size < 0)
1898 return (NULL);
1899
1900 malloc_mutex_lock(&dss_mtx);
1901 if (dss_prev != (void *)-1) {
1902 intptr_t incr;
1903
1904 /*
1905 * The loop is necessary to recover from races with other
1906 * threads that are using the DSS for something other than
1907 * malloc.
1908 */
1909 do {
1910 void *ret;
1911
1912 /* Get the current end of the DSS. */
1913 dss_max = sbrk(0);
1914
1915 /*
1916 * Calculate how much padding is necessary to
1917 * chunk-align the end of the DSS.
1918 */
1919 incr = (intptr_t)size
1920 - (intptr_t)CHUNK_ADDR2OFFSET(dss_max);
1921 if (incr == (intptr_t)size)
1922 ret = dss_max;
1923 else {
1924 ret = (void *)((intptr_t)dss_max + incr);
1925 incr += size;
1926 }
1927
1928 dss_prev = sbrk(incr);
1929 if (dss_prev == dss_max) {
1930 /* Success. */
1931 dss_max = (void *)((intptr_t)dss_prev + incr);
1932 malloc_mutex_unlock(&dss_mtx);
1933 return (ret);
1934 }
1935 } while (dss_prev != (void *)-1);
1936 }
1937 malloc_mutex_unlock(&dss_mtx);
1938
1939 return (NULL);
1940}
1941
1942static void *
1943chunk_recycle_dss(size_t size, bool zero)
1944{
1945 extent_node_t *node, key;
1946
1947 key.addr = NULL;
1948 key.size = size;
1949 malloc_mutex_lock(&dss_mtx);
1950 node = extent_tree_szad_nsearch(&dss_chunks_szad, &key);
1951 if (node != NULL) {
1952 void *ret = node->addr;
1953
1954 /* Remove node from the tree. */
1955 extent_tree_szad_remove(&dss_chunks_szad, node);
1956 if (node->size == size) {
1957 extent_tree_ad_remove(&dss_chunks_ad, node);
1958 base_node_dealloc(node);
1959 } else {
1960 /*
1961 * Insert the remainder of node's address range as a
1962 * smaller chunk. Its position within dss_chunks_ad
1963 * does not change.
1964 */
1965 assert(node->size > size);
1966 node->addr = (void *)((uintptr_t)node->addr + size);
1967 node->size -= size;
1968 extent_tree_szad_insert(&dss_chunks_szad, node);
1969 }
1970 malloc_mutex_unlock(&dss_mtx);
1971
1972 if (zero)
1973 memset(ret, 0, size);
1974 return (ret);
1975 }
1976 malloc_mutex_unlock(&dss_mtx);
1977
1978 return (NULL);
1979}
1980#endif
1981
1982static void *
1983chunk_alloc_mmap(size_t size)
1984{
1985 void *ret;
1986 size_t offset;
1987
1988 /*
1989 * Ideally, there would be a way to specify alignment to mmap() (like
1990 * NetBSD has), but in the absence of such a feature, we have to work
1991 * hard to efficiently create aligned mappings. The reliable, but
1992 * expensive method is to create a mapping that is over-sized, then
1993 * trim the excess. However, that always results in at least one call
1994 * to pages_unmap().
1995 *
1996 * A more optimistic approach is to try mapping precisely the right
1997 * amount, then try to append another mapping if alignment is off. In
1998 * practice, this works out well as long as the application is not
1999 * interleaving mappings via direct mmap() calls. If we do run into a
2000 * situation where there is an interleaved mapping and we are unable to
2001 * extend an unaligned mapping, our best option is to momentarily
2002 * revert to the reliable-but-expensive method. This will tend to
2003 * leave a gap in the memory map that is too small to cause later
2004 * problems for the optimistic method.
2005 */
2006
2007 ret = pages_map(NULL, size);
2008 if (ret == NULL)
2009 return (NULL);
2010
2011 offset = CHUNK_ADDR2OFFSET(ret);
2012 if (offset != 0) {
2013 /* Try to extend chunk boundary. */
2014 if (pages_map((void *)((uintptr_t)ret + size),
2015 chunksize - offset) == NULL) {
2016 /*
2017 * Extension failed. Clean up, then revert to the
2018 * reliable-but-expensive method.
2019 */
2020 pages_unmap(ret, size);
2021
2022 /* Beware size_t wrap-around. */
2023 if (size + chunksize <= size)
2024 return NULL;
2025
2026 ret = pages_map(NULL, size + chunksize);
2027 if (ret == NULL)
2028 return (NULL);
2029
2030 /* Clean up unneeded leading/trailing space. */
2031 offset = CHUNK_ADDR2OFFSET(ret);
2032 if (offset != 0) {
2033 /* Leading space. */
2034 pages_unmap(ret, chunksize - offset);
2035
2036 ret = (void *)((uintptr_t)ret +
2037 (chunksize - offset));
2038
2039 /* Trailing space. */
2040 pages_unmap((void *)((uintptr_t)ret + size),
2041 offset);
2042 } else {
2043 /* Trailing space only. */
2044 pages_unmap((void *)((uintptr_t)ret + size),
2045 chunksize);
2046 }
2047 } else {
2048 /* Clean up unneeded leading space. */
2049 pages_unmap(ret, chunksize - offset);
2050 ret = (void *)((uintptr_t)ret + (chunksize - offset));
2051 }
2052 }
2053
2054 return (ret);
2055}
2056
2057static void *
2058chunk_alloc(size_t size, bool zero)
2059{
2060 void *ret;
2061
2062 assert(size != 0);
2063 assert((size & chunksize_mask) == 0);
2064
Jason Evansb7924f52009-06-23 19:01:18 -07002065#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002066 if (opt_dss) {
2067 ret = chunk_recycle_dss(size, zero);
2068 if (ret != NULL) {
2069 goto RETURN;
2070 }
2071
2072 ret = chunk_alloc_dss(size);
2073 if (ret != NULL)
2074 goto RETURN;
2075 }
Jason Evansc9658dd2009-06-22 14:44:08 -07002076
2077 if (opt_mmap)
Jason Evans289053c2009-06-22 12:08:42 -07002078#endif
Jason Evansc9658dd2009-06-22 14:44:08 -07002079 {
2080 ret = chunk_alloc_mmap(size);
2081 if (ret != NULL)
2082 goto RETURN;
2083 }
Jason Evans289053c2009-06-22 12:08:42 -07002084
2085 /* All strategies for allocation failed. */
2086 ret = NULL;
2087RETURN:
Jason Evansb7924f52009-06-23 19:01:18 -07002088#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002089 if (ret != NULL) {
2090 stats_chunks.nchunks += (size / chunksize);
2091 stats_chunks.curchunks += (size / chunksize);
2092 }
2093 if (stats_chunks.curchunks > stats_chunks.highchunks)
2094 stats_chunks.highchunks = stats_chunks.curchunks;
2095#endif
2096
2097 assert(CHUNK_ADDR2BASE(ret) == ret);
2098 return (ret);
2099}
2100
Jason Evansb7924f52009-06-23 19:01:18 -07002101#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002102static extent_node_t *
2103chunk_dealloc_dss_record(void *chunk, size_t size)
2104{
2105 extent_node_t *node, *prev, key;
2106
2107 key.addr = (void *)((uintptr_t)chunk + size);
2108 node = extent_tree_ad_nsearch(&dss_chunks_ad, &key);
2109 /* Try to coalesce forward. */
2110 if (node != NULL && node->addr == key.addr) {
2111 /*
2112 * Coalesce chunk with the following address range. This does
2113 * not change the position within dss_chunks_ad, so only
2114 * remove/insert from/into dss_chunks_szad.
2115 */
2116 extent_tree_szad_remove(&dss_chunks_szad, node);
2117 node->addr = chunk;
2118 node->size += size;
2119 extent_tree_szad_insert(&dss_chunks_szad, node);
2120 } else {
2121 /*
2122 * Coalescing forward failed, so insert a new node. Drop
2123 * dss_mtx during node allocation, since it is possible that a
2124 * new base chunk will be allocated.
2125 */
2126 malloc_mutex_unlock(&dss_mtx);
2127 node = base_node_alloc();
2128 malloc_mutex_lock(&dss_mtx);
2129 if (node == NULL)
2130 return (NULL);
2131 node->addr = chunk;
2132 node->size = size;
2133 extent_tree_ad_insert(&dss_chunks_ad, node);
2134 extent_tree_szad_insert(&dss_chunks_szad, node);
2135 }
2136
2137 /* Try to coalesce backward. */
2138 prev = extent_tree_ad_prev(&dss_chunks_ad, node);
2139 if (prev != NULL && (void *)((uintptr_t)prev->addr + prev->size) ==
2140 chunk) {
2141 /*
2142 * Coalesce chunk with the previous address range. This does
2143 * not change the position within dss_chunks_ad, so only
2144 * remove/insert node from/into dss_chunks_szad.
2145 */
2146 extent_tree_szad_remove(&dss_chunks_szad, prev);
2147 extent_tree_ad_remove(&dss_chunks_ad, prev);
2148
2149 extent_tree_szad_remove(&dss_chunks_szad, node);
2150 node->addr = prev->addr;
2151 node->size += prev->size;
2152 extent_tree_szad_insert(&dss_chunks_szad, node);
2153
2154 base_node_dealloc(prev);
2155 }
2156
2157 return (node);
2158}
2159
2160static bool
2161chunk_dealloc_dss(void *chunk, size_t size)
2162{
2163
2164 malloc_mutex_lock(&dss_mtx);
2165 if ((uintptr_t)chunk >= (uintptr_t)dss_base
2166 && (uintptr_t)chunk < (uintptr_t)dss_max) {
2167 extent_node_t *node;
2168
2169 /* Try to coalesce with other unused chunks. */
2170 node = chunk_dealloc_dss_record(chunk, size);
2171 if (node != NULL) {
2172 chunk = node->addr;
2173 size = node->size;
2174 }
2175
2176 /* Get the current end of the DSS. */
2177 dss_max = sbrk(0);
2178
2179 /*
2180 * Try to shrink the DSS if this chunk is at the end of the
2181 * DSS. The sbrk() call here is subject to a race condition
2182 * with threads that use brk(2) or sbrk(2) directly, but the
2183 * alternative would be to leak memory for the sake of poorly
2184 * designed multi-threaded programs.
2185 */
2186 if ((void *)((uintptr_t)chunk + size) == dss_max
2187 && (dss_prev = sbrk(-(intptr_t)size)) == dss_max) {
2188 /* Success. */
2189 dss_max = (void *)((intptr_t)dss_prev - (intptr_t)size);
2190
2191 if (node != NULL) {
2192 extent_tree_szad_remove(&dss_chunks_szad, node);
2193 extent_tree_ad_remove(&dss_chunks_ad, node);
2194 base_node_dealloc(node);
2195 }
2196 malloc_mutex_unlock(&dss_mtx);
2197 } else {
2198 malloc_mutex_unlock(&dss_mtx);
Jason Evansc9658dd2009-06-22 14:44:08 -07002199 madvise(chunk, size, MADV_DONTNEED);
Jason Evans289053c2009-06-22 12:08:42 -07002200 }
2201
2202 return (false);
2203 }
2204 malloc_mutex_unlock(&dss_mtx);
2205
2206 return (true);
2207}
2208#endif
2209
2210static void
2211chunk_dealloc_mmap(void *chunk, size_t size)
2212{
2213
2214 pages_unmap(chunk, size);
2215}
2216
2217static void
2218chunk_dealloc(void *chunk, size_t size)
2219{
2220
2221 assert(chunk != NULL);
2222 assert(CHUNK_ADDR2BASE(chunk) == chunk);
2223 assert(size != 0);
2224 assert((size & chunksize_mask) == 0);
2225
Jason Evansb7924f52009-06-23 19:01:18 -07002226#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002227 stats_chunks.curchunks -= (size / chunksize);
2228#endif
2229
Jason Evansb7924f52009-06-23 19:01:18 -07002230#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002231 if (opt_dss) {
2232 if (chunk_dealloc_dss(chunk, size) == false)
2233 return;
2234 }
2235
2236 if (opt_mmap)
2237#endif
2238 chunk_dealloc_mmap(chunk, size);
2239}
2240
2241/*
2242 * End chunk management functions.
2243 */
2244/******************************************************************************/
2245/*
2246 * Begin arena.
2247 */
2248
2249/*
2250 * Choose an arena based on a per-thread value (fast-path code, calls slow-path
2251 * code if necessary).
2252 */
2253static inline arena_t *
2254choose_arena(void)
2255{
2256 arena_t *ret;
2257
2258 /*
2259 * We can only use TLS if this is a PIC library, since for the static
2260 * library version, libc's malloc is used by TLS allocation, which
2261 * introduces a bootstrapping issue.
2262 */
2263#ifndef NO_TLS
Jason Evans289053c2009-06-22 12:08:42 -07002264 ret = arenas_map;
2265 if (ret == NULL) {
2266 ret = choose_arena_hard();
2267 assert(ret != NULL);
2268 }
2269#else
Jason Evansb7924f52009-06-23 19:01:18 -07002270 if (isthreaded && narenas > 1) {
Jason Evans289053c2009-06-22 12:08:42 -07002271 unsigned long ind;
2272
2273 /*
Jason Evansc9658dd2009-06-22 14:44:08 -07002274 * Hash pthread_self() to one of the arenas. There is a prime
Jason Evans289053c2009-06-22 12:08:42 -07002275 * number of arenas, so this has a reasonable chance of
2276 * working. Even so, the hashing can be easily thwarted by
Jason Evansc9658dd2009-06-22 14:44:08 -07002277 * inconvenient pthread_self() values. Without specific
2278 * knowledge of how pthread_self() calculates values, we can't
Jason Evans289053c2009-06-22 12:08:42 -07002279 * easily do much better than this.
2280 */
Jason Evansc9658dd2009-06-22 14:44:08 -07002281 ind = (unsigned long) pthread_self() % narenas;
Jason Evans289053c2009-06-22 12:08:42 -07002282
2283 /*
2284 * Optimistially assume that arenas[ind] has been initialized.
2285 * At worst, we find out that some other thread has already
2286 * done so, after acquiring the lock in preparation. Note that
2287 * this lazy locking also has the effect of lazily forcing
2288 * cache coherency; without the lock acquisition, there's no
2289 * guarantee that modification of arenas[ind] by another thread
2290 * would be seen on this CPU for an arbitrary amount of time.
2291 *
2292 * In general, this approach to modifying a synchronized value
2293 * isn't a good idea, but in this case we only ever modify the
2294 * value once, so things work out well.
2295 */
2296 ret = arenas[ind];
2297 if (ret == NULL) {
2298 /*
2299 * Avoid races with another thread that may have already
2300 * initialized arenas[ind].
2301 */
2302 malloc_spin_lock(&arenas_lock);
2303 if (arenas[ind] == NULL)
2304 ret = arenas_extend((unsigned)ind);
2305 else
2306 ret = arenas[ind];
2307 malloc_spin_unlock(&arenas_lock);
2308 }
2309 } else
2310 ret = arenas[0];
2311#endif
2312
2313 assert(ret != NULL);
2314 return (ret);
2315}
2316
2317#ifndef NO_TLS
2318/*
2319 * Choose an arena based on a per-thread value (slow-path code only, called
2320 * only by choose_arena()).
2321 */
2322static arena_t *
2323choose_arena_hard(void)
2324{
2325 arena_t *ret;
2326
Jason Evansb7924f52009-06-23 19:01:18 -07002327 assert(isthreaded);
Jason Evans289053c2009-06-22 12:08:42 -07002328
Jason Evansb7924f52009-06-23 19:01:18 -07002329#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07002330 /* Seed the PRNG used for arena load balancing. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002331 SPRN(balance, (uint32_t)(uintptr_t)(pthread_self()));
Jason Evans289053c2009-06-22 12:08:42 -07002332#endif
2333
2334 if (narenas > 1) {
Jason Evansb7924f52009-06-23 19:01:18 -07002335#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07002336 unsigned ind;
2337
2338 ind = PRN(balance, narenas_2pow);
2339 if ((ret = arenas[ind]) == NULL) {
2340 malloc_spin_lock(&arenas_lock);
2341 if ((ret = arenas[ind]) == NULL)
2342 ret = arenas_extend(ind);
2343 malloc_spin_unlock(&arenas_lock);
2344 }
2345#else
2346 malloc_spin_lock(&arenas_lock);
2347 if ((ret = arenas[next_arena]) == NULL)
2348 ret = arenas_extend(next_arena);
2349 next_arena = (next_arena + 1) % narenas;
2350 malloc_spin_unlock(&arenas_lock);
2351#endif
2352 } else
2353 ret = arenas[0];
2354
2355 arenas_map = ret;
2356
2357 return (ret);
2358}
2359#endif
2360
2361static inline int
2362arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
2363{
2364 uintptr_t a_chunk = (uintptr_t)a;
2365 uintptr_t b_chunk = (uintptr_t)b;
2366
2367 assert(a != NULL);
2368 assert(b != NULL);
2369
2370 return ((a_chunk > b_chunk) - (a_chunk < b_chunk));
2371}
2372
2373/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002374rb_wrap(static, arena_chunk_tree_dirty_, arena_chunk_tree_t,
Jason Evans289053c2009-06-22 12:08:42 -07002375 arena_chunk_t, link_dirty, arena_chunk_comp)
2376
2377static inline int
2378arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
2379{
2380 uintptr_t a_mapelm = (uintptr_t)a;
2381 uintptr_t b_mapelm = (uintptr_t)b;
2382
2383 assert(a != NULL);
2384 assert(b != NULL);
2385
2386 return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm));
2387}
2388
2389/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002390rb_wrap(static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
Jason Evans289053c2009-06-22 12:08:42 -07002391 link, arena_run_comp)
2392
2393static inline int
2394arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
2395{
2396 int ret;
2397 size_t a_size = a->bits & ~PAGE_MASK;
2398 size_t b_size = b->bits & ~PAGE_MASK;
2399
2400 ret = (a_size > b_size) - (a_size < b_size);
2401 if (ret == 0) {
2402 uintptr_t a_mapelm, b_mapelm;
2403
2404 if ((a->bits & CHUNK_MAP_KEY) == 0)
2405 a_mapelm = (uintptr_t)a;
2406 else {
2407 /*
2408 * Treat keys as though they are lower than anything
2409 * else.
2410 */
2411 a_mapelm = 0;
2412 }
2413 b_mapelm = (uintptr_t)b;
2414
2415 ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
2416 }
2417
2418 return (ret);
2419}
2420
2421/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002422rb_wrap(static, arena_avail_tree_, arena_avail_tree_t,
Jason Evans289053c2009-06-22 12:08:42 -07002423 arena_chunk_map_t, link, arena_avail_comp)
2424
2425static inline void *
2426arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
2427{
2428 void *ret;
2429 unsigned i, mask, bit, regind;
2430
2431 assert(run->magic == ARENA_RUN_MAGIC);
2432 assert(run->regs_minelm < bin->regs_mask_nelms);
2433
2434 /*
2435 * Move the first check outside the loop, so that run->regs_minelm can
2436 * be updated unconditionally, without the possibility of updating it
2437 * multiple times.
2438 */
2439 i = run->regs_minelm;
2440 mask = run->regs_mask[i];
2441 if (mask != 0) {
2442 /* Usable allocation found. */
2443 bit = ffs((int)mask) - 1;
2444
2445 regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
2446 assert(regind < bin->nregs);
2447 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
2448 + (bin->reg_size * regind));
2449
2450 /* Clear bit. */
2451 mask ^= (1U << bit);
2452 run->regs_mask[i] = mask;
2453
2454 return (ret);
2455 }
2456
2457 for (i++; i < bin->regs_mask_nelms; i++) {
2458 mask = run->regs_mask[i];
2459 if (mask != 0) {
2460 /* Usable allocation found. */
2461 bit = ffs((int)mask) - 1;
2462
2463 regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
2464 assert(regind < bin->nregs);
2465 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
2466 + (bin->reg_size * regind));
2467
2468 /* Clear bit. */
2469 mask ^= (1U << bit);
2470 run->regs_mask[i] = mask;
2471
2472 /*
2473 * Make a note that nothing before this element
2474 * contains a free region.
2475 */
2476 run->regs_minelm = i; /* Low payoff: + (mask == 0); */
2477
2478 return (ret);
2479 }
2480 }
2481 /* Not reached. */
2482 assert(0);
2483 return (NULL);
2484}
2485
2486static inline void
2487arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
2488{
2489 unsigned diff, regind, elm, bit;
2490
2491 assert(run->magic == ARENA_RUN_MAGIC);
2492
2493 /*
2494 * Avoid doing division with a variable divisor if possible. Using
2495 * actual division here can reduce allocator throughput by over 20%!
2496 */
2497 diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
2498 if ((size & (size - 1)) == 0) {
2499 /*
2500 * log2_table allows fast division of a power of two in the
2501 * [1..128] range.
2502 *
2503 * (x / divisor) becomes (x >> log2_table[divisor - 1]).
2504 */
2505 static const unsigned char log2_table[] = {
2506 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
2507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
2508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
2510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
2514 };
2515
2516 if (size <= 128)
2517 regind = (diff >> log2_table[size - 1]);
2518 else if (size <= 32768)
2519 regind = diff >> (8 + log2_table[(size >> 8) - 1]);
2520 else
2521 regind = diff / size;
2522 } else if (size < qspace_max) {
2523 /*
2524 * To divide by a number D that is not a power of two we
2525 * multiply by (2^21 / D) and then right shift by 21 positions.
2526 *
2527 * X / D
2528 *
2529 * becomes
2530 *
2531 * (X * qsize_invs[(D >> QUANTUM_2POW) - 3])
2532 * >> SIZE_INV_SHIFT
2533 *
2534 * We can omit the first three elements, because we never
2535 * divide by 0, and QUANTUM and 2*QUANTUM are both powers of
2536 * two, which are handled above.
2537 */
2538#define SIZE_INV_SHIFT 21
2539#define QSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << QUANTUM_2POW)) + 1)
2540 static const unsigned qsize_invs[] = {
2541 QSIZE_INV(3),
2542 QSIZE_INV(4), QSIZE_INV(5), QSIZE_INV(6), QSIZE_INV(7)
2543#if (QUANTUM_2POW < 4)
2544 ,
2545 QSIZE_INV(8), QSIZE_INV(9), QSIZE_INV(10), QSIZE_INV(11),
2546 QSIZE_INV(12),QSIZE_INV(13), QSIZE_INV(14), QSIZE_INV(15)
2547#endif
2548 };
2549 assert(QUANTUM * (((sizeof(qsize_invs)) / sizeof(unsigned)) + 3)
2550 >= (1U << QSPACE_MAX_2POW_DEFAULT));
2551
2552 if (size <= (((sizeof(qsize_invs) / sizeof(unsigned)) + 2) <<
2553 QUANTUM_2POW)) {
2554 regind = qsize_invs[(size >> QUANTUM_2POW) - 3] * diff;
2555 regind >>= SIZE_INV_SHIFT;
2556 } else
2557 regind = diff / size;
2558#undef QSIZE_INV
2559 } else if (size < cspace_max) {
2560#define CSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << CACHELINE_2POW)) + 1)
2561 static const unsigned csize_invs[] = {
2562 CSIZE_INV(3),
2563 CSIZE_INV(4), CSIZE_INV(5), CSIZE_INV(6), CSIZE_INV(7)
2564 };
2565 assert(CACHELINE * (((sizeof(csize_invs)) / sizeof(unsigned)) +
2566 3) >= (1U << CSPACE_MAX_2POW_DEFAULT));
2567
2568 if (size <= (((sizeof(csize_invs) / sizeof(unsigned)) + 2) <<
2569 CACHELINE_2POW)) {
2570 regind = csize_invs[(size >> CACHELINE_2POW) - 3] *
2571 diff;
2572 regind >>= SIZE_INV_SHIFT;
2573 } else
2574 regind = diff / size;
2575#undef CSIZE_INV
2576 } else {
2577#define SSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << SUBPAGE_2POW)) + 1)
2578 static const unsigned ssize_invs[] = {
2579 SSIZE_INV(3),
2580 SSIZE_INV(4), SSIZE_INV(5), SSIZE_INV(6), SSIZE_INV(7),
2581 SSIZE_INV(8), SSIZE_INV(9), SSIZE_INV(10), SSIZE_INV(11),
2582 SSIZE_INV(12), SSIZE_INV(13), SSIZE_INV(14), SSIZE_INV(15)
Jason Evansb7924f52009-06-23 19:01:18 -07002583#if (STATIC_PAGE_SHIFT == 13)
Jason Evans289053c2009-06-22 12:08:42 -07002584 ,
2585 SSIZE_INV(16), SSIZE_INV(17), SSIZE_INV(18), SSIZE_INV(19),
2586 SSIZE_INV(20), SSIZE_INV(21), SSIZE_INV(22), SSIZE_INV(23),
2587 SSIZE_INV(24), SSIZE_INV(25), SSIZE_INV(26), SSIZE_INV(27),
2588 SSIZE_INV(28), SSIZE_INV(29), SSIZE_INV(29), SSIZE_INV(30)
2589#endif
2590 };
2591 assert(SUBPAGE * (((sizeof(ssize_invs)) / sizeof(unsigned)) + 3)
2592 >= PAGE_SIZE);
2593
2594 if (size < (((sizeof(ssize_invs) / sizeof(unsigned)) + 2) <<
2595 SUBPAGE_2POW)) {
2596 regind = ssize_invs[(size >> SUBPAGE_2POW) - 3] * diff;
2597 regind >>= SIZE_INV_SHIFT;
2598 } else
2599 regind = diff / size;
2600#undef SSIZE_INV
2601 }
2602#undef SIZE_INV_SHIFT
2603 assert(diff == regind * size);
2604 assert(regind < bin->nregs);
2605
2606 elm = regind >> (SIZEOF_INT_2POW + 3);
2607 if (elm < run->regs_minelm)
2608 run->regs_minelm = elm;
2609 bit = regind - (elm << (SIZEOF_INT_2POW + 3));
2610 assert((run->regs_mask[elm] & (1U << bit)) == 0);
2611 run->regs_mask[elm] |= (1U << bit);
2612}
2613
2614static void
2615arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large,
2616 bool zero)
2617{
2618 arena_chunk_t *chunk;
2619 size_t old_ndirty, run_ind, total_pages, need_pages, rem_pages, i;
2620
2621 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
2622 old_ndirty = chunk->ndirty;
2623 run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
2624 >> PAGE_SHIFT);
2625 total_pages = (chunk->map[run_ind].bits & ~PAGE_MASK) >>
2626 PAGE_SHIFT;
2627 need_pages = (size >> PAGE_SHIFT);
2628 assert(need_pages > 0);
2629 assert(need_pages <= total_pages);
2630 rem_pages = total_pages - need_pages;
2631
2632 arena_avail_tree_remove(&arena->runs_avail, &chunk->map[run_ind]);
2633
2634 /* Keep track of trailing unused pages for later use. */
2635 if (rem_pages > 0) {
2636 chunk->map[run_ind+need_pages].bits = (rem_pages <<
2637 PAGE_SHIFT) | (chunk->map[run_ind+need_pages].bits &
2638 PAGE_MASK);
2639 chunk->map[run_ind+total_pages-1].bits = (rem_pages <<
2640 PAGE_SHIFT) | (chunk->map[run_ind+total_pages-1].bits &
2641 PAGE_MASK);
2642 arena_avail_tree_insert(&arena->runs_avail,
2643 &chunk->map[run_ind+need_pages]);
2644 }
2645
2646 for (i = 0; i < need_pages; i++) {
2647 /* Zero if necessary. */
2648 if (zero) {
2649 if ((chunk->map[run_ind + i].bits & CHUNK_MAP_ZEROED)
2650 == 0) {
2651 memset((void *)((uintptr_t)chunk + ((run_ind
2652 + i) << PAGE_SHIFT)), 0, PAGE_SIZE);
2653 /* CHUNK_MAP_ZEROED is cleared below. */
2654 }
2655 }
2656
2657 /* Update dirty page accounting. */
2658 if (chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) {
2659 chunk->ndirty--;
2660 arena->ndirty--;
2661 /* CHUNK_MAP_DIRTY is cleared below. */
2662 }
2663
2664 /* Initialize the chunk map. */
2665 if (large) {
2666 chunk->map[run_ind + i].bits = CHUNK_MAP_LARGE
2667 | CHUNK_MAP_ALLOCATED;
2668 } else {
2669 chunk->map[run_ind + i].bits = (size_t)run
2670 | CHUNK_MAP_ALLOCATED;
2671 }
2672 }
2673
2674 /*
2675 * Set the run size only in the first element for large runs. This is
2676 * primarily a debugging aid, since the lack of size info for trailing
2677 * pages only matters if the application tries to operate on an
2678 * interior pointer.
2679 */
2680 if (large)
2681 chunk->map[run_ind].bits |= size;
2682
2683 if (chunk->ndirty == 0 && old_ndirty > 0)
2684 arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk);
2685}
2686
2687static arena_chunk_t *
2688arena_chunk_alloc(arena_t *arena)
2689{
2690 arena_chunk_t *chunk;
2691 size_t i;
2692
2693 if (arena->spare != NULL) {
2694 chunk = arena->spare;
2695 arena->spare = NULL;
2696 } else {
2697 chunk = (arena_chunk_t *)chunk_alloc(chunksize, true);
2698 if (chunk == NULL)
2699 return (NULL);
Jason Evansb7924f52009-06-23 19:01:18 -07002700#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002701 arena->stats.mapped += chunksize;
2702#endif
2703
2704 chunk->arena = arena;
2705
2706 /*
2707 * Claim that no pages are in use, since the header is merely
2708 * overhead.
2709 */
2710 chunk->ndirty = 0;
2711
2712 /*
2713 * Initialize the map to contain one maximal free untouched run.
2714 */
2715 for (i = 0; i < arena_chunk_header_npages; i++)
2716 chunk->map[i].bits = 0;
2717 chunk->map[i].bits = arena_maxclass | CHUNK_MAP_ZEROED;
2718 for (i++; i < chunk_npages-1; i++) {
2719 chunk->map[i].bits = CHUNK_MAP_ZEROED;
2720 }
2721 chunk->map[chunk_npages-1].bits = arena_maxclass |
2722 CHUNK_MAP_ZEROED;
2723 }
2724
2725 /* Insert the run into the runs_avail tree. */
2726 arena_avail_tree_insert(&arena->runs_avail,
2727 &chunk->map[arena_chunk_header_npages]);
2728
2729 return (chunk);
2730}
2731
2732static void
2733arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
2734{
2735
2736 if (arena->spare != NULL) {
2737 if (arena->spare->ndirty > 0) {
2738 arena_chunk_tree_dirty_remove(
2739 &chunk->arena->chunks_dirty, arena->spare);
2740 arena->ndirty -= arena->spare->ndirty;
2741 }
2742 chunk_dealloc((void *)arena->spare, chunksize);
Jason Evansb7924f52009-06-23 19:01:18 -07002743#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002744 arena->stats.mapped -= chunksize;
2745#endif
2746 }
2747
2748 /*
2749 * Remove run from runs_avail, regardless of whether this chunk
2750 * will be cached, so that the arena does not use it. Dirty page
2751 * flushing only uses the chunks_dirty tree, so leaving this chunk in
2752 * the chunks_* trees is sufficient for that purpose.
2753 */
2754 arena_avail_tree_remove(&arena->runs_avail,
2755 &chunk->map[arena_chunk_header_npages]);
2756
2757 arena->spare = chunk;
2758}
2759
2760static arena_run_t *
2761arena_run_alloc(arena_t *arena, size_t size, bool large, bool zero)
2762{
2763 arena_chunk_t *chunk;
2764 arena_run_t *run;
2765 arena_chunk_map_t *mapelm, key;
2766
2767 assert(size <= arena_maxclass);
2768 assert((size & PAGE_MASK) == 0);
2769
2770 /* Search the arena's chunks for the lowest best fit. */
2771 key.bits = size | CHUNK_MAP_KEY;
2772 mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
2773 if (mapelm != NULL) {
2774 arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
2775 size_t pageind = ((uintptr_t)mapelm - (uintptr_t)run_chunk->map)
2776 / sizeof(arena_chunk_map_t);
2777
2778 run = (arena_run_t *)((uintptr_t)run_chunk + (pageind
2779 << PAGE_SHIFT));
2780 arena_run_split(arena, run, size, large, zero);
2781 return (run);
2782 }
2783
2784 /*
2785 * No usable runs. Create a new chunk from which to allocate the run.
2786 */
2787 chunk = arena_chunk_alloc(arena);
2788 if (chunk == NULL)
2789 return (NULL);
2790 run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages <<
2791 PAGE_SHIFT));
2792 /* Update page map. */
2793 arena_run_split(arena, run, size, large, zero);
2794 return (run);
2795}
2796
2797static void
2798arena_purge(arena_t *arena)
2799{
2800 arena_chunk_t *chunk;
2801 size_t i, npages;
Jason Evansb7924f52009-06-23 19:01:18 -07002802#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07002803 size_t ndirty = 0;
2804
2805 rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty,
2806 chunk) {
2807 ndirty += chunk->ndirty;
2808 } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk)
2809 assert(ndirty == arena->ndirty);
2810#endif
2811 assert(arena->ndirty > opt_dirty_max);
2812
Jason Evansb7924f52009-06-23 19:01:18 -07002813#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002814 arena->stats.npurge++;
2815#endif
2816
2817 /*
2818 * Iterate downward through chunks until enough dirty memory has been
2819 * purged. Terminate as soon as possible in order to minimize the
2820 * number of system calls, even if a chunk has only been partially
2821 * purged.
2822 */
2823 while (arena->ndirty > (opt_dirty_max >> 1)) {
2824 chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty);
2825 assert(chunk != NULL);
2826
2827 for (i = chunk_npages - 1; chunk->ndirty > 0; i--) {
2828 assert(i >= arena_chunk_header_npages);
2829
2830 if (chunk->map[i].bits & CHUNK_MAP_DIRTY) {
2831 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
2832 /* Find adjacent dirty run(s). */
2833 for (npages = 1; i > arena_chunk_header_npages
2834 && (chunk->map[i - 1].bits &
2835 CHUNK_MAP_DIRTY); npages++) {
2836 i--;
2837 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
2838 }
2839 chunk->ndirty -= npages;
2840 arena->ndirty -= npages;
2841
2842 madvise((void *)((uintptr_t)chunk + (i <<
2843 PAGE_SHIFT)), (npages << PAGE_SHIFT),
Jason Evansc9658dd2009-06-22 14:44:08 -07002844 MADV_DONTNEED);
Jason Evansb7924f52009-06-23 19:01:18 -07002845#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002846 arena->stats.nmadvise++;
2847 arena->stats.purged += npages;
2848#endif
2849 if (arena->ndirty <= (opt_dirty_max >> 1))
2850 break;
2851 }
2852 }
2853
2854 if (chunk->ndirty == 0) {
2855 arena_chunk_tree_dirty_remove(&arena->chunks_dirty,
2856 chunk);
2857 }
2858 }
2859}
2860
2861static void
2862arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty)
2863{
2864 arena_chunk_t *chunk;
2865 size_t size, run_ind, run_pages;
2866
2867 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
2868 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk)
2869 >> PAGE_SHIFT);
2870 assert(run_ind >= arena_chunk_header_npages);
2871 assert(run_ind < chunk_npages);
2872 if ((chunk->map[run_ind].bits & CHUNK_MAP_LARGE) != 0)
2873 size = chunk->map[run_ind].bits & ~PAGE_MASK;
2874 else
2875 size = run->bin->run_size;
2876 run_pages = (size >> PAGE_SHIFT);
2877
2878 /* Mark pages as unallocated in the chunk map. */
2879 if (dirty) {
2880 size_t i;
2881
2882 for (i = 0; i < run_pages; i++) {
2883 assert((chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY)
2884 == 0);
2885 chunk->map[run_ind + i].bits = CHUNK_MAP_DIRTY;
2886 }
2887
2888 if (chunk->ndirty == 0) {
2889 arena_chunk_tree_dirty_insert(&arena->chunks_dirty,
2890 chunk);
2891 }
2892 chunk->ndirty += run_pages;
2893 arena->ndirty += run_pages;
2894 } else {
2895 size_t i;
2896
2897 for (i = 0; i < run_pages; i++) {
2898 chunk->map[run_ind + i].bits &= ~(CHUNK_MAP_LARGE |
2899 CHUNK_MAP_ALLOCATED);
2900 }
2901 }
2902 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2903 PAGE_MASK);
2904 chunk->map[run_ind+run_pages-1].bits = size |
2905 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2906
2907 /* Try to coalesce forward. */
2908 if (run_ind + run_pages < chunk_npages &&
2909 (chunk->map[run_ind+run_pages].bits & CHUNK_MAP_ALLOCATED) == 0) {
2910 size_t nrun_size = chunk->map[run_ind+run_pages].bits &
2911 ~PAGE_MASK;
2912
2913 /*
2914 * Remove successor from runs_avail; the coalesced run is
2915 * inserted later.
2916 */
2917 arena_avail_tree_remove(&arena->runs_avail,
2918 &chunk->map[run_ind+run_pages]);
2919
2920 size += nrun_size;
2921 run_pages = size >> PAGE_SHIFT;
2922
2923 assert((chunk->map[run_ind+run_pages-1].bits & ~PAGE_MASK)
2924 == nrun_size);
2925 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2926 PAGE_MASK);
2927 chunk->map[run_ind+run_pages-1].bits = size |
2928 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2929 }
2930
2931 /* Try to coalesce backward. */
2932 if (run_ind > arena_chunk_header_npages && (chunk->map[run_ind-1].bits &
2933 CHUNK_MAP_ALLOCATED) == 0) {
2934 size_t prun_size = chunk->map[run_ind-1].bits & ~PAGE_MASK;
2935
2936 run_ind -= prun_size >> PAGE_SHIFT;
2937
2938 /*
2939 * Remove predecessor from runs_avail; the coalesced run is
2940 * inserted later.
2941 */
2942 arena_avail_tree_remove(&arena->runs_avail,
2943 &chunk->map[run_ind]);
2944
2945 size += prun_size;
2946 run_pages = size >> PAGE_SHIFT;
2947
2948 assert((chunk->map[run_ind].bits & ~PAGE_MASK) ==
2949 prun_size);
2950 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2951 PAGE_MASK);
2952 chunk->map[run_ind+run_pages-1].bits = size |
2953 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2954 }
2955
2956 /* Insert into runs_avail, now that coalescing is complete. */
2957 arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind]);
2958
2959 /* Deallocate chunk if it is now completely unused. */
2960 if ((chunk->map[arena_chunk_header_npages].bits & (~PAGE_MASK |
2961 CHUNK_MAP_ALLOCATED)) == arena_maxclass)
2962 arena_chunk_dealloc(arena, chunk);
2963
2964 /* Enforce opt_dirty_max. */
2965 if (arena->ndirty > opt_dirty_max)
2966 arena_purge(arena);
2967}
2968
2969static void
2970arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
2971 size_t oldsize, size_t newsize)
2972{
2973 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
2974 size_t head_npages = (oldsize - newsize) >> PAGE_SHIFT;
2975
2976 assert(oldsize > newsize);
2977
2978 /*
2979 * Update the chunk map so that arena_run_dalloc() can treat the
2980 * leading run as separately allocated.
2981 */
2982 chunk->map[pageind].bits = (oldsize - newsize) | CHUNK_MAP_LARGE |
2983 CHUNK_MAP_ALLOCATED;
2984 chunk->map[pageind+head_npages].bits = newsize | CHUNK_MAP_LARGE |
2985 CHUNK_MAP_ALLOCATED;
2986
2987 arena_run_dalloc(arena, run, false);
2988}
2989
2990static void
2991arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
2992 size_t oldsize, size_t newsize, bool dirty)
2993{
2994 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
2995 size_t npages = newsize >> PAGE_SHIFT;
2996
2997 assert(oldsize > newsize);
2998
2999 /*
3000 * Update the chunk map so that arena_run_dalloc() can treat the
3001 * trailing run as separately allocated.
3002 */
3003 chunk->map[pageind].bits = newsize | CHUNK_MAP_LARGE |
3004 CHUNK_MAP_ALLOCATED;
3005 chunk->map[pageind+npages].bits = (oldsize - newsize) | CHUNK_MAP_LARGE
3006 | CHUNK_MAP_ALLOCATED;
3007
3008 arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize),
3009 dirty);
3010}
3011
3012static arena_run_t *
3013arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
3014{
3015 arena_chunk_map_t *mapelm;
3016 arena_run_t *run;
3017 unsigned i, remainder;
3018
3019 /* Look for a usable run. */
3020 mapelm = arena_run_tree_first(&bin->runs);
3021 if (mapelm != NULL) {
3022 /* run is guaranteed to have available space. */
3023 arena_run_tree_remove(&bin->runs, mapelm);
3024 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
Jason Evansb7924f52009-06-23 19:01:18 -07003025#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003026 bin->stats.reruns++;
3027#endif
3028 return (run);
3029 }
3030 /* No existing runs have any space available. */
3031
3032 /* Allocate a new run. */
3033 run = arena_run_alloc(arena, bin->run_size, false, false);
3034 if (run == NULL)
3035 return (NULL);
3036
3037 /* Initialize run internals. */
3038 run->bin = bin;
3039
3040 for (i = 0; i < bin->regs_mask_nelms - 1; i++)
3041 run->regs_mask[i] = UINT_MAX;
3042 remainder = bin->nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1);
3043 if (remainder == 0)
3044 run->regs_mask[i] = UINT_MAX;
3045 else {
3046 /* The last element has spare bits that need to be unset. */
3047 run->regs_mask[i] = (UINT_MAX >> ((1U << (SIZEOF_INT_2POW + 3))
3048 - remainder));
3049 }
3050
3051 run->regs_minelm = 0;
3052
3053 run->nfree = bin->nregs;
Jason Evansb7924f52009-06-23 19:01:18 -07003054#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07003055 run->magic = ARENA_RUN_MAGIC;
3056#endif
3057
Jason Evansb7924f52009-06-23 19:01:18 -07003058#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003059 bin->stats.nruns++;
3060 bin->stats.curruns++;
3061 if (bin->stats.curruns > bin->stats.highruns)
3062 bin->stats.highruns = bin->stats.curruns;
3063#endif
3064 return (run);
3065}
3066
3067/* bin->runcur must have space available before this function is called. */
3068static inline void *
3069arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run)
3070{
3071 void *ret;
3072
3073 assert(run->magic == ARENA_RUN_MAGIC);
3074 assert(run->nfree > 0);
3075
3076 ret = arena_run_reg_alloc(run, bin);
3077 assert(ret != NULL);
3078 run->nfree--;
3079
3080 return (ret);
3081}
3082
3083/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
3084static void *
3085arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
3086{
3087
3088 bin->runcur = arena_bin_nonfull_run_get(arena, bin);
3089 if (bin->runcur == NULL)
3090 return (NULL);
3091 assert(bin->runcur->magic == ARENA_RUN_MAGIC);
3092 assert(bin->runcur->nfree > 0);
3093
3094 return (arena_bin_malloc_easy(arena, bin, bin->runcur));
3095}
3096
3097/*
3098 * Calculate bin->run_size such that it meets the following constraints:
3099 *
3100 * *) bin->run_size >= min_run_size
3101 * *) bin->run_size <= arena_maxclass
3102 * *) bin->run_size <= RUN_MAX_SMALL
3103 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
3104 *
3105 * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
3106 * also calculated here, since these settings are all interdependent.
3107 */
3108static size_t
3109arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size)
3110{
3111 size_t try_run_size, good_run_size;
3112 unsigned good_nregs, good_mask_nelms, good_reg0_offset;
3113 unsigned try_nregs, try_mask_nelms, try_reg0_offset;
3114
3115 assert(min_run_size >= PAGE_SIZE);
3116 assert(min_run_size <= arena_maxclass);
3117 assert(min_run_size <= RUN_MAX_SMALL);
3118
3119 /*
3120 * Calculate known-valid settings before entering the run_size
3121 * expansion loop, so that the first part of the loop always copies
3122 * valid settings.
3123 *
3124 * The do..while loop iteratively reduces the number of regions until
3125 * the run header and the regions no longer overlap. A closed formula
3126 * would be quite messy, since there is an interdependency between the
3127 * header's mask length and the number of regions.
3128 */
3129 try_run_size = min_run_size;
3130 try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size)
3131 + 1; /* Counter-act try_nregs-- in loop. */
3132 do {
3133 try_nregs--;
3134 try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
3135 ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0);
3136 try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
3137 } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))
3138 > try_reg0_offset);
3139
3140 /* run_size expansion loop. */
3141 do {
3142 /*
3143 * Copy valid settings before trying more aggressive settings.
3144 */
3145 good_run_size = try_run_size;
3146 good_nregs = try_nregs;
3147 good_mask_nelms = try_mask_nelms;
3148 good_reg0_offset = try_reg0_offset;
3149
3150 /* Try more aggressive settings. */
3151 try_run_size += PAGE_SIZE;
3152 try_nregs = ((try_run_size - sizeof(arena_run_t)) /
3153 bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */
3154 do {
3155 try_nregs--;
3156 try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
3157 ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ?
3158 1 : 0);
3159 try_reg0_offset = try_run_size - (try_nregs *
3160 bin->reg_size);
3161 } while (sizeof(arena_run_t) + (sizeof(unsigned) *
3162 (try_mask_nelms - 1)) > try_reg0_offset);
3163 } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL
3164 && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX
3165 && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size);
3166
3167 assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1))
3168 <= good_reg0_offset);
3169 assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs);
3170
3171 /* Copy final settings. */
3172 bin->run_size = good_run_size;
3173 bin->nregs = good_nregs;
3174 bin->regs_mask_nelms = good_mask_nelms;
3175 bin->reg0_offset = good_reg0_offset;
3176
3177 return (good_run_size);
3178}
3179
Jason Evansb7924f52009-06-23 19:01:18 -07003180#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003181static inline void
3182arena_lock_balance(arena_t *arena)
3183{
3184 unsigned contention;
3185
3186 contention = malloc_spin_lock(&arena->lock);
3187 if (narenas > 1) {
3188 /*
3189 * Calculate the exponentially averaged contention for this
3190 * arena. Due to integer math always rounding down, this value
3191 * decays somewhat faster than normal.
3192 */
3193 arena->contention = (((uint64_t)arena->contention
3194 * (uint64_t)((1U << BALANCE_ALPHA_INV_2POW)-1))
3195 + (uint64_t)contention) >> BALANCE_ALPHA_INV_2POW;
3196 if (arena->contention >= opt_balance_threshold)
3197 arena_lock_balance_hard(arena);
3198 }
3199}
3200
3201static void
3202arena_lock_balance_hard(arena_t *arena)
3203{
3204 uint32_t ind;
3205
3206 arena->contention = 0;
Jason Evansb7924f52009-06-23 19:01:18 -07003207#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003208 arena->stats.nbalance++;
3209#endif
3210 ind = PRN(balance, narenas_2pow);
3211 if (arenas[ind] != NULL)
3212 arenas_map = arenas[ind];
3213 else {
3214 malloc_spin_lock(&arenas_lock);
3215 if (arenas[ind] != NULL)
3216 arenas_map = arenas[ind];
3217 else
3218 arenas_map = arenas_extend(ind);
3219 malloc_spin_unlock(&arenas_lock);
3220 }
3221}
3222#endif
3223
Jason Evansb7924f52009-06-23 19:01:18 -07003224#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003225static inline void *
3226mag_alloc(mag_t *mag)
3227{
3228
3229 if (mag->nrounds == 0)
3230 return (NULL);
3231 mag->nrounds--;
3232
3233 return (mag->rounds[mag->nrounds]);
3234}
3235
3236static void
3237mag_load(mag_t *mag)
3238{
3239 arena_t *arena;
3240 arena_bin_t *bin;
3241 arena_run_t *run;
3242 void *round;
3243 size_t i;
3244
3245 arena = choose_arena();
3246 bin = &arena->bins[mag->binind];
Jason Evansb7924f52009-06-23 19:01:18 -07003247#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003248 arena_lock_balance(arena);
3249#else
3250 malloc_spin_lock(&arena->lock);
3251#endif
3252 for (i = mag->nrounds; i < max_rounds; i++) {
3253 if ((run = bin->runcur) != NULL && run->nfree > 0)
3254 round = arena_bin_malloc_easy(arena, bin, run);
3255 else
3256 round = arena_bin_malloc_hard(arena, bin);
3257 if (round == NULL)
3258 break;
3259 mag->rounds[i] = round;
3260 }
Jason Evansb7924f52009-06-23 19:01:18 -07003261#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003262 bin->stats.nmags++;
3263 arena->stats.nmalloc_small += (i - mag->nrounds);
3264 arena->stats.allocated_small += (i - mag->nrounds) * bin->reg_size;
3265#endif
3266 malloc_spin_unlock(&arena->lock);
3267 mag->nrounds = i;
3268}
3269
3270static inline void *
3271mag_rack_alloc(mag_rack_t *rack, size_t size, bool zero)
3272{
3273 void *ret;
3274 bin_mags_t *bin_mags;
3275 mag_t *mag;
3276 size_t binind;
3277
3278 binind = size2bin[size];
3279 assert(binind < nbins);
3280 bin_mags = &rack->bin_mags[binind];
3281
3282 mag = bin_mags->curmag;
3283 if (mag == NULL) {
3284 /* Create an initial magazine for this size class. */
3285 assert(bin_mags->sparemag == NULL);
3286 mag = mag_create(choose_arena(), binind);
3287 if (mag == NULL)
3288 return (NULL);
3289 bin_mags->curmag = mag;
3290 mag_load(mag);
3291 }
3292
3293 ret = mag_alloc(mag);
3294 if (ret == NULL) {
3295 if (bin_mags->sparemag != NULL) {
3296 if (bin_mags->sparemag->nrounds > 0) {
3297 /* Swap magazines. */
3298 bin_mags->curmag = bin_mags->sparemag;
3299 bin_mags->sparemag = mag;
3300 mag = bin_mags->curmag;
3301 } else {
3302 /* Reload the current magazine. */
3303 mag_load(mag);
3304 }
3305 } else {
3306 /* Create a second magazine. */
3307 mag = mag_create(choose_arena(), binind);
3308 if (mag == NULL)
3309 return (NULL);
3310 mag_load(mag);
3311 bin_mags->sparemag = bin_mags->curmag;
3312 bin_mags->curmag = mag;
3313 }
3314 ret = mag_alloc(mag);
3315 if (ret == NULL)
3316 return (NULL);
3317 }
3318
3319 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003320#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003321 if (opt_junk)
3322 memset(ret, 0xa5, size);
3323 else if (opt_zero)
3324 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003325#endif
Jason Evans289053c2009-06-22 12:08:42 -07003326 } else
3327 memset(ret, 0, size);
3328
3329 return (ret);
3330}
3331#endif
3332
3333static inline void *
3334arena_malloc_small(arena_t *arena, size_t size, bool zero)
3335{
3336 void *ret;
3337 arena_bin_t *bin;
3338 arena_run_t *run;
3339 size_t binind;
3340
3341 binind = size2bin[size];
3342 assert(binind < nbins);
3343 bin = &arena->bins[binind];
3344 size = bin->reg_size;
3345
Jason Evansb7924f52009-06-23 19:01:18 -07003346#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003347 arena_lock_balance(arena);
3348#else
3349 malloc_spin_lock(&arena->lock);
3350#endif
3351 if ((run = bin->runcur) != NULL && run->nfree > 0)
3352 ret = arena_bin_malloc_easy(arena, bin, run);
3353 else
3354 ret = arena_bin_malloc_hard(arena, bin);
3355
3356 if (ret == NULL) {
3357 malloc_spin_unlock(&arena->lock);
3358 return (NULL);
3359 }
3360
Jason Evansb7924f52009-06-23 19:01:18 -07003361#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003362 bin->stats.nrequests++;
3363 arena->stats.nmalloc_small++;
3364 arena->stats.allocated_small += size;
3365#endif
3366 malloc_spin_unlock(&arena->lock);
3367
3368 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003369#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003370 if (opt_junk)
3371 memset(ret, 0xa5, size);
3372 else if (opt_zero)
3373 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003374#endif
Jason Evans289053c2009-06-22 12:08:42 -07003375 } else
3376 memset(ret, 0, size);
3377
3378 return (ret);
3379}
3380
3381static void *
3382arena_malloc_large(arena_t *arena, size_t size, bool zero)
3383{
3384 void *ret;
3385
3386 /* Large allocation. */
3387 size = PAGE_CEILING(size);
Jason Evansb7924f52009-06-23 19:01:18 -07003388#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003389 arena_lock_balance(arena);
3390#else
3391 malloc_spin_lock(&arena->lock);
3392#endif
3393 ret = (void *)arena_run_alloc(arena, size, true, zero);
3394 if (ret == NULL) {
3395 malloc_spin_unlock(&arena->lock);
3396 return (NULL);
3397 }
Jason Evansb7924f52009-06-23 19:01:18 -07003398#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003399 arena->stats.nmalloc_large++;
3400 arena->stats.allocated_large += size;
3401#endif
3402 malloc_spin_unlock(&arena->lock);
3403
3404 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003405#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003406 if (opt_junk)
3407 memset(ret, 0xa5, size);
3408 else if (opt_zero)
3409 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003410#endif
Jason Evans289053c2009-06-22 12:08:42 -07003411 }
3412
3413 return (ret);
3414}
3415
3416static inline void *
Jason Evanscc00a152009-06-25 18:06:48 -07003417arena_malloc(size_t size, bool zero)
Jason Evans289053c2009-06-22 12:08:42 -07003418{
3419
Jason Evans289053c2009-06-22 12:08:42 -07003420 assert(size != 0);
3421 assert(QUANTUM_CEILING(size) <= arena_maxclass);
3422
3423 if (size <= bin_maxclass) {
Jason Evansb7924f52009-06-23 19:01:18 -07003424#ifdef JEMALLOC_MAG
3425 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07003426 mag_rack_t *rack = mag_rack;
3427 if (rack == NULL) {
Jason Evanscc00a152009-06-25 18:06:48 -07003428 rack = mag_rack_create(choose_arena());
Jason Evans289053c2009-06-22 12:08:42 -07003429 if (rack == NULL)
3430 return (NULL);
3431 mag_rack = rack;
Jason Evansb7924f52009-06-23 19:01:18 -07003432 pthread_setspecific(mag_rack_tsd, rack);
Jason Evans289053c2009-06-22 12:08:42 -07003433 }
3434 return (mag_rack_alloc(rack, size, zero));
3435 } else
3436#endif
Jason Evanscc00a152009-06-25 18:06:48 -07003437 return (arena_malloc_small(choose_arena(), size, zero));
Jason Evans289053c2009-06-22 12:08:42 -07003438 } else
Jason Evanscc00a152009-06-25 18:06:48 -07003439 return (arena_malloc_large(choose_arena(), size, zero));
Jason Evans289053c2009-06-22 12:08:42 -07003440}
3441
3442static inline void *
3443imalloc(size_t size)
3444{
3445
3446 assert(size != 0);
3447
3448 if (size <= arena_maxclass)
Jason Evanscc00a152009-06-25 18:06:48 -07003449 return (arena_malloc(size, false));
Jason Evans289053c2009-06-22 12:08:42 -07003450 else
3451 return (huge_malloc(size, false));
3452}
3453
3454static inline void *
3455icalloc(size_t size)
3456{
3457
3458 if (size <= arena_maxclass)
Jason Evanscc00a152009-06-25 18:06:48 -07003459 return (arena_malloc(size, true));
Jason Evans289053c2009-06-22 12:08:42 -07003460 else
3461 return (huge_malloc(size, true));
3462}
3463
3464/* Only handles large allocations that require more than page alignment. */
3465static void *
3466arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size)
3467{
3468 void *ret;
3469 size_t offset;
3470 arena_chunk_t *chunk;
3471
3472 assert((size & PAGE_MASK) == 0);
3473 assert((alignment & PAGE_MASK) == 0);
3474
Jason Evansb7924f52009-06-23 19:01:18 -07003475#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003476 arena_lock_balance(arena);
3477#else
3478 malloc_spin_lock(&arena->lock);
3479#endif
3480 ret = (void *)arena_run_alloc(arena, alloc_size, true, false);
3481 if (ret == NULL) {
3482 malloc_spin_unlock(&arena->lock);
3483 return (NULL);
3484 }
3485
3486 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
3487
3488 offset = (uintptr_t)ret & (alignment - 1);
3489 assert((offset & PAGE_MASK) == 0);
3490 assert(offset < alloc_size);
3491 if (offset == 0)
3492 arena_run_trim_tail(arena, chunk, ret, alloc_size, size, false);
3493 else {
3494 size_t leadsize, trailsize;
3495
3496 leadsize = alignment - offset;
3497 if (leadsize > 0) {
3498 arena_run_trim_head(arena, chunk, ret, alloc_size,
3499 alloc_size - leadsize);
3500 ret = (void *)((uintptr_t)ret + leadsize);
3501 }
3502
3503 trailsize = alloc_size - leadsize - size;
3504 if (trailsize != 0) {
3505 /* Trim trailing space. */
3506 assert(trailsize < alloc_size);
3507 arena_run_trim_tail(arena, chunk, ret, size + trailsize,
3508 size, false);
3509 }
3510 }
3511
Jason Evansb7924f52009-06-23 19:01:18 -07003512#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003513 arena->stats.nmalloc_large++;
3514 arena->stats.allocated_large += size;
3515#endif
3516 malloc_spin_unlock(&arena->lock);
3517
Jason Evansb7924f52009-06-23 19:01:18 -07003518#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003519 if (opt_junk)
3520 memset(ret, 0xa5, size);
3521 else if (opt_zero)
3522 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003523#endif
Jason Evans289053c2009-06-22 12:08:42 -07003524 return (ret);
3525}
3526
3527static inline void *
3528ipalloc(size_t alignment, size_t size)
3529{
3530 void *ret;
3531 size_t ceil_size;
3532
3533 /*
3534 * Round size up to the nearest multiple of alignment.
3535 *
3536 * This done, we can take advantage of the fact that for each small
3537 * size class, every object is aligned at the smallest power of two
3538 * that is non-zero in the base two representation of the size. For
3539 * example:
3540 *
3541 * Size | Base 2 | Minimum alignment
3542 * -----+----------+------------------
3543 * 96 | 1100000 | 32
3544 * 144 | 10100000 | 32
3545 * 192 | 11000000 | 64
3546 *
3547 * Depending on runtime settings, it is possible that arena_malloc()
3548 * will further round up to a power of two, but that never causes
3549 * correctness issues.
3550 */
3551 ceil_size = (size + (alignment - 1)) & (-alignment);
3552 /*
3553 * (ceil_size < size) protects against the combination of maximal
3554 * alignment and size greater than maximal alignment.
3555 */
3556 if (ceil_size < size) {
3557 /* size_t overflow. */
3558 return (NULL);
3559 }
3560
3561 if (ceil_size <= PAGE_SIZE || (alignment <= PAGE_SIZE
3562 && ceil_size <= arena_maxclass))
Jason Evanscc00a152009-06-25 18:06:48 -07003563 ret = arena_malloc(ceil_size, false);
Jason Evans289053c2009-06-22 12:08:42 -07003564 else {
3565 size_t run_size;
3566
3567 /*
3568 * We can't achieve subpage alignment, so round up alignment
3569 * permanently; it makes later calculations simpler.
3570 */
3571 alignment = PAGE_CEILING(alignment);
3572 ceil_size = PAGE_CEILING(size);
3573 /*
3574 * (ceil_size < size) protects against very large sizes within
3575 * PAGE_SIZE of SIZE_T_MAX.
3576 *
3577 * (ceil_size + alignment < ceil_size) protects against the
3578 * combination of maximal alignment and ceil_size large enough
3579 * to cause overflow. This is similar to the first overflow
3580 * check above, but it needs to be repeated due to the new
3581 * ceil_size value, which may now be *equal* to maximal
3582 * alignment, whereas before we only detected overflow if the
3583 * original size was *greater* than maximal alignment.
3584 */
3585 if (ceil_size < size || ceil_size + alignment < ceil_size) {
3586 /* size_t overflow. */
3587 return (NULL);
3588 }
3589
3590 /*
3591 * Calculate the size of the over-size run that arena_palloc()
3592 * would need to allocate in order to guarantee the alignment.
3593 */
3594 if (ceil_size >= alignment)
3595 run_size = ceil_size + alignment - PAGE_SIZE;
3596 else {
3597 /*
3598 * It is possible that (alignment << 1) will cause
3599 * overflow, but it doesn't matter because we also
3600 * subtract PAGE_SIZE, which in the case of overflow
3601 * leaves us with a very large run_size. That causes
3602 * the first conditional below to fail, which means
3603 * that the bogus run_size value never gets used for
3604 * anything important.
3605 */
3606 run_size = (alignment << 1) - PAGE_SIZE;
3607 }
3608
3609 if (run_size <= arena_maxclass) {
3610 ret = arena_palloc(choose_arena(), alignment, ceil_size,
3611 run_size);
3612 } else if (alignment <= chunksize)
3613 ret = huge_malloc(ceil_size, false);
3614 else
3615 ret = huge_palloc(alignment, ceil_size);
3616 }
3617
3618 assert(((uintptr_t)ret & (alignment - 1)) == 0);
3619 return (ret);
3620}
3621
3622/* Return the size of the allocation pointed to by ptr. */
3623static size_t
3624arena_salloc(const void *ptr)
3625{
3626 size_t ret;
3627 arena_chunk_t *chunk;
3628 size_t pageind, mapbits;
3629
3630 assert(ptr != NULL);
3631 assert(CHUNK_ADDR2BASE(ptr) != ptr);
3632
3633 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3634 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3635 mapbits = chunk->map[pageind].bits;
3636 assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
3637 if ((mapbits & CHUNK_MAP_LARGE) == 0) {
3638 arena_run_t *run = (arena_run_t *)(mapbits & ~PAGE_MASK);
3639 assert(run->magic == ARENA_RUN_MAGIC);
3640 ret = run->bin->reg_size;
3641 } else {
3642 ret = mapbits & ~PAGE_MASK;
3643 assert(ret != 0);
3644 }
3645
3646 return (ret);
3647}
3648
3649static inline size_t
3650isalloc(const void *ptr)
3651{
3652 size_t ret;
3653 arena_chunk_t *chunk;
3654
3655 assert(ptr != NULL);
3656
3657 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3658 if (chunk != ptr) {
3659 /* Region. */
3660 assert(chunk->arena->magic == ARENA_MAGIC);
3661
3662 ret = arena_salloc(ptr);
3663 } else {
3664 extent_node_t *node, key;
3665
3666 /* Chunk (huge allocation). */
3667
3668 malloc_mutex_lock(&huge_mtx);
3669
3670 /* Extract from tree of huge allocations. */
3671 key.addr = __DECONST(void *, ptr);
3672 node = extent_tree_ad_search(&huge, &key);
3673 assert(node != NULL);
3674
3675 ret = node->size;
3676
3677 malloc_mutex_unlock(&huge_mtx);
3678 }
3679
3680 return (ret);
3681}
3682
3683static inline void
3684arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3685 arena_chunk_map_t *mapelm)
3686{
3687 arena_run_t *run;
3688 arena_bin_t *bin;
3689 size_t size;
3690
3691 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
3692 assert(run->magic == ARENA_RUN_MAGIC);
3693 bin = run->bin;
3694 size = bin->reg_size;
3695
Jason Evansb7924f52009-06-23 19:01:18 -07003696#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003697 if (opt_junk)
3698 memset(ptr, 0x5a, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003699#endif
Jason Evans289053c2009-06-22 12:08:42 -07003700
3701 arena_run_reg_dalloc(run, bin, ptr, size);
3702 run->nfree++;
3703
3704 if (run->nfree == bin->nregs) {
3705 /* Deallocate run. */
3706 if (run == bin->runcur)
3707 bin->runcur = NULL;
3708 else if (bin->nregs != 1) {
3709 size_t run_pageind = (((uintptr_t)run -
3710 (uintptr_t)chunk)) >> PAGE_SHIFT;
3711 arena_chunk_map_t *run_mapelm =
3712 &chunk->map[run_pageind];
3713 /*
3714 * This block's conditional is necessary because if the
3715 * run only contains one region, then it never gets
3716 * inserted into the non-full runs tree.
3717 */
3718 arena_run_tree_remove(&bin->runs, run_mapelm);
3719 }
Jason Evansb7924f52009-06-23 19:01:18 -07003720#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07003721 run->magic = 0;
3722#endif
3723 arena_run_dalloc(arena, run, true);
Jason Evansb7924f52009-06-23 19:01:18 -07003724#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003725 bin->stats.curruns--;
3726#endif
3727 } else if (run->nfree == 1 && run != bin->runcur) {
3728 /*
3729 * Make sure that bin->runcur always refers to the lowest
3730 * non-full run, if one exists.
3731 */
3732 if (bin->runcur == NULL)
3733 bin->runcur = run;
3734 else if ((uintptr_t)run < (uintptr_t)bin->runcur) {
3735 /* Switch runcur. */
3736 if (bin->runcur->nfree > 0) {
3737 arena_chunk_t *runcur_chunk =
3738 CHUNK_ADDR2BASE(bin->runcur);
3739 size_t runcur_pageind =
3740 (((uintptr_t)bin->runcur -
3741 (uintptr_t)runcur_chunk)) >> PAGE_SHIFT;
3742 arena_chunk_map_t *runcur_mapelm =
3743 &runcur_chunk->map[runcur_pageind];
3744
3745 /* Insert runcur. */
3746 arena_run_tree_insert(&bin->runs,
3747 runcur_mapelm);
3748 }
3749 bin->runcur = run;
3750 } else {
3751 size_t run_pageind = (((uintptr_t)run -
3752 (uintptr_t)chunk)) >> PAGE_SHIFT;
3753 arena_chunk_map_t *run_mapelm =
3754 &chunk->map[run_pageind];
3755
3756 assert(arena_run_tree_search(&bin->runs, run_mapelm) ==
3757 NULL);
3758 arena_run_tree_insert(&bin->runs, run_mapelm);
3759 }
3760 }
Jason Evansb7924f52009-06-23 19:01:18 -07003761#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003762 arena->stats.allocated_small -= size;
3763 arena->stats.ndalloc_small++;
3764#endif
3765}
3766
Jason Evansb7924f52009-06-23 19:01:18 -07003767#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003768static void
3769mag_unload(mag_t *mag)
3770{
3771 arena_chunk_t *chunk;
3772 arena_t *arena;
3773 void *round;
3774 size_t i, ndeferred, nrounds;
3775
3776 for (ndeferred = mag->nrounds; ndeferred > 0;) {
3777 nrounds = ndeferred;
3778 /* Lock the arena associated with the first round. */
3779 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mag->rounds[0]);
3780 arena = chunk->arena;
Jason Evansb7924f52009-06-23 19:01:18 -07003781#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003782 arena_lock_balance(arena);
3783#else
3784 malloc_spin_lock(&arena->lock);
3785#endif
3786 /* Deallocate every round that belongs to the locked arena. */
3787 for (i = ndeferred = 0; i < nrounds; i++) {
3788 round = mag->rounds[i];
3789 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(round);
3790 if (chunk->arena == arena) {
3791 size_t pageind = (((uintptr_t)round -
3792 (uintptr_t)chunk) >> PAGE_SHIFT);
3793 arena_chunk_map_t *mapelm =
3794 &chunk->map[pageind];
3795 arena_dalloc_small(arena, chunk, round, mapelm);
3796 } else {
3797 /*
3798 * This round was allocated via a different
3799 * arena than the one that is currently locked.
3800 * Stash the round, so that it can be handled
3801 * in a future pass.
3802 */
3803 mag->rounds[ndeferred] = round;
3804 ndeferred++;
3805 }
3806 }
3807 malloc_spin_unlock(&arena->lock);
3808 }
3809
3810 mag->nrounds = 0;
3811}
3812
3813static inline void
3814mag_rack_dalloc(mag_rack_t *rack, void *ptr)
3815{
3816 arena_t *arena;
3817 arena_chunk_t *chunk;
3818 arena_run_t *run;
3819 arena_bin_t *bin;
3820 bin_mags_t *bin_mags;
3821 mag_t *mag;
3822 size_t pageind, binind;
3823 arena_chunk_map_t *mapelm;
3824
3825 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3826 arena = chunk->arena;
3827 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3828 mapelm = &chunk->map[pageind];
3829 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
3830 assert(run->magic == ARENA_RUN_MAGIC);
3831 bin = run->bin;
3832 binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
3833 sizeof(arena_bin_t);
3834 assert(binind < nbins);
3835
Jason Evansb7924f52009-06-23 19:01:18 -07003836#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003837 if (opt_junk)
3838 memset(ptr, 0x5a, arena->bins[binind].reg_size);
Jason Evansb7924f52009-06-23 19:01:18 -07003839#endif
Jason Evans289053c2009-06-22 12:08:42 -07003840
3841 bin_mags = &rack->bin_mags[binind];
3842 mag = bin_mags->curmag;
3843 if (mag == NULL) {
3844 /* Create an initial magazine for this size class. */
3845 assert(bin_mags->sparemag == NULL);
3846 mag = mag_create(choose_arena(), binind);
3847 if (mag == NULL) {
3848 malloc_spin_lock(&arena->lock);
3849 arena_dalloc_small(arena, chunk, ptr, mapelm);
3850 malloc_spin_unlock(&arena->lock);
3851 return;
3852 }
3853 bin_mags->curmag = mag;
3854 }
3855
3856 if (mag->nrounds == max_rounds) {
3857 if (bin_mags->sparemag != NULL) {
3858 if (bin_mags->sparemag->nrounds < max_rounds) {
3859 /* Swap magazines. */
3860 bin_mags->curmag = bin_mags->sparemag;
3861 bin_mags->sparemag = mag;
3862 mag = bin_mags->curmag;
3863 } else {
3864 /* Unload the current magazine. */
3865 mag_unload(mag);
3866 }
3867 } else {
3868 /* Create a second magazine. */
3869 mag = mag_create(choose_arena(), binind);
3870 if (mag == NULL) {
3871 mag = rack->bin_mags[binind].curmag;
3872 mag_unload(mag);
3873 } else {
3874 bin_mags->sparemag = bin_mags->curmag;
3875 bin_mags->curmag = mag;
3876 }
3877 }
3878 assert(mag->nrounds < max_rounds);
3879 }
3880 mag->rounds[mag->nrounds] = ptr;
3881 mag->nrounds++;
3882}
3883#endif
3884
3885static void
3886arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr)
3887{
3888 /* Large allocation. */
3889 malloc_spin_lock(&arena->lock);
3890
Jason Evansb7924f52009-06-23 19:01:18 -07003891#ifdef JEMALLOC_FILL
3892#ifndef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003893 if (opt_junk)
3894#endif
Jason Evansb7924f52009-06-23 19:01:18 -07003895#endif
Jason Evans289053c2009-06-22 12:08:42 -07003896 {
Jason Evansb7924f52009-06-23 19:01:18 -07003897#if (defined(JEMALLOC_FILL) || defined(JEMALLOC_STATS))
Jason Evans289053c2009-06-22 12:08:42 -07003898 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >>
3899 PAGE_SHIFT;
3900 size_t size = chunk->map[pageind].bits & ~PAGE_MASK;
Jason Evansb7924f52009-06-23 19:01:18 -07003901#endif
Jason Evans289053c2009-06-22 12:08:42 -07003902
Jason Evansb7924f52009-06-23 19:01:18 -07003903#ifdef JEMALLOC_FILL
3904#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003905 if (opt_junk)
3906#endif
3907 memset(ptr, 0x5a, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003908#endif
3909#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003910 arena->stats.allocated_large -= size;
3911#endif
3912 }
Jason Evansb7924f52009-06-23 19:01:18 -07003913#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003914 arena->stats.ndalloc_large++;
3915#endif
3916
3917 arena_run_dalloc(arena, (arena_run_t *)ptr, true);
3918 malloc_spin_unlock(&arena->lock);
3919}
3920
3921static inline void
3922arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
3923{
3924 size_t pageind;
3925 arena_chunk_map_t *mapelm;
3926
3927 assert(arena != NULL);
3928 assert(arena->magic == ARENA_MAGIC);
3929 assert(chunk->arena == arena);
3930 assert(ptr != NULL);
3931 assert(CHUNK_ADDR2BASE(ptr) != ptr);
3932
3933 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3934 mapelm = &chunk->map[pageind];
3935 assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
3936 if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
3937 /* Small allocation. */
Jason Evansb7924f52009-06-23 19:01:18 -07003938#ifdef JEMALLOC_MAG
3939 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07003940 mag_rack_t *rack = mag_rack;
3941 if (rack == NULL) {
3942 rack = mag_rack_create(arena);
3943 if (rack == NULL) {
3944 malloc_spin_lock(&arena->lock);
3945 arena_dalloc_small(arena, chunk, ptr,
3946 mapelm);
3947 malloc_spin_unlock(&arena->lock);
3948 }
3949 mag_rack = rack;
Jason Evansb7924f52009-06-23 19:01:18 -07003950 pthread_setspecific(mag_rack_tsd, rack);
Jason Evans289053c2009-06-22 12:08:42 -07003951 }
3952 mag_rack_dalloc(rack, ptr);
3953 } else {
3954#endif
3955 malloc_spin_lock(&arena->lock);
3956 arena_dalloc_small(arena, chunk, ptr, mapelm);
3957 malloc_spin_unlock(&arena->lock);
Jason Evansb7924f52009-06-23 19:01:18 -07003958#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003959 }
3960#endif
3961 } else
3962 arena_dalloc_large(arena, chunk, ptr);
3963}
3964
3965static inline void
3966idalloc(void *ptr)
3967{
3968 arena_chunk_t *chunk;
3969
3970 assert(ptr != NULL);
3971
3972 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3973 if (chunk != ptr)
3974 arena_dalloc(chunk->arena, chunk, ptr);
3975 else
3976 huge_dalloc(ptr);
3977}
3978
3979static void
3980arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3981 size_t size, size_t oldsize)
3982{
3983
3984 assert(size < oldsize);
3985
3986 /*
3987 * Shrink the run, and make trailing pages available for other
3988 * allocations.
3989 */
Jason Evansb7924f52009-06-23 19:01:18 -07003990#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003991 arena_lock_balance(arena);
3992#else
3993 malloc_spin_lock(&arena->lock);
3994#endif
3995 arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size,
3996 true);
Jason Evansb7924f52009-06-23 19:01:18 -07003997#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003998 arena->stats.allocated_large -= oldsize - size;
3999#endif
4000 malloc_spin_unlock(&arena->lock);
4001}
4002
4003static bool
4004arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
4005 size_t size, size_t oldsize)
4006{
4007 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
4008 size_t npages = oldsize >> PAGE_SHIFT;
4009
4010 assert(oldsize == (chunk->map[pageind].bits & ~PAGE_MASK));
4011
4012 /* Try to extend the run. */
4013 assert(size > oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004014#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004015 arena_lock_balance(arena);
4016#else
4017 malloc_spin_lock(&arena->lock);
4018#endif
4019 if (pageind + npages < chunk_npages && (chunk->map[pageind+npages].bits
4020 & CHUNK_MAP_ALLOCATED) == 0 && (chunk->map[pageind+npages].bits &
4021 ~PAGE_MASK) >= size - oldsize) {
4022 /*
4023 * The next run is available and sufficiently large. Split the
4024 * following run, then merge the first part with the existing
4025 * allocation.
4026 */
4027 arena_run_split(arena, (arena_run_t *)((uintptr_t)chunk +
4028 ((pageind+npages) << PAGE_SHIFT)), size - oldsize, true,
4029 false);
4030
4031 chunk->map[pageind].bits = size | CHUNK_MAP_LARGE |
4032 CHUNK_MAP_ALLOCATED;
4033 chunk->map[pageind+npages].bits = CHUNK_MAP_LARGE |
4034 CHUNK_MAP_ALLOCATED;
4035
Jason Evansb7924f52009-06-23 19:01:18 -07004036#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004037 arena->stats.allocated_large += size - oldsize;
4038#endif
4039 malloc_spin_unlock(&arena->lock);
4040 return (false);
4041 }
4042 malloc_spin_unlock(&arena->lock);
4043
4044 return (true);
4045}
4046
4047/*
4048 * Try to resize a large allocation, in order to avoid copying. This will
4049 * always fail if growing an object, and the following run is already in use.
4050 */
4051static bool
4052arena_ralloc_large(void *ptr, size_t size, size_t oldsize)
4053{
4054 size_t psize;
4055
4056 psize = PAGE_CEILING(size);
4057 if (psize == oldsize) {
4058 /* Same size class. */
Jason Evansb7924f52009-06-23 19:01:18 -07004059#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004060 if (opt_junk && size < oldsize) {
4061 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize -
4062 size);
4063 }
Jason Evansb7924f52009-06-23 19:01:18 -07004064#endif
Jason Evans289053c2009-06-22 12:08:42 -07004065 return (false);
4066 } else {
4067 arena_chunk_t *chunk;
4068 arena_t *arena;
4069
4070 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
4071 arena = chunk->arena;
4072 assert(arena->magic == ARENA_MAGIC);
4073
4074 if (psize < oldsize) {
Jason Evansb7924f52009-06-23 19:01:18 -07004075#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004076 /* Fill before shrinking in order avoid a race. */
4077 if (opt_junk) {
4078 memset((void *)((uintptr_t)ptr + size), 0x5a,
4079 oldsize - size);
4080 }
Jason Evansb7924f52009-06-23 19:01:18 -07004081#endif
Jason Evans289053c2009-06-22 12:08:42 -07004082 arena_ralloc_large_shrink(arena, chunk, ptr, psize,
4083 oldsize);
4084 return (false);
4085 } else {
4086 bool ret = arena_ralloc_large_grow(arena, chunk, ptr,
4087 psize, oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004088#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004089 if (ret == false && opt_zero) {
4090 memset((void *)((uintptr_t)ptr + oldsize), 0,
4091 size - oldsize);
4092 }
Jason Evansb7924f52009-06-23 19:01:18 -07004093#endif
Jason Evans289053c2009-06-22 12:08:42 -07004094 return (ret);
4095 }
4096 }
4097}
4098
4099static void *
4100arena_ralloc(void *ptr, size_t size, size_t oldsize)
4101{
4102 void *ret;
4103 size_t copysize;
4104
4105 /* Try to avoid moving the allocation. */
4106 if (size <= bin_maxclass) {
4107 if (oldsize <= bin_maxclass && size2bin[size] ==
4108 size2bin[oldsize])
4109 goto IN_PLACE;
4110 } else {
4111 if (oldsize > bin_maxclass && oldsize <= arena_maxclass) {
4112 assert(size > bin_maxclass);
4113 if (arena_ralloc_large(ptr, size, oldsize) == false)
4114 return (ptr);
4115 }
4116 }
4117
4118 /*
4119 * If we get here, then size and oldsize are different enough that we
4120 * need to move the object. In that case, fall back to allocating new
4121 * space and copying.
4122 */
Jason Evanscc00a152009-06-25 18:06:48 -07004123 ret = arena_malloc(size, false);
Jason Evans289053c2009-06-22 12:08:42 -07004124 if (ret == NULL)
4125 return (NULL);
4126
4127 /* Junk/zero-filling were already done by arena_malloc(). */
4128 copysize = (size < oldsize) ? size : oldsize;
4129 memcpy(ret, ptr, copysize);
4130 idalloc(ptr);
4131 return (ret);
4132IN_PLACE:
Jason Evansb7924f52009-06-23 19:01:18 -07004133#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004134 if (opt_junk && size < oldsize)
4135 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size);
4136 else if (opt_zero && size > oldsize)
4137 memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004138#endif
Jason Evans289053c2009-06-22 12:08:42 -07004139 return (ptr);
4140}
4141
4142static inline void *
4143iralloc(void *ptr, size_t size)
4144{
4145 size_t oldsize;
4146
4147 assert(ptr != NULL);
4148 assert(size != 0);
4149
4150 oldsize = isalloc(ptr);
4151
4152 if (size <= arena_maxclass)
4153 return (arena_ralloc(ptr, size, oldsize));
4154 else
4155 return (huge_ralloc(ptr, size, oldsize));
4156}
4157
4158static bool
4159arena_new(arena_t *arena)
4160{
4161 unsigned i;
4162 arena_bin_t *bin;
4163 size_t prev_run_size;
4164
4165 if (malloc_spin_init(&arena->lock))
4166 return (true);
4167
Jason Evansb7924f52009-06-23 19:01:18 -07004168#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004169 memset(&arena->stats, 0, sizeof(arena_stats_t));
4170#endif
4171
4172 /* Initialize chunks. */
4173 arena_chunk_tree_dirty_new(&arena->chunks_dirty);
4174 arena->spare = NULL;
4175
4176 arena->ndirty = 0;
4177
4178 arena_avail_tree_new(&arena->runs_avail);
4179
Jason Evansb7924f52009-06-23 19:01:18 -07004180#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004181 arena->contention = 0;
4182#endif
4183
4184 /* Initialize bins. */
4185 prev_run_size = PAGE_SIZE;
4186
4187 i = 0;
Jason Evansb7924f52009-06-23 19:01:18 -07004188#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004189 /* (2^n)-spaced tiny bins. */
4190 for (; i < ntbins; i++) {
4191 bin = &arena->bins[i];
4192 bin->runcur = NULL;
4193 arena_run_tree_new(&bin->runs);
4194
4195 bin->reg_size = (1U << (TINY_MIN_2POW + i));
4196
4197 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4198
Jason Evansb7924f52009-06-23 19:01:18 -07004199#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004200 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4201#endif
4202 }
4203#endif
4204
4205 /* Quantum-spaced bins. */
4206 for (; i < ntbins + nqbins; i++) {
4207 bin = &arena->bins[i];
4208 bin->runcur = NULL;
4209 arena_run_tree_new(&bin->runs);
4210
4211 bin->reg_size = (i - ntbins + 1) << QUANTUM_2POW;
4212
4213 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4214
Jason Evansb7924f52009-06-23 19:01:18 -07004215#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004216 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4217#endif
4218 }
4219
4220 /* Cacheline-spaced bins. */
4221 for (; i < ntbins + nqbins + ncbins; i++) {
4222 bin = &arena->bins[i];
4223 bin->runcur = NULL;
4224 arena_run_tree_new(&bin->runs);
4225
4226 bin->reg_size = cspace_min + ((i - (ntbins + nqbins)) <<
4227 CACHELINE_2POW);
4228
4229 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4230
Jason Evansb7924f52009-06-23 19:01:18 -07004231#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004232 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4233#endif
4234 }
4235
4236 /* Subpage-spaced bins. */
4237 for (; i < nbins; i++) {
4238 bin = &arena->bins[i];
4239 bin->runcur = NULL;
4240 arena_run_tree_new(&bin->runs);
4241
4242 bin->reg_size = sspace_min + ((i - (ntbins + nqbins + ncbins))
4243 << SUBPAGE_2POW);
4244
4245 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4246
Jason Evansb7924f52009-06-23 19:01:18 -07004247#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004248 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4249#endif
4250 }
4251
Jason Evansb7924f52009-06-23 19:01:18 -07004252#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004253 arena->magic = ARENA_MAGIC;
4254#endif
4255
4256 return (false);
4257}
4258
4259/* Create a new arena and insert it into the arenas array at index ind. */
4260static arena_t *
4261arenas_extend(unsigned ind)
4262{
4263 arena_t *ret;
4264
4265 /* Allocate enough space for trailing bins. */
4266 ret = (arena_t *)base_alloc(sizeof(arena_t)
4267 + (sizeof(arena_bin_t) * (nbins - 1)));
4268 if (ret != NULL && arena_new(ret) == false) {
4269 arenas[ind] = ret;
4270 return (ret);
4271 }
4272 /* Only reached if there is an OOM error. */
4273
4274 /*
4275 * OOM here is quite inconvenient to propagate, since dealing with it
4276 * would require a check for failure in the fast path. Instead, punt
4277 * by using arenas[0]. In practice, this is an extremely unlikely
4278 * failure.
4279 */
Jason Evans804c9ec2009-06-22 17:44:33 -07004280 jemalloc_message("<jemalloc>",
4281 ": Error initializing arena\n", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004282 if (opt_abort)
4283 abort();
4284
4285 return (arenas[0]);
4286}
4287
Jason Evansb7924f52009-06-23 19:01:18 -07004288#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07004289static mag_t *
4290mag_create(arena_t *arena, size_t binind)
4291{
4292 mag_t *ret;
4293
4294 if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <=
4295 bin_maxclass) {
4296 ret = arena_malloc_small(arena, sizeof(mag_t) + (sizeof(void *)
4297 * (max_rounds - 1)), false);
4298 } else {
4299 ret = imalloc(sizeof(mag_t) + (sizeof(void *) * (max_rounds -
4300 1)));
4301 }
4302 if (ret == NULL)
4303 return (NULL);
4304 ret->binind = binind;
4305 ret->nrounds = 0;
4306
4307 return (ret);
4308}
4309
4310static void
4311mag_destroy(mag_t *mag)
4312{
4313 arena_t *arena;
4314 arena_chunk_t *chunk;
4315 size_t pageind;
4316 arena_chunk_map_t *mapelm;
4317
4318 chunk = CHUNK_ADDR2BASE(mag);
4319 arena = chunk->arena;
4320 pageind = (((uintptr_t)mag - (uintptr_t)chunk) >> PAGE_SHIFT);
4321 mapelm = &chunk->map[pageind];
4322
4323 assert(mag->nrounds == 0);
4324 if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <=
4325 bin_maxclass) {
4326 malloc_spin_lock(&arena->lock);
4327 arena_dalloc_small(arena, chunk, mag, mapelm);
4328 malloc_spin_unlock(&arena->lock);
4329 } else
4330 idalloc(mag);
4331}
4332
4333static mag_rack_t *
4334mag_rack_create(arena_t *arena)
4335{
4336
4337 assert(sizeof(mag_rack_t) + (sizeof(bin_mags_t *) * (nbins - 1)) <=
4338 bin_maxclass);
4339 return (arena_malloc_small(arena, sizeof(mag_rack_t) +
4340 (sizeof(bin_mags_t) * (nbins - 1)), true));
4341}
4342
4343static void
4344mag_rack_destroy(mag_rack_t *rack)
4345{
4346 arena_t *arena;
4347 arena_chunk_t *chunk;
4348 bin_mags_t *bin_mags;
4349 size_t i, pageind;
4350 arena_chunk_map_t *mapelm;
4351
4352 for (i = 0; i < nbins; i++) {
4353 bin_mags = &rack->bin_mags[i];
4354 if (bin_mags->curmag != NULL) {
4355 assert(bin_mags->curmag->binind == i);
4356 mag_unload(bin_mags->curmag);
4357 mag_destroy(bin_mags->curmag);
4358 }
4359 if (bin_mags->sparemag != NULL) {
4360 assert(bin_mags->sparemag->binind == i);
4361 mag_unload(bin_mags->sparemag);
4362 mag_destroy(bin_mags->sparemag);
4363 }
4364 }
4365
4366 chunk = CHUNK_ADDR2BASE(rack);
4367 arena = chunk->arena;
4368 pageind = (((uintptr_t)rack - (uintptr_t)chunk) >> PAGE_SHIFT);
4369 mapelm = &chunk->map[pageind];
4370
4371 malloc_spin_lock(&arena->lock);
4372 arena_dalloc_small(arena, chunk, rack, mapelm);
4373 malloc_spin_unlock(&arena->lock);
4374}
4375#endif
4376
4377/*
4378 * End arena.
4379 */
4380/******************************************************************************/
4381/*
4382 * Begin general internal functions.
4383 */
4384
4385static void *
4386huge_malloc(size_t size, bool zero)
4387{
4388 void *ret;
4389 size_t csize;
4390 extent_node_t *node;
4391
4392 /* Allocate one or more contiguous chunks for this request. */
4393
4394 csize = CHUNK_CEILING(size);
4395 if (csize == 0) {
4396 /* size is large enough to cause size_t wrap-around. */
4397 return (NULL);
4398 }
4399
4400 /* Allocate an extent node with which to track the chunk. */
4401 node = base_node_alloc();
4402 if (node == NULL)
4403 return (NULL);
4404
4405 ret = chunk_alloc(csize, zero);
4406 if (ret == NULL) {
4407 base_node_dealloc(node);
4408 return (NULL);
4409 }
4410
4411 /* Insert node into huge. */
4412 node->addr = ret;
4413 node->size = csize;
4414
4415 malloc_mutex_lock(&huge_mtx);
4416 extent_tree_ad_insert(&huge, node);
Jason Evansb7924f52009-06-23 19:01:18 -07004417#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004418 huge_nmalloc++;
4419 huge_allocated += csize;
4420#endif
4421 malloc_mutex_unlock(&huge_mtx);
4422
Jason Evansb7924f52009-06-23 19:01:18 -07004423#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004424 if (zero == false) {
4425 if (opt_junk)
4426 memset(ret, 0xa5, csize);
4427 else if (opt_zero)
4428 memset(ret, 0, csize);
4429 }
Jason Evansb7924f52009-06-23 19:01:18 -07004430#endif
Jason Evans289053c2009-06-22 12:08:42 -07004431
4432 return (ret);
4433}
4434
4435/* Only handles large allocations that require more than chunk alignment. */
4436static void *
4437huge_palloc(size_t alignment, size_t size)
4438{
4439 void *ret;
4440 size_t alloc_size, chunk_size, offset;
4441 extent_node_t *node;
4442
4443 /*
4444 * This allocation requires alignment that is even larger than chunk
4445 * alignment. This means that huge_malloc() isn't good enough.
4446 *
4447 * Allocate almost twice as many chunks as are demanded by the size or
4448 * alignment, in order to assure the alignment can be achieved, then
4449 * unmap leading and trailing chunks.
4450 */
4451 assert(alignment >= chunksize);
4452
4453 chunk_size = CHUNK_CEILING(size);
4454
4455 if (size >= alignment)
4456 alloc_size = chunk_size + alignment - chunksize;
4457 else
4458 alloc_size = (alignment << 1) - chunksize;
4459
4460 /* Allocate an extent node with which to track the chunk. */
4461 node = base_node_alloc();
4462 if (node == NULL)
4463 return (NULL);
4464
4465 ret = chunk_alloc(alloc_size, false);
4466 if (ret == NULL) {
4467 base_node_dealloc(node);
4468 return (NULL);
4469 }
4470
4471 offset = (uintptr_t)ret & (alignment - 1);
4472 assert((offset & chunksize_mask) == 0);
4473 assert(offset < alloc_size);
4474 if (offset == 0) {
4475 /* Trim trailing space. */
4476 chunk_dealloc((void *)((uintptr_t)ret + chunk_size), alloc_size
4477 - chunk_size);
4478 } else {
4479 size_t trailsize;
4480
4481 /* Trim leading space. */
4482 chunk_dealloc(ret, alignment - offset);
4483
4484 ret = (void *)((uintptr_t)ret + (alignment - offset));
4485
4486 trailsize = alloc_size - (alignment - offset) - chunk_size;
4487 if (trailsize != 0) {
4488 /* Trim trailing space. */
4489 assert(trailsize < alloc_size);
4490 chunk_dealloc((void *)((uintptr_t)ret + chunk_size),
4491 trailsize);
4492 }
4493 }
4494
4495 /* Insert node into huge. */
4496 node->addr = ret;
4497 node->size = chunk_size;
4498
4499 malloc_mutex_lock(&huge_mtx);
4500 extent_tree_ad_insert(&huge, node);
Jason Evansb7924f52009-06-23 19:01:18 -07004501#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004502 huge_nmalloc++;
4503 huge_allocated += chunk_size;
4504#endif
4505 malloc_mutex_unlock(&huge_mtx);
4506
Jason Evansb7924f52009-06-23 19:01:18 -07004507#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004508 if (opt_junk)
4509 memset(ret, 0xa5, chunk_size);
4510 else if (opt_zero)
4511 memset(ret, 0, chunk_size);
Jason Evansb7924f52009-06-23 19:01:18 -07004512#endif
Jason Evans289053c2009-06-22 12:08:42 -07004513
4514 return (ret);
4515}
4516
4517static void *
4518huge_ralloc(void *ptr, size_t size, size_t oldsize)
4519{
4520 void *ret;
4521 size_t copysize;
4522
4523 /* Avoid moving the allocation if the size class would not change. */
4524 if (oldsize > arena_maxclass &&
4525 CHUNK_CEILING(size) == CHUNK_CEILING(oldsize)) {
Jason Evansb7924f52009-06-23 19:01:18 -07004526#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004527 if (opt_junk && size < oldsize) {
4528 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize
4529 - size);
4530 } else if (opt_zero && size > oldsize) {
4531 memset((void *)((uintptr_t)ptr + oldsize), 0, size
4532 - oldsize);
4533 }
Jason Evansb7924f52009-06-23 19:01:18 -07004534#endif
Jason Evans289053c2009-06-22 12:08:42 -07004535 return (ptr);
4536 }
4537
4538 /*
4539 * If we get here, then size and oldsize are different enough that we
4540 * need to use a different size class. In that case, fall back to
4541 * allocating new space and copying.
4542 */
4543 ret = huge_malloc(size, false);
4544 if (ret == NULL)
4545 return (NULL);
4546
4547 copysize = (size < oldsize) ? size : oldsize;
4548 memcpy(ret, ptr, copysize);
4549 idalloc(ptr);
4550 return (ret);
4551}
4552
4553static void
4554huge_dalloc(void *ptr)
4555{
4556 extent_node_t *node, key;
4557
4558 malloc_mutex_lock(&huge_mtx);
4559
4560 /* Extract from tree of huge allocations. */
4561 key.addr = ptr;
4562 node = extent_tree_ad_search(&huge, &key);
4563 assert(node != NULL);
4564 assert(node->addr == ptr);
4565 extent_tree_ad_remove(&huge, node);
4566
Jason Evansb7924f52009-06-23 19:01:18 -07004567#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004568 huge_ndalloc++;
4569 huge_allocated -= node->size;
4570#endif
4571
4572 malloc_mutex_unlock(&huge_mtx);
4573
4574 /* Unmap chunk. */
Jason Evansb7924f52009-06-23 19:01:18 -07004575#ifdef JEMALLOC_FILL
4576#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07004577 if (opt_dss && opt_junk)
4578 memset(node->addr, 0x5a, node->size);
4579#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004580#endif
Jason Evans289053c2009-06-22 12:08:42 -07004581 chunk_dealloc(node->addr, node->size);
4582
4583 base_node_dealloc(node);
4584}
4585
4586static void
4587malloc_print_stats(void)
4588{
4589
4590 if (opt_print_stats) {
4591 char s[UMAX2S_BUFSIZE];
Jason Evans804c9ec2009-06-22 17:44:33 -07004592 jemalloc_message("___ Begin jemalloc statistics ___\n", "", "",
Jason Evans289053c2009-06-22 12:08:42 -07004593 "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004594 jemalloc_message("Assertions ",
Jason Evans289053c2009-06-22 12:08:42 -07004595#ifdef NDEBUG
4596 "disabled",
4597#else
4598 "enabled",
4599#endif
4600 "\n", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004601 jemalloc_message("Boolean JEMALLOC_OPTIONS: ",
Jason Evans289053c2009-06-22 12:08:42 -07004602 opt_abort ? "A" : "a", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004603#ifdef JEMALLOC_DSS
Jason Evans804c9ec2009-06-22 17:44:33 -07004604 jemalloc_message(opt_dss ? "D" : "d", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004605#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004606#ifdef JEMALLOC_MAG
Jason Evans804c9ec2009-06-22 17:44:33 -07004607 jemalloc_message(opt_mag ? "G" : "g", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004608#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004609#ifdef JEMALLOC_FILL
Jason Evans804c9ec2009-06-22 17:44:33 -07004610 jemalloc_message(opt_junk ? "J" : "j", "", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004611#endif
4612#ifdef JEMALLOC_DSS
Jason Evans804c9ec2009-06-22 17:44:33 -07004613 jemalloc_message(opt_mmap ? "M" : "m", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004614#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004615 jemalloc_message("P", "", "", "");
4616#ifdef JEMALLOC_STATS
4617 jemalloc_message(opt_utrace ? "U" : "u", "", "", "");
4618#endif
4619#ifdef JEMALLOC_SYSV
4620 jemalloc_message(opt_sysv ? "V" : "v", "", "", "");
4621#endif
4622#ifdef JEMALLOC_XMALLOC
4623 jemalloc_message(opt_xmalloc ? "X" : "x", "", "", "");
4624#endif
4625#ifdef JEMALLOC_FILL
4626 jemalloc_message(opt_zero ? "Z" : "z", "", "", "");
4627#endif
4628 jemalloc_message("\n", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004629
Jason Evans804c9ec2009-06-22 17:44:33 -07004630 jemalloc_message("CPUs: ", umax2s(ncpus, s), "\n", "");
4631 jemalloc_message("Max arenas: ", umax2s(narenas, s), "\n", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004632#ifdef JEMALLOC_BALANCE
Jason Evans804c9ec2009-06-22 17:44:33 -07004633 jemalloc_message("Arena balance threshold: ",
Jason Evans289053c2009-06-22 12:08:42 -07004634 umax2s(opt_balance_threshold, s), "\n", "");
4635#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004636 jemalloc_message("Pointer size: ", umax2s(sizeof(void *), s),
Jason Evans289053c2009-06-22 12:08:42 -07004637 "\n", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004638 jemalloc_message("Quantum size: ", umax2s(QUANTUM, s), "\n",
4639 "");
4640 jemalloc_message("Cacheline size (assumed): ",
4641 umax2s(CACHELINE, s), "\n", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004642#ifdef JEMALLOC_TINY
Jason Evans804c9ec2009-06-22 17:44:33 -07004643 jemalloc_message("Tiny 2^n-spaced sizes: [", umax2s((1U <<
Jason Evans289053c2009-06-22 12:08:42 -07004644 TINY_MIN_2POW), s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004645 jemalloc_message(umax2s((qspace_min >> 1), s), "]\n", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004646#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004647 jemalloc_message("Quantum-spaced sizes: [", umax2s(qspace_min,
Jason Evans289053c2009-06-22 12:08:42 -07004648 s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004649 jemalloc_message(umax2s(qspace_max, s), "]\n", "", "");
4650 jemalloc_message("Cacheline-spaced sizes: [",
4651 umax2s(cspace_min, s), "..", "");
4652 jemalloc_message(umax2s(cspace_max, s), "]\n", "", "");
4653 jemalloc_message("Subpage-spaced sizes: [", umax2s(sspace_min,
Jason Evans289053c2009-06-22 12:08:42 -07004654 s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004655 jemalloc_message(umax2s(sspace_max, s), "]\n", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004656#ifdef JEMALLOC_MAG
Jason Evans804c9ec2009-06-22 17:44:33 -07004657 jemalloc_message("Rounds per magazine: ", umax2s(max_rounds,
4658 s), "\n", "");
Jason Evans289053c2009-06-22 12:08:42 -07004659#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004660 jemalloc_message("Max dirty pages per arena: ",
Jason Evans289053c2009-06-22 12:08:42 -07004661 umax2s(opt_dirty_max, s), "\n", "");
4662
Jason Evans804c9ec2009-06-22 17:44:33 -07004663 jemalloc_message("Chunk size: ", umax2s(chunksize, s), "", "");
4664 jemalloc_message(" (2^", umax2s(opt_chunk_2pow, s), ")\n", "");
Jason Evans289053c2009-06-22 12:08:42 -07004665
Jason Evansb7924f52009-06-23 19:01:18 -07004666#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004667 {
4668 size_t allocated, mapped;
Jason Evansb7924f52009-06-23 19:01:18 -07004669#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004670 uint64_t nbalance = 0;
4671#endif
4672 unsigned i;
4673 arena_t *arena;
4674
4675 /* Calculate and print allocated/mapped stats. */
4676
4677 /* arenas. */
4678 for (i = 0, allocated = 0; i < narenas; i++) {
4679 if (arenas[i] != NULL) {
4680 malloc_spin_lock(&arenas[i]->lock);
4681 allocated +=
4682 arenas[i]->stats.allocated_small;
4683 allocated +=
4684 arenas[i]->stats.allocated_large;
Jason Evansb7924f52009-06-23 19:01:18 -07004685#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004686 nbalance += arenas[i]->stats.nbalance;
4687#endif
4688 malloc_spin_unlock(&arenas[i]->lock);
4689 }
4690 }
4691
4692 /* huge/base. */
4693 malloc_mutex_lock(&huge_mtx);
4694 allocated += huge_allocated;
4695 mapped = stats_chunks.curchunks * chunksize;
4696 malloc_mutex_unlock(&huge_mtx);
4697
4698 malloc_mutex_lock(&base_mtx);
4699 mapped += base_mapped;
4700 malloc_mutex_unlock(&base_mtx);
4701
4702 malloc_printf("Allocated: %zu, mapped: %zu\n",
4703 allocated, mapped);
4704
Jason Evansb7924f52009-06-23 19:01:18 -07004705#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004706 malloc_printf("Arena balance reassignments: %llu\n",
4707 nbalance);
4708#endif
4709
4710 /* Print chunk stats. */
4711 {
4712 chunk_stats_t chunks_stats;
4713
4714 malloc_mutex_lock(&huge_mtx);
4715 chunks_stats = stats_chunks;
4716 malloc_mutex_unlock(&huge_mtx);
4717
4718 malloc_printf("chunks: nchunks "
4719 "highchunks curchunks\n");
4720 malloc_printf(" %13llu%13lu%13lu\n",
4721 chunks_stats.nchunks,
4722 chunks_stats.highchunks,
4723 chunks_stats.curchunks);
4724 }
4725
4726 /* Print chunk stats. */
4727 malloc_printf(
4728 "huge: nmalloc ndalloc allocated\n");
4729 malloc_printf(" %12llu %12llu %12zu\n",
4730 huge_nmalloc, huge_ndalloc, huge_allocated);
4731
4732 /* Print stats for each arena. */
4733 for (i = 0; i < narenas; i++) {
4734 arena = arenas[i];
4735 if (arena != NULL) {
4736 malloc_printf(
4737 "\narenas[%u]:\n", i);
4738 malloc_spin_lock(&arena->lock);
4739 stats_print(arena);
4740 malloc_spin_unlock(&arena->lock);
4741 }
4742 }
4743 }
Jason Evansb7924f52009-06-23 19:01:18 -07004744#endif /* #ifdef JEMALLOC_STATS */
Jason Evans804c9ec2009-06-22 17:44:33 -07004745 jemalloc_message("--- End jemalloc statistics ---\n", "", "",
4746 "");
Jason Evans289053c2009-06-22 12:08:42 -07004747 }
4748}
4749
Jason Evansb7924f52009-06-23 19:01:18 -07004750#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004751static void
4752size2bin_validate(void)
4753{
4754 size_t i, size, binind;
4755
4756 assert(size2bin[0] == 0xffU);
4757 i = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07004758# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004759 /* Tiny. */
4760 for (; i < (1U << TINY_MIN_2POW); i++) {
4761 size = pow2_ceil(1U << TINY_MIN_2POW);
4762 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4763 assert(size2bin[i] == binind);
4764 }
4765 for (; i < qspace_min; i++) {
4766 size = pow2_ceil(i);
4767 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4768 assert(size2bin[i] == binind);
4769 }
4770# endif
4771 /* Quantum-spaced. */
4772 for (; i <= qspace_max; i++) {
4773 size = QUANTUM_CEILING(i);
4774 binind = ntbins + (size >> QUANTUM_2POW) - 1;
4775 assert(size2bin[i] == binind);
4776 }
4777 /* Cacheline-spaced. */
4778 for (; i <= cspace_max; i++) {
4779 size = CACHELINE_CEILING(i);
4780 binind = ntbins + nqbins + ((size - cspace_min) >>
4781 CACHELINE_2POW);
4782 assert(size2bin[i] == binind);
4783 }
4784 /* Sub-page. */
4785 for (; i <= sspace_max; i++) {
4786 size = SUBPAGE_CEILING(i);
4787 binind = ntbins + nqbins + ncbins + ((size - sspace_min)
4788 >> SUBPAGE_2POW);
4789 assert(size2bin[i] == binind);
4790 }
4791}
4792#endif
4793
4794static bool
4795size2bin_init(void)
4796{
4797
4798 if (opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT
4799 || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT)
4800 return (size2bin_init_hard());
4801
4802 size2bin = const_size2bin;
Jason Evansb7924f52009-06-23 19:01:18 -07004803#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004804 assert(sizeof(const_size2bin) == bin_maxclass + 1);
4805 size2bin_validate();
4806#endif
4807 return (false);
4808}
4809
4810static bool
4811size2bin_init_hard(void)
4812{
4813 size_t i, size, binind;
4814 uint8_t *custom_size2bin;
4815
4816 assert(opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT
4817 || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT);
4818
4819 custom_size2bin = (uint8_t *)base_alloc(bin_maxclass + 1);
4820 if (custom_size2bin == NULL)
4821 return (true);
4822
4823 custom_size2bin[0] = 0xffU;
4824 i = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07004825#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004826 /* Tiny. */
4827 for (; i < (1U << TINY_MIN_2POW); i++) {
4828 size = pow2_ceil(1U << TINY_MIN_2POW);
4829 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4830 custom_size2bin[i] = binind;
4831 }
4832 for (; i < qspace_min; i++) {
4833 size = pow2_ceil(i);
4834 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4835 custom_size2bin[i] = binind;
4836 }
4837#endif
4838 /* Quantum-spaced. */
4839 for (; i <= qspace_max; i++) {
4840 size = QUANTUM_CEILING(i);
4841 binind = ntbins + (size >> QUANTUM_2POW) - 1;
4842 custom_size2bin[i] = binind;
4843 }
4844 /* Cacheline-spaced. */
4845 for (; i <= cspace_max; i++) {
4846 size = CACHELINE_CEILING(i);
4847 binind = ntbins + nqbins + ((size - cspace_min) >>
4848 CACHELINE_2POW);
4849 custom_size2bin[i] = binind;
4850 }
4851 /* Sub-page. */
4852 for (; i <= sspace_max; i++) {
4853 size = SUBPAGE_CEILING(i);
4854 binind = ntbins + nqbins + ncbins + ((size - sspace_min) >>
4855 SUBPAGE_2POW);
4856 custom_size2bin[i] = binind;
4857 }
4858
4859 size2bin = custom_size2bin;
Jason Evansb7924f52009-06-23 19:01:18 -07004860#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004861 size2bin_validate();
4862#endif
4863 return (false);
4864}
4865
Jason Evansc9658dd2009-06-22 14:44:08 -07004866static unsigned
4867malloc_ncpus(void)
4868{
4869 unsigned ret;
Jason Evansb7924f52009-06-23 19:01:18 -07004870 long result;
Jason Evansc9658dd2009-06-22 14:44:08 -07004871
Jason Evansb7924f52009-06-23 19:01:18 -07004872 result = sysconf(_SC_NPROCESSORS_ONLN);
4873 if (result == -1) {
4874 /* Error. */
4875 ret = 1;
Jason Evansc9658dd2009-06-22 14:44:08 -07004876 }
Jason Evansb7924f52009-06-23 19:01:18 -07004877 ret = (unsigned)result;
Jason Evansc9658dd2009-06-22 14:44:08 -07004878
4879 return (ret);
4880}
Jason Evansb7924f52009-06-23 19:01:18 -07004881
Jason Evans289053c2009-06-22 12:08:42 -07004882/*
4883 * FreeBSD's pthreads implementation calls malloc(3), so the malloc
4884 * implementation has to take pains to avoid infinite recursion during
4885 * initialization.
4886 */
4887static inline bool
4888malloc_init(void)
4889{
4890
4891 if (malloc_initialized == false)
4892 return (malloc_init_hard());
4893
4894 return (false);
4895}
4896
4897static bool
4898malloc_init_hard(void)
4899{
4900 unsigned i;
4901 int linklen;
4902 char buf[PATH_MAX + 1];
4903 const char *opts;
Jason Evansb7924f52009-06-23 19:01:18 -07004904 arena_t *init_arenas[1];
Jason Evans289053c2009-06-22 12:08:42 -07004905
4906 malloc_mutex_lock(&init_lock);
Jason Evansb7924f52009-06-23 19:01:18 -07004907 if (malloc_initialized || malloc_initializer == pthread_self()) {
Jason Evans289053c2009-06-22 12:08:42 -07004908 /*
4909 * Another thread initialized the allocator before this one
Jason Evansb7924f52009-06-23 19:01:18 -07004910 * acquired init_lock, or this thread is the inializing thread,
4911 * and it is recursively allocating.
Jason Evans289053c2009-06-22 12:08:42 -07004912 */
4913 malloc_mutex_unlock(&init_lock);
4914 return (false);
4915 }
Jason Evansb7924f52009-06-23 19:01:18 -07004916 if (malloc_initializer != (unsigned long)0) {
4917 /* Busy-wait until the initializing thread completes. */
4918 do {
4919 malloc_mutex_unlock(&init_lock);
4920 CPU_SPINWAIT;
4921 malloc_mutex_lock(&init_lock);
4922 } while (malloc_initialized == false);
4923 return (false);
4924 }
Jason Evans289053c2009-06-22 12:08:42 -07004925
Jason Evansb7924f52009-06-23 19:01:18 -07004926#ifdef DYNAMIC_PAGE_SHIFT
Jason Evansc9658dd2009-06-22 14:44:08 -07004927 /* Get page size. */
4928 {
4929 long result;
4930
4931 result = sysconf(_SC_PAGESIZE);
4932 assert(result != -1);
Jason Evansb7924f52009-06-23 19:01:18 -07004933 pagesize = (unsigned)result;
4934
4935 /*
4936 * We assume that pagesize is a power of 2 when calculating
4937 * pagesize_mask and pagesize_2pow.
4938 */
4939 assert(((result - 1) & result) == 0);
4940 pagesize_mask = result - 1;
4941 pagesize_2pow = ffs((int)result) - 1;
Jason Evans289053c2009-06-22 12:08:42 -07004942 }
Jason Evansc9658dd2009-06-22 14:44:08 -07004943#endif
Jason Evans289053c2009-06-22 12:08:42 -07004944
4945 for (i = 0; i < 3; i++) {
4946 unsigned j;
4947
4948 /* Get runtime configuration. */
4949 switch (i) {
4950 case 0:
Jason Evans804c9ec2009-06-22 17:44:33 -07004951 if ((linklen = readlink("/etc/jemalloc.conf", buf,
Jason Evans289053c2009-06-22 12:08:42 -07004952 sizeof(buf) - 1)) != -1) {
4953 /*
Jason Evans804c9ec2009-06-22 17:44:33 -07004954 * Use the contents of the "/etc/jemalloc.conf"
Jason Evans289053c2009-06-22 12:08:42 -07004955 * symbolic link's name.
4956 */
4957 buf[linklen] = '\0';
4958 opts = buf;
4959 } else {
4960 /* No configuration specified. */
4961 buf[0] = '\0';
4962 opts = buf;
4963 }
4964 break;
4965 case 1:
Jason Evansb7924f52009-06-23 19:01:18 -07004966 if ((opts = getenv("JEMALLOC_OPTIONS")) != NULL) {
Jason Evans289053c2009-06-22 12:08:42 -07004967 /*
4968 * Do nothing; opts is already initialized to
Jason Evans804c9ec2009-06-22 17:44:33 -07004969 * the value of the JEMALLOC_OPTIONS
4970 * environment variable.
Jason Evans289053c2009-06-22 12:08:42 -07004971 */
4972 } else {
4973 /* No configuration specified. */
4974 buf[0] = '\0';
4975 opts = buf;
4976 }
4977 break;
4978 case 2:
Jason Evans804c9ec2009-06-22 17:44:33 -07004979 if (jemalloc_options != NULL) {
Jason Evans289053c2009-06-22 12:08:42 -07004980 /*
4981 * Use options that were compiled into the
4982 * program.
4983 */
Jason Evans804c9ec2009-06-22 17:44:33 -07004984 opts = jemalloc_options;
Jason Evans289053c2009-06-22 12:08:42 -07004985 } else {
4986 /* No configuration specified. */
4987 buf[0] = '\0';
4988 opts = buf;
4989 }
4990 break;
4991 default:
4992 /* NOTREACHED */
4993 assert(false);
Jason Evansb7924f52009-06-23 19:01:18 -07004994 buf[0] = '\0';
4995 opts = buf;
Jason Evans289053c2009-06-22 12:08:42 -07004996 }
4997
4998 for (j = 0; opts[j] != '\0'; j++) {
4999 unsigned k, nreps;
5000 bool nseen;
5001
5002 /* Parse repetition count, if any. */
5003 for (nreps = 0, nseen = false;; j++, nseen = true) {
5004 switch (opts[j]) {
5005 case '0': case '1': case '2': case '3':
5006 case '4': case '5': case '6': case '7':
5007 case '8': case '9':
5008 nreps *= 10;
5009 nreps += opts[j] - '0';
5010 break;
5011 default:
5012 goto MALLOC_OUT;
5013 }
5014 }
5015MALLOC_OUT:
5016 if (nseen == false)
5017 nreps = 1;
5018
5019 for (k = 0; k < nreps; k++) {
5020 switch (opts[j]) {
5021 case 'a':
5022 opt_abort = false;
5023 break;
5024 case 'A':
5025 opt_abort = true;
5026 break;
5027 case 'b':
Jason Evansb7924f52009-06-23 19:01:18 -07005028#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005029 opt_balance_threshold >>= 1;
5030#endif
5031 break;
5032 case 'B':
Jason Evansb7924f52009-06-23 19:01:18 -07005033#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005034 if (opt_balance_threshold == 0)
5035 opt_balance_threshold = 1;
5036 else if ((opt_balance_threshold << 1)
5037 > opt_balance_threshold)
5038 opt_balance_threshold <<= 1;
5039#endif
5040 break;
5041 case 'c':
5042 if (opt_cspace_max_2pow - 1 >
5043 opt_qspace_max_2pow &&
5044 opt_cspace_max_2pow >
5045 CACHELINE_2POW)
5046 opt_cspace_max_2pow--;
5047 break;
5048 case 'C':
5049 if (opt_cspace_max_2pow < PAGE_SHIFT
5050 - 1)
5051 opt_cspace_max_2pow++;
5052 break;
5053 case 'd':
Jason Evansb7924f52009-06-23 19:01:18 -07005054#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005055 opt_dss = false;
5056#endif
5057 break;
5058 case 'D':
Jason Evansb7924f52009-06-23 19:01:18 -07005059#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005060 opt_dss = true;
5061#endif
5062 break;
5063 case 'f':
5064 opt_dirty_max >>= 1;
5065 break;
5066 case 'F':
5067 if (opt_dirty_max == 0)
5068 opt_dirty_max = 1;
5069 else if ((opt_dirty_max << 1) != 0)
5070 opt_dirty_max <<= 1;
5071 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005072#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005073 case 'g':
5074 opt_mag = false;
5075 break;
5076 case 'G':
5077 opt_mag = true;
5078 break;
5079#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005080#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07005081 case 'j':
5082 opt_junk = false;
5083 break;
5084 case 'J':
5085 opt_junk = true;
5086 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005087#endif
Jason Evans289053c2009-06-22 12:08:42 -07005088 case 'k':
5089 /*
5090 * Chunks always require at least one
5091 * header page, so chunks can never be
5092 * smaller than two pages.
5093 */
5094 if (opt_chunk_2pow > PAGE_SHIFT + 1)
5095 opt_chunk_2pow--;
5096 break;
5097 case 'K':
5098 if (opt_chunk_2pow + 1 <
5099 (sizeof(size_t) << 3))
5100 opt_chunk_2pow++;
5101 break;
5102 case 'm':
Jason Evansb7924f52009-06-23 19:01:18 -07005103#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005104 opt_mmap = false;
5105#endif
5106 break;
5107 case 'M':
Jason Evansb7924f52009-06-23 19:01:18 -07005108#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005109 opt_mmap = true;
5110#endif
5111 break;
5112 case 'n':
5113 opt_narenas_lshift--;
5114 break;
5115 case 'N':
5116 opt_narenas_lshift++;
5117 break;
5118 case 'p':
5119 opt_print_stats = false;
5120 break;
5121 case 'P':
5122 opt_print_stats = true;
5123 break;
5124 case 'q':
5125 if (opt_qspace_max_2pow > QUANTUM_2POW)
5126 opt_qspace_max_2pow--;
5127 break;
5128 case 'Q':
5129 if (opt_qspace_max_2pow + 1 <
5130 opt_cspace_max_2pow)
5131 opt_qspace_max_2pow++;
5132 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005133#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005134 case 'R':
5135 if (opt_mag_size_2pow + 1 < (8U <<
5136 SIZEOF_PTR_2POW))
5137 opt_mag_size_2pow++;
5138 break;
5139 case 'r':
5140 /*
5141 * Make sure there's always at least
5142 * one round per magazine.
5143 */
5144 if ((1U << (opt_mag_size_2pow-1)) >=
5145 sizeof(mag_t))
5146 opt_mag_size_2pow--;
5147 break;
5148#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005149#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005150 case 'u':
5151 opt_utrace = false;
5152 break;
5153 case 'U':
5154 opt_utrace = true;
5155 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005156#endif
5157#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005158 case 'v':
5159 opt_sysv = false;
5160 break;
5161 case 'V':
5162 opt_sysv = true;
5163 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005164#endif
5165#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005166 case 'x':
5167 opt_xmalloc = false;
5168 break;
5169 case 'X':
5170 opt_xmalloc = true;
5171 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005172#endif
5173#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07005174 case 'z':
5175 opt_zero = false;
5176 break;
5177 case 'Z':
5178 opt_zero = true;
5179 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005180#endif
Jason Evans289053c2009-06-22 12:08:42 -07005181 default: {
5182 char cbuf[2];
5183
5184 cbuf[0] = opts[j];
5185 cbuf[1] = '\0';
Jason Evans804c9ec2009-06-22 17:44:33 -07005186 jemalloc_message("<jemalloc>",
5187 ": Unsupported character "
Jason Evans289053c2009-06-22 12:08:42 -07005188 "in malloc options: '", cbuf,
5189 "'\n");
5190 }
5191 }
5192 }
5193 }
5194 }
5195
Jason Evansb7924f52009-06-23 19:01:18 -07005196#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005197 /* Make sure that there is some method for acquiring memory. */
5198 if (opt_dss == false && opt_mmap == false)
5199 opt_mmap = true;
5200#endif
5201
5202 /* Take care to call atexit() only once. */
5203 if (opt_print_stats) {
5204 /* Print statistics at exit. */
5205 atexit(malloc_print_stats);
5206 }
5207
Jason Evansc9658dd2009-06-22 14:44:08 -07005208 /* Register fork handlers. */
Jason Evans804c9ec2009-06-22 17:44:33 -07005209 pthread_atfork(jemalloc_prefork, jemalloc_postfork, jemalloc_postfork);
Jason Evansc9658dd2009-06-22 14:44:08 -07005210
Jason Evansb7924f52009-06-23 19:01:18 -07005211#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005212 /*
5213 * Calculate the actual number of rounds per magazine, taking into
5214 * account header overhead.
5215 */
5216 max_rounds = (1LLU << (opt_mag_size_2pow - SIZEOF_PTR_2POW)) -
5217 (sizeof(mag_t) >> SIZEOF_PTR_2POW) + 1;
5218#endif
5219
5220 /* Set variables according to the value of opt_[qc]space_max_2pow. */
5221 qspace_max = (1U << opt_qspace_max_2pow);
5222 cspace_min = CACHELINE_CEILING(qspace_max);
5223 if (cspace_min == qspace_max)
5224 cspace_min += CACHELINE;
5225 cspace_max = (1U << opt_cspace_max_2pow);
5226 sspace_min = SUBPAGE_CEILING(cspace_max);
5227 if (sspace_min == cspace_max)
5228 sspace_min += SUBPAGE;
5229 assert(sspace_min < PAGE_SIZE);
5230 sspace_max = PAGE_SIZE - SUBPAGE;
5231
Jason Evansb7924f52009-06-23 19:01:18 -07005232#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07005233 assert(QUANTUM_2POW >= TINY_MIN_2POW);
5234#endif
5235 assert(ntbins <= QUANTUM_2POW);
5236 nqbins = qspace_max >> QUANTUM_2POW;
5237 ncbins = ((cspace_max - cspace_min) >> CACHELINE_2POW) + 1;
5238 nsbins = ((sspace_max - sspace_min) >> SUBPAGE_2POW) + 1;
5239 nbins = ntbins + nqbins + ncbins + nsbins;
5240
5241 if (size2bin_init()) {
5242 malloc_mutex_unlock(&init_lock);
5243 return (true);
5244 }
5245
5246 /* Set variables according to the value of opt_chunk_2pow. */
5247 chunksize = (1LU << opt_chunk_2pow);
5248 chunksize_mask = chunksize - 1;
5249 chunk_npages = (chunksize >> PAGE_SHIFT);
5250 {
5251 size_t header_size;
5252
5253 /*
5254 * Compute the header size such that it is large enough to
5255 * contain the page map.
5256 */
5257 header_size = sizeof(arena_chunk_t) +
5258 (sizeof(arena_chunk_map_t) * (chunk_npages - 1));
5259 arena_chunk_header_npages = (header_size >> PAGE_SHIFT) +
5260 ((header_size & PAGE_MASK) != 0);
5261 }
5262 arena_maxclass = chunksize - (arena_chunk_header_npages <<
5263 PAGE_SHIFT);
5264
5265 UTRACE(0, 0, 0);
5266
Jason Evansb7924f52009-06-23 19:01:18 -07005267#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005268 memset(&stats_chunks, 0, sizeof(chunk_stats_t));
5269#endif
5270
5271 /* Various sanity checks that regard configuration. */
5272 assert(chunksize >= PAGE_SIZE);
5273
5274 /* Initialize chunks data. */
Jason Evansc9658dd2009-06-22 14:44:08 -07005275 if (malloc_mutex_init(&huge_mtx)) {
5276 malloc_mutex_unlock(&init_lock);
5277 return (true);
5278 }
Jason Evans289053c2009-06-22 12:08:42 -07005279 extent_tree_ad_new(&huge);
Jason Evansb7924f52009-06-23 19:01:18 -07005280#ifdef JEMALLOC_DSS
Jason Evansc9658dd2009-06-22 14:44:08 -07005281 if (malloc_mutex_init(&dss_mtx)) {
5282 malloc_mutex_unlock(&init_lock);
5283 return (true);
5284 }
Jason Evans289053c2009-06-22 12:08:42 -07005285 dss_base = sbrk(0);
5286 dss_prev = dss_base;
5287 dss_max = dss_base;
5288 extent_tree_szad_new(&dss_chunks_szad);
5289 extent_tree_ad_new(&dss_chunks_ad);
5290#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005291#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005292 huge_nmalloc = 0;
5293 huge_ndalloc = 0;
5294 huge_allocated = 0;
5295#endif
5296
5297 /* Initialize base allocation data structures. */
Jason Evansb7924f52009-06-23 19:01:18 -07005298#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005299 base_mapped = 0;
5300#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005301#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005302 /*
5303 * Allocate a base chunk here, since it doesn't actually have to be
5304 * chunk-aligned. Doing this before allocating any other chunks allows
5305 * the use of space that would otherwise be wasted.
5306 */
5307 if (opt_dss)
5308 base_pages_alloc(0);
5309#endif
5310 base_nodes = NULL;
Jason Evansc9658dd2009-06-22 14:44:08 -07005311 if (malloc_mutex_init(&base_mtx)) {
5312 malloc_mutex_unlock(&init_lock);
5313 return (true);
5314 }
Jason Evans289053c2009-06-22 12:08:42 -07005315
Jason Evansb7924f52009-06-23 19:01:18 -07005316 /*
5317 * Create enough scaffolding to allow recursive allocation in
5318 * malloc_ncpus().
5319 */
5320 narenas = 1;
5321 arenas = init_arenas;
5322 memset(arenas, 0, sizeof(arena_t *) * narenas);
5323
5324 /*
5325 * Initialize one arena here. The rest are lazily created in
5326 * choose_arena_hard().
5327 */
5328 arenas_extend(0);
5329 if (arenas[0] == NULL) {
5330 malloc_mutex_unlock(&init_lock);
5331 return (true);
5332 }
5333
5334#ifndef NO_TLS
5335 /*
5336 * Assign the initial arena to the initial thread, in order to avoid
5337 * spurious creation of an extra arena if the application switches to
5338 * threaded mode.
5339 */
5340 arenas_map = arenas[0];
5341#endif
5342
5343#ifdef JEMALLOC_MAG
5344 if (pthread_key_create(&mag_rack_tsd, thread_cleanup) != 0) {
5345 jemalloc_message("<jemalloc>",
5346 ": Error in pthread_key_create()\n", "", "");
5347 abort();
5348 }
5349#endif
5350 /*
5351 * Seed here for the initial thread, since choose_arena_hard() is only
5352 * called for other threads. The seed value doesn't really matter.
5353 */
5354#ifdef JEMALLOC_BALANCE
5355 SPRN(balance, 42);
5356#endif
5357
5358 malloc_spin_init(&arenas_lock);
5359
5360 /* Get number of CPUs. */
5361 malloc_initializer = pthread_self();
5362 malloc_mutex_unlock(&init_lock);
5363 ncpus = malloc_ncpus();
5364 malloc_mutex_lock(&init_lock);
5365
Jason Evans289053c2009-06-22 12:08:42 -07005366 if (ncpus > 1) {
5367 /*
5368 * For SMP systems, create twice as many arenas as there are
5369 * CPUs by default.
5370 */
5371 opt_narenas_lshift++;
5372 }
5373
5374 /* Determine how many arenas to use. */
5375 narenas = ncpus;
5376 if (opt_narenas_lshift > 0) {
5377 if ((narenas << opt_narenas_lshift) > narenas)
5378 narenas <<= opt_narenas_lshift;
5379 /*
5380 * Make sure not to exceed the limits of what base_alloc() can
5381 * handle.
5382 */
5383 if (narenas * sizeof(arena_t *) > chunksize)
5384 narenas = chunksize / sizeof(arena_t *);
5385 } else if (opt_narenas_lshift < 0) {
5386 if ((narenas >> -opt_narenas_lshift) < narenas)
5387 narenas >>= -opt_narenas_lshift;
5388 /* Make sure there is at least one arena. */
5389 if (narenas == 0)
5390 narenas = 1;
5391 }
Jason Evansb7924f52009-06-23 19:01:18 -07005392#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005393 assert(narenas != 0);
5394 for (narenas_2pow = 0;
5395 (narenas >> (narenas_2pow + 1)) != 0;
5396 narenas_2pow++);
5397#endif
5398
5399#ifdef NO_TLS
5400 if (narenas > 1) {
5401 static const unsigned primes[] = {1, 3, 5, 7, 11, 13, 17, 19,
5402 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
5403 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
5404 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
5405 223, 227, 229, 233, 239, 241, 251, 257, 263};
5406 unsigned nprimes, parenas;
5407
5408 /*
5409 * Pick a prime number of hash arenas that is more than narenas
5410 * so that direct hashing of pthread_self() pointers tends to
5411 * spread allocations evenly among the arenas.
5412 */
5413 assert((narenas & 1) == 0); /* narenas must be even. */
5414 nprimes = (sizeof(primes) >> SIZEOF_INT_2POW);
5415 parenas = primes[nprimes - 1]; /* In case not enough primes. */
5416 for (i = 1; i < nprimes; i++) {
5417 if (primes[i] > narenas) {
5418 parenas = primes[i];
5419 break;
5420 }
5421 }
5422 narenas = parenas;
5423 }
5424#endif
5425
5426#ifndef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -07005427# ifndef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005428 next_arena = 0;
5429# endif
5430#endif
5431
5432 /* Allocate and initialize arenas. */
5433 arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
5434 if (arenas == NULL) {
5435 malloc_mutex_unlock(&init_lock);
5436 return (true);
5437 }
5438 /*
5439 * Zero the array. In practice, this should always be pre-zeroed,
5440 * since it was just mmap()ed, but let's be sure.
5441 */
5442 memset(arenas, 0, sizeof(arena_t *) * narenas);
Jason Evansb7924f52009-06-23 19:01:18 -07005443 /* Copy the pointer to the one arena that was already initialized. */
5444 arenas[0] = init_arenas[0];
Jason Evans289053c2009-06-22 12:08:42 -07005445
5446 malloc_initialized = true;
5447 malloc_mutex_unlock(&init_lock);
5448 return (false);
5449}
5450
5451/*
5452 * End general internal functions.
5453 */
5454/******************************************************************************/
5455/*
5456 * Begin malloc(3)-compatible functions.
5457 */
5458
5459void *
5460malloc(size_t size)
5461{
5462 void *ret;
5463
5464 if (malloc_init()) {
5465 ret = NULL;
5466 goto RETURN;
5467 }
5468
5469 if (size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005470#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005471 if (opt_sysv == false)
Jason Evansb7924f52009-06-23 19:01:18 -07005472#endif
Jason Evans289053c2009-06-22 12:08:42 -07005473 size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005474#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005475 else {
5476 ret = NULL;
5477 goto RETURN;
5478 }
Jason Evansb7924f52009-06-23 19:01:18 -07005479#endif
Jason Evans289053c2009-06-22 12:08:42 -07005480 }
5481
5482 ret = imalloc(size);
5483
5484RETURN:
5485 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005486#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005487 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005488 jemalloc_message("<jemalloc>",
5489 ": Error in malloc(): out of memory\n", "",
Jason Evans289053c2009-06-22 12:08:42 -07005490 "");
5491 abort();
5492 }
Jason Evansb7924f52009-06-23 19:01:18 -07005493#endif
Jason Evans289053c2009-06-22 12:08:42 -07005494 errno = ENOMEM;
5495 }
5496
5497 UTRACE(0, size, ret);
5498 return (ret);
5499}
5500
5501int
5502posix_memalign(void **memptr, size_t alignment, size_t size)
5503{
5504 int ret;
5505 void *result;
5506
5507 if (malloc_init())
5508 result = NULL;
5509 else {
5510 /* Make sure that alignment is a large enough power of 2. */
5511 if (((alignment - 1) & alignment) != 0
5512 || alignment < sizeof(void *)) {
Jason Evansb7924f52009-06-23 19:01:18 -07005513#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005514 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005515 jemalloc_message("<jemalloc>",
5516 ": Error in posix_memalign(): "
Jason Evans289053c2009-06-22 12:08:42 -07005517 "invalid alignment\n", "", "");
5518 abort();
5519 }
Jason Evansb7924f52009-06-23 19:01:18 -07005520#endif
Jason Evans289053c2009-06-22 12:08:42 -07005521 result = NULL;
5522 ret = EINVAL;
5523 goto RETURN;
5524 }
5525
5526 result = ipalloc(alignment, size);
5527 }
5528
5529 if (result == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005530#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005531 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005532 jemalloc_message("<jemalloc>",
5533 ": Error in posix_memalign(): out of memory\n",
Jason Evans289053c2009-06-22 12:08:42 -07005534 "", "");
5535 abort();
5536 }
Jason Evansb7924f52009-06-23 19:01:18 -07005537#endif
Jason Evans289053c2009-06-22 12:08:42 -07005538 ret = ENOMEM;
5539 goto RETURN;
5540 }
5541
5542 *memptr = result;
5543 ret = 0;
5544
5545RETURN:
5546 UTRACE(0, size, result);
5547 return (ret);
5548}
5549
5550void *
5551calloc(size_t num, size_t size)
5552{
5553 void *ret;
5554 size_t num_size;
5555
5556 if (malloc_init()) {
5557 num_size = 0;
5558 ret = NULL;
5559 goto RETURN;
5560 }
5561
5562 num_size = num * size;
5563 if (num_size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005564#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005565 if ((opt_sysv == false) && ((num == 0) || (size == 0)))
Jason Evansb7924f52009-06-23 19:01:18 -07005566#endif
Jason Evans289053c2009-06-22 12:08:42 -07005567 num_size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005568#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005569 else {
5570 ret = NULL;
5571 goto RETURN;
5572 }
Jason Evansb7924f52009-06-23 19:01:18 -07005573#endif
Jason Evans289053c2009-06-22 12:08:42 -07005574 /*
5575 * Try to avoid division here. We know that it isn't possible to
5576 * overflow during multiplication if neither operand uses any of the
5577 * most significant half of the bits in a size_t.
5578 */
5579 } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2)))
5580 && (num_size / size != num)) {
5581 /* size_t overflow. */
5582 ret = NULL;
5583 goto RETURN;
5584 }
5585
5586 ret = icalloc(num_size);
5587
5588RETURN:
5589 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005590#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005591 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005592 jemalloc_message("<jemalloc>",
5593 ": Error in calloc(): out of memory\n", "",
Jason Evans289053c2009-06-22 12:08:42 -07005594 "");
5595 abort();
5596 }
Jason Evansb7924f52009-06-23 19:01:18 -07005597#endif
Jason Evans289053c2009-06-22 12:08:42 -07005598 errno = ENOMEM;
5599 }
5600
5601 UTRACE(0, num_size, ret);
5602 return (ret);
5603}
5604
5605void *
5606realloc(void *ptr, size_t size)
5607{
5608 void *ret;
5609
5610 if (size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005611#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005612 if (opt_sysv == false)
Jason Evansb7924f52009-06-23 19:01:18 -07005613#endif
Jason Evans289053c2009-06-22 12:08:42 -07005614 size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005615#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005616 else {
5617 if (ptr != NULL)
5618 idalloc(ptr);
5619 ret = NULL;
5620 goto RETURN;
5621 }
Jason Evansb7924f52009-06-23 19:01:18 -07005622#endif
Jason Evans289053c2009-06-22 12:08:42 -07005623 }
5624
5625 if (ptr != NULL) {
5626 assert(malloc_initialized);
5627
5628 ret = iralloc(ptr, size);
5629
5630 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005631#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005632 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005633 jemalloc_message("<jemalloc>",
5634 ": Error in realloc(): out of "
Jason Evans289053c2009-06-22 12:08:42 -07005635 "memory\n", "", "");
5636 abort();
5637 }
Jason Evansb7924f52009-06-23 19:01:18 -07005638#endif
Jason Evans289053c2009-06-22 12:08:42 -07005639 errno = ENOMEM;
5640 }
5641 } else {
5642 if (malloc_init())
5643 ret = NULL;
5644 else
5645 ret = imalloc(size);
5646
5647 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005648#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005649 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005650 jemalloc_message("<jemalloc>",
5651 ": Error in realloc(): out of "
Jason Evans289053c2009-06-22 12:08:42 -07005652 "memory\n", "", "");
5653 abort();
5654 }
Jason Evansb7924f52009-06-23 19:01:18 -07005655#endif
Jason Evans289053c2009-06-22 12:08:42 -07005656 errno = ENOMEM;
5657 }
5658 }
5659
5660RETURN:
5661 UTRACE(ptr, size, ret);
5662 return (ret);
5663}
5664
5665void
5666free(void *ptr)
5667{
5668
5669 UTRACE(ptr, 0, 0);
5670 if (ptr != NULL) {
5671 assert(malloc_initialized);
5672
5673 idalloc(ptr);
5674 }
5675}
5676
5677/*
5678 * End malloc(3)-compatible functions.
5679 */
5680/******************************************************************************/
5681/*
5682 * Begin non-standard functions.
5683 */
5684
5685size_t
5686malloc_usable_size(const void *ptr)
5687{
5688
5689 assert(ptr != NULL);
5690
5691 return (isalloc(ptr));
5692}
5693
5694/*
5695 * End non-standard functions.
5696 */
5697/******************************************************************************/
5698/*
5699 * Begin library-private functions.
5700 */
5701
5702/******************************************************************************/
5703/*
5704 * Begin thread cache.
5705 */
5706
5707/*
5708 * We provide an unpublished interface in order to receive notifications from
5709 * the pthreads library whenever a thread exits. This allows us to clean up
5710 * thread caches.
5711 */
Jason Evansb7924f52009-06-23 19:01:18 -07005712static void
5713thread_cleanup(void *arg)
Jason Evans289053c2009-06-22 12:08:42 -07005714{
5715
Jason Evansb7924f52009-06-23 19:01:18 -07005716#ifdef JEMALLOC_MAG
5717 assert((mag_rack_t *)arg == mag_rack);
Jason Evans289053c2009-06-22 12:08:42 -07005718 if (mag_rack != NULL) {
5719 assert(mag_rack != (void *)-1);
5720 mag_rack_destroy(mag_rack);
Jason Evansb7924f52009-06-23 19:01:18 -07005721#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07005722 mag_rack = (void *)-1;
5723#endif
5724 }
5725#endif
5726}
5727
5728/*
5729 * The following functions are used by threading libraries for protection of
5730 * malloc during fork(). These functions are only called if the program is
5731 * running in threaded mode, so there is no need to check whether the program
5732 * is threaded here.
5733 */
5734
Jason Evanscc00a152009-06-25 18:06:48 -07005735static void
Jason Evans804c9ec2009-06-22 17:44:33 -07005736jemalloc_prefork(void)
Jason Evans289053c2009-06-22 12:08:42 -07005737{
5738 bool again;
5739 unsigned i, j;
5740 arena_t *larenas[narenas], *tarenas[narenas];
5741
5742 /* Acquire all mutexes in a safe order. */
5743
5744 /*
5745 * arenas_lock must be acquired after all of the arena mutexes, in
5746 * order to avoid potential deadlock with arena_lock_balance[_hard]().
5747 * Since arenas_lock protects the arenas array, the following code has
5748 * to race with arenas_extend() callers until it succeeds in locking
5749 * all arenas before locking arenas_lock.
5750 */
5751 memset(larenas, 0, sizeof(arena_t *) * narenas);
5752 do {
5753 again = false;
5754
5755 malloc_spin_lock(&arenas_lock);
5756 for (i = 0; i < narenas; i++) {
5757 if (arenas[i] != larenas[i]) {
5758 memcpy(tarenas, arenas, sizeof(arena_t *) *
5759 narenas);
5760 malloc_spin_unlock(&arenas_lock);
5761 for (j = 0; j < narenas; j++) {
5762 if (larenas[j] != tarenas[j]) {
5763 larenas[j] = tarenas[j];
5764 malloc_spin_lock(
5765 &larenas[j]->lock);
5766 }
5767 }
5768 again = true;
5769 break;
5770 }
5771 }
5772 } while (again);
5773
5774 malloc_mutex_lock(&base_mtx);
5775
5776 malloc_mutex_lock(&huge_mtx);
5777
Jason Evansb7924f52009-06-23 19:01:18 -07005778#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005779 malloc_mutex_lock(&dss_mtx);
5780#endif
5781}
5782
Jason Evanscc00a152009-06-25 18:06:48 -07005783static void
Jason Evans804c9ec2009-06-22 17:44:33 -07005784jemalloc_postfork(void)
Jason Evans289053c2009-06-22 12:08:42 -07005785{
5786 unsigned i;
5787 arena_t *larenas[narenas];
5788
5789 /* Release all mutexes, now that fork() has completed. */
5790
Jason Evansb7924f52009-06-23 19:01:18 -07005791#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005792 malloc_mutex_unlock(&dss_mtx);
5793#endif
5794
5795 malloc_mutex_unlock(&huge_mtx);
5796
5797 malloc_mutex_unlock(&base_mtx);
5798
5799 memcpy(larenas, arenas, sizeof(arena_t *) * narenas);
5800 malloc_spin_unlock(&arenas_lock);
5801 for (i = 0; i < narenas; i++) {
5802 if (larenas[i] != NULL)
5803 malloc_spin_unlock(&larenas[i]->lock);
5804 }
5805}
5806
5807/*
5808 * End library-private functions.
5809 */
5810/******************************************************************************/