blob: 01fb878066de051173bd8a0c062c5b71fd9740eb [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 Evansb8f0a652009-06-29 09:41:43 -07001068#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07001069static bool opt_xmalloc = false;
Jason Evansb8f0a652009-06-29 09:41:43 -07001070#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001071#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001072static bool opt_zero = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001073#endif
Jason Evans289053c2009-06-22 12:08:42 -07001074static int opt_narenas_lshift = 0;
1075
Jason Evansb7924f52009-06-23 19:01:18 -07001076#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001077typedef struct {
1078 void *p;
1079 size_t s;
1080 void *r;
1081} malloc_utrace_t;
1082
1083#define UTRACE(a, b, c) \
1084 if (opt_utrace) { \
1085 malloc_utrace_t ut; \
1086 ut.p = (a); \
1087 ut.s = (b); \
1088 ut.r = (c); \
1089 utrace(&ut, sizeof(ut)); \
1090 }
Jason Evansc9658dd2009-06-22 14:44:08 -07001091#else
1092#define UTRACE(a, b, c)
1093#endif
Jason Evans289053c2009-06-22 12:08:42 -07001094
1095/******************************************************************************/
1096/*
1097 * Begin function prototypes for non-inline static functions.
1098 */
1099
Jason Evansc9658dd2009-06-22 14:44:08 -07001100static bool malloc_mutex_init(malloc_mutex_t *mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001101static bool malloc_spin_init(pthread_mutex_t *lock);
1102static void wrtmessage(const char *p1, const char *p2, const char *p3,
1103 const char *p4);
Jason Evansb7924f52009-06-23 19:01:18 -07001104#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001105static void malloc_printf(const char *format, ...);
1106#endif
1107static char *umax2s(uintmax_t x, char *s);
Jason Evansb7924f52009-06-23 19:01:18 -07001108#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001109static bool base_pages_alloc_dss(size_t minsize);
1110#endif
1111static bool base_pages_alloc_mmap(size_t minsize);
1112static bool base_pages_alloc(size_t minsize);
1113static void *base_alloc(size_t size);
Jason Evans289053c2009-06-22 12:08:42 -07001114static extent_node_t *base_node_alloc(void);
1115static void base_node_dealloc(extent_node_t *node);
Jason Evansb7924f52009-06-23 19:01:18 -07001116#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001117static void stats_print(arena_t *arena);
1118#endif
1119static void *pages_map(void *addr, size_t size);
1120static void pages_unmap(void *addr, size_t size);
Jason Evansb7924f52009-06-23 19:01:18 -07001121#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001122static void *chunk_alloc_dss(size_t size);
1123static void *chunk_recycle_dss(size_t size, bool zero);
1124#endif
1125static void *chunk_alloc_mmap(size_t size);
1126static void *chunk_alloc(size_t size, bool zero);
Jason Evansb7924f52009-06-23 19:01:18 -07001127#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001128static extent_node_t *chunk_dealloc_dss_record(void *chunk, size_t size);
1129static bool chunk_dealloc_dss(void *chunk, size_t size);
1130#endif
1131static void chunk_dealloc_mmap(void *chunk, size_t size);
1132static void chunk_dealloc(void *chunk, size_t size);
1133#ifndef NO_TLS
1134static arena_t *choose_arena_hard(void);
1135#endif
1136static void arena_run_split(arena_t *arena, arena_run_t *run, size_t size,
1137 bool large, bool zero);
1138static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
1139static void arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
1140static arena_run_t *arena_run_alloc(arena_t *arena, size_t size, bool large,
1141 bool zero);
1142static void arena_purge(arena_t *arena);
1143static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty);
1144static void arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk,
1145 arena_run_t *run, size_t oldsize, size_t newsize);
1146static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk,
1147 arena_run_t *run, size_t oldsize, size_t newsize, bool dirty);
1148static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
1149static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
1150static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size);
Jason Evansb7924f52009-06-23 19:01:18 -07001151#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001152static void arena_lock_balance_hard(arena_t *arena);
1153#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001154#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001155static void mag_load(mag_t *mag);
1156#endif
1157static void *arena_malloc_large(arena_t *arena, size_t size, bool zero);
1158static void *arena_palloc(arena_t *arena, size_t alignment, size_t size,
1159 size_t alloc_size);
1160static size_t arena_salloc(const void *ptr);
Jason Evansb7924f52009-06-23 19:01:18 -07001161#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001162static void mag_unload(mag_t *mag);
1163#endif
1164static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk,
1165 void *ptr);
1166static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk,
1167 void *ptr, size_t size, size_t oldsize);
1168static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk,
1169 void *ptr, size_t size, size_t oldsize);
1170static bool arena_ralloc_large(void *ptr, size_t size, size_t oldsize);
1171static void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
1172static bool arena_new(arena_t *arena);
1173static arena_t *arenas_extend(unsigned ind);
Jason Evansb7924f52009-06-23 19:01:18 -07001174#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001175static mag_t *mag_create(arena_t *arena, size_t binind);
1176static void mag_destroy(mag_t *mag);
1177static mag_rack_t *mag_rack_create(arena_t *arena);
1178static void mag_rack_destroy(mag_rack_t *rack);
1179#endif
1180static void *huge_malloc(size_t size, bool zero);
1181static void *huge_palloc(size_t alignment, size_t size);
1182static void *huge_ralloc(void *ptr, size_t size, size_t oldsize);
1183static void huge_dalloc(void *ptr);
1184static void malloc_print_stats(void);
Jason Evansb7924f52009-06-23 19:01:18 -07001185#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07001186static void size2bin_validate(void);
1187#endif
1188static bool size2bin_init(void);
1189static bool size2bin_init_hard(void);
Jason Evansc9658dd2009-06-22 14:44:08 -07001190static unsigned malloc_ncpus(void);
Jason Evans289053c2009-06-22 12:08:42 -07001191static bool malloc_init_hard(void);
Jason Evansb7924f52009-06-23 19:01:18 -07001192static void thread_cleanup(void *arg);
Jason Evanscc00a152009-06-25 18:06:48 -07001193static void jemalloc_prefork(void);
1194static void jemalloc_postfork(void);
Jason Evans289053c2009-06-22 12:08:42 -07001195
1196/*
1197 * End function prototypes.
1198 */
1199/******************************************************************************/
Jason Evans289053c2009-06-22 12:08:42 -07001200
1201static void
Jason Evansc9658dd2009-06-22 14:44:08 -07001202wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
1203{
1204
Jason Evansb7924f52009-06-23 19:01:18 -07001205 if (write(STDERR_FILENO, p1, strlen(p1)) < 0
1206 || write(STDERR_FILENO, p2, strlen(p2)) < 0
1207 || write(STDERR_FILENO, p3, strlen(p3)) < 0
1208 || write(STDERR_FILENO, p4, strlen(p4)) < 0)
1209 return;
Jason Evansc9658dd2009-06-22 14:44:08 -07001210}
1211
Jason Evans804c9ec2009-06-22 17:44:33 -07001212void (*jemalloc_message)(const char *p1, const char *p2, const char *p3,
Jason Evansc9658dd2009-06-22 14:44:08 -07001213 const char *p4) = wrtmessage;
1214
1215/*
1216 * We don't want to depend on vsnprintf() for production builds, since that can
1217 * cause unnecessary bloat for static binaries. umax2s() provides minimal
1218 * integer printing functionality, so that malloc_printf() use can be limited to
Jason Evansb7924f52009-06-23 19:01:18 -07001219 * JEMALLOC_STATS code.
Jason Evansc9658dd2009-06-22 14:44:08 -07001220 */
1221#define UMAX2S_BUFSIZE 21
1222static char *
1223umax2s(uintmax_t x, char *s)
1224{
1225 unsigned i;
1226
1227 i = UMAX2S_BUFSIZE - 1;
1228 s[i] = '\0';
1229 do {
1230 i--;
1231 s[i] = "0123456789"[x % 10];
1232 x /= 10;
1233 } while (x > 0);
1234
1235 return (&s[i]);
1236}
1237
1238/*
1239 * Define a custom assert() in order to reduce the chances of deadlock during
1240 * assertion failure.
1241 */
Jason Evansb7924f52009-06-23 19:01:18 -07001242#ifdef JEMALLOC_DEBUG
Jason Evansc9658dd2009-06-22 14:44:08 -07001243# define assert(e) do { \
1244 if (!(e)) { \
1245 char line_buf[UMAX2S_BUFSIZE]; \
Jason Evanscc00a152009-06-25 18:06:48 -07001246 jemalloc_message("<jemalloc>: ", __FILE__, ":", \
1247 umax2s(__LINE__, line_buf)); \
1248 jemalloc_message(": Failed assertion: ", "\"", #e, \
1249 "\"\n"); \
Jason Evansc9658dd2009-06-22 14:44:08 -07001250 abort(); \
1251 } \
1252} while (0)
1253#else
1254#define assert(e)
1255#endif
1256
Jason Evansb7924f52009-06-23 19:01:18 -07001257#ifdef JEMALLOC_STATS
Jason Evansc9658dd2009-06-22 14:44:08 -07001258static int
1259utrace(const void *addr, size_t len)
1260{
1261 malloc_utrace_t *ut = (malloc_utrace_t *)addr;
1262
1263 assert(len == sizeof(malloc_utrace_t));
1264
1265 if (ut->p == NULL && ut->s == 0 && ut->r == NULL)
Jason Evanscc00a152009-06-25 18:06:48 -07001266 malloc_printf("<jemalloc>:utrace: %d malloc_init()\n",
1267 getpid());
Jason Evansc9658dd2009-06-22 14:44:08 -07001268 else if (ut->p == NULL && ut->r != NULL) {
Jason Evanscc00a152009-06-25 18:06:48 -07001269 malloc_printf("<jemalloc>:utrace: %d %p = malloc(%zu)\n",
1270 getpid(), ut->r, ut->s);
Jason Evansc9658dd2009-06-22 14:44:08 -07001271 } else if (ut->p != NULL && ut->r != NULL) {
Jason Evanscc00a152009-06-25 18:06:48 -07001272 malloc_printf("<jemalloc>:utrace: %d %p = realloc(%p, %zu)\n",
1273 getpid(), ut->r, ut->p, ut->s);
Jason Evansc9658dd2009-06-22 14:44:08 -07001274 } else
Jason Evanscc00a152009-06-25 18:06:48 -07001275 malloc_printf("<jemalloc>:utrace: %d free(%p)\n", getpid(),
1276 ut->p);
Jason Evansc9658dd2009-06-22 14:44:08 -07001277
1278 return (0);
1279}
1280#endif
1281
Jason Evansb7924f52009-06-23 19:01:18 -07001282#ifdef JEMALLOC_STATS
Jason Evansc9658dd2009-06-22 14:44:08 -07001283/*
1284 * Print to stderr in such a way as to (hopefully) avoid memory allocation.
1285 */
1286static void
1287malloc_printf(const char *format, ...)
1288{
1289 char buf[4096];
1290 va_list ap;
1291
1292 va_start(ap, format);
1293 vsnprintf(buf, sizeof(buf), format, ap);
1294 va_end(ap);
Jason Evans804c9ec2009-06-22 17:44:33 -07001295 jemalloc_message(buf, "", "", "");
Jason Evansc9658dd2009-06-22 14:44:08 -07001296}
1297#endif
1298
1299/******************************************************************************/
1300/*
Jason Evansb7924f52009-06-23 19:01:18 -07001301 * Begin pthreads integration. We intercept pthread_create() calls in order
1302 * to toggle isthreaded if the process goes multi-threaded.
1303 */
1304
1305#ifdef JEMALLOC_LAZY_LOCK
1306int (*pthread_create_fptr)(pthread_t *restrict, const pthread_attr_t *,
1307 void *(*)(void *), void *restrict);
1308
1309static void
1310get_pthread_create_fptr(void)
1311{
1312
1313 pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
1314 if (pthread_create_fptr == NULL) {
1315 jemalloc_message("<jemalloc>",
1316 ": Error in dlsym(RTLD_NEXT, \"pthread_create\")\n", "",
1317 "");
1318 abort();
1319 }
1320}
1321
1322int
1323pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,
1324 void *(*start_routine)(void *), void *restrict arg)
1325{
1326 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
1327
1328 pthread_once(&once_control, get_pthread_create_fptr);
1329
1330 isthreaded = true;
1331 return pthread_create_fptr(thread, attr, start_routine, arg);
1332}
1333#endif
1334
1335/******************************************************************************/
1336/*
Jason Evansc9658dd2009-06-22 14:44:08 -07001337 * Begin mutex.
1338 */
1339
1340static bool
Jason Evans289053c2009-06-22 12:08:42 -07001341malloc_mutex_init(malloc_mutex_t *mutex)
1342{
Jason Evansc9658dd2009-06-22 14:44:08 -07001343 pthread_mutexattr_t attr;
Jason Evans289053c2009-06-22 12:08:42 -07001344
Jason Evansc9658dd2009-06-22 14:44:08 -07001345 if (pthread_mutexattr_init(&attr) != 0)
1346 return (true);
1347 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1348 if (pthread_mutex_init(mutex, &attr) != 0) {
1349 pthread_mutexattr_destroy(&attr);
1350 return (true);
1351 }
1352 pthread_mutexattr_destroy(&attr);
1353
1354 return (false);
Jason Evans289053c2009-06-22 12:08:42 -07001355}
1356
1357static inline void
1358malloc_mutex_lock(malloc_mutex_t *mutex)
1359{
1360
Jason Evansb7924f52009-06-23 19:01:18 -07001361 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001362 pthread_mutex_lock(mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001363}
1364
1365static inline void
1366malloc_mutex_unlock(malloc_mutex_t *mutex)
1367{
1368
Jason Evansb7924f52009-06-23 19:01:18 -07001369 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001370 pthread_mutex_unlock(mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001371}
1372
1373/*
1374 * End mutex.
1375 */
1376/******************************************************************************/
1377/*
1378 * Begin spin lock. Spin locks here are actually adaptive mutexes that block
1379 * after a period of spinning, because unbounded spinning would allow for
1380 * priority inversion.
1381 */
1382
Jason Evans289053c2009-06-22 12:08:42 -07001383static bool
1384malloc_spin_init(pthread_mutex_t *lock)
1385{
1386
Jason Evansc9658dd2009-06-22 14:44:08 -07001387 if (pthread_mutex_init(lock, NULL) != 0)
Jason Evans289053c2009-06-22 12:08:42 -07001388 return (true);
1389
1390 return (false);
1391}
1392
1393static inline unsigned
1394malloc_spin_lock(pthread_mutex_t *lock)
1395{
1396 unsigned ret = 0;
1397
Jason Evansb7924f52009-06-23 19:01:18 -07001398 if (isthreaded) {
Jason Evansc9658dd2009-06-22 14:44:08 -07001399 if (pthread_mutex_trylock(lock) != 0) {
Jason Evans289053c2009-06-22 12:08:42 -07001400 /* Exponentially back off if there are multiple CPUs. */
1401 if (ncpus > 1) {
1402 unsigned i;
1403 volatile unsigned j;
1404
1405 for (i = 1; i <= SPIN_LIMIT_2POW; i++) {
1406 for (j = 0; j < (1U << i); j++) {
1407 ret++;
1408 CPU_SPINWAIT;
1409 }
1410
Jason Evansc9658dd2009-06-22 14:44:08 -07001411 if (pthread_mutex_trylock(lock) == 0)
Jason Evans289053c2009-06-22 12:08:42 -07001412 return (ret);
1413 }
1414 }
1415
1416 /*
1417 * Spinning failed. Block until the lock becomes
1418 * available, in order to avoid indefinite priority
1419 * inversion.
1420 */
Jason Evansc9658dd2009-06-22 14:44:08 -07001421 pthread_mutex_lock(lock);
Jason Evans289053c2009-06-22 12:08:42 -07001422 assert((ret << BLOCK_COST_2POW) != 0 || ncpus == 1);
1423 return (ret << BLOCK_COST_2POW);
1424 }
1425 }
1426
1427 return (ret);
1428}
1429
1430static inline void
1431malloc_spin_unlock(pthread_mutex_t *lock)
1432{
1433
Jason Evansb7924f52009-06-23 19:01:18 -07001434 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001435 pthread_mutex_unlock(lock);
Jason Evans289053c2009-06-22 12:08:42 -07001436}
1437
1438/*
1439 * End spin lock.
1440 */
1441/******************************************************************************/
1442/*
1443 * Begin Utility functions/macros.
1444 */
1445
1446/* Return the chunk address for allocation address a. */
1447#define CHUNK_ADDR2BASE(a) \
1448 ((void *)((uintptr_t)(a) & ~chunksize_mask))
1449
1450/* Return the chunk offset of address a. */
1451#define CHUNK_ADDR2OFFSET(a) \
1452 ((size_t)((uintptr_t)(a) & chunksize_mask))
1453
1454/* Return the smallest chunk multiple that is >= s. */
1455#define CHUNK_CEILING(s) \
1456 (((s) + chunksize_mask) & ~chunksize_mask)
1457
1458/* Return the smallest quantum multiple that is >= a. */
1459#define QUANTUM_CEILING(a) \
1460 (((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
1461
1462/* Return the smallest cacheline multiple that is >= s. */
1463#define CACHELINE_CEILING(s) \
1464 (((s) + CACHELINE_MASK) & ~CACHELINE_MASK)
1465
1466/* Return the smallest subpage multiple that is >= s. */
1467#define SUBPAGE_CEILING(s) \
1468 (((s) + SUBPAGE_MASK) & ~SUBPAGE_MASK)
1469
Jason Evansc9658dd2009-06-22 14:44:08 -07001470/* Return the smallest pagesize multiple that is >= s. */
Jason Evans289053c2009-06-22 12:08:42 -07001471#define PAGE_CEILING(s) \
Jason Evansb7924f52009-06-23 19:01:18 -07001472 (((s) + PAGE_MASK) & ~PAGE_MASK)
Jason Evans289053c2009-06-22 12:08:42 -07001473
Jason Evansb7924f52009-06-23 19:01:18 -07001474#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07001475/* Compute the smallest power of 2 that is >= x. */
1476static inline size_t
1477pow2_ceil(size_t x)
1478{
1479
1480 x--;
1481 x |= x >> 1;
1482 x |= x >> 2;
1483 x |= x >> 4;
1484 x |= x >> 8;
1485 x |= x >> 16;
1486#if (SIZEOF_PTR == 8)
1487 x |= x >> 32;
1488#endif
1489 x++;
1490 return (x);
1491}
1492#endif
1493
Jason Evansb7924f52009-06-23 19:01:18 -07001494#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001495/*
1496 * Use a simple linear congruential pseudo-random number generator:
1497 *
1498 * prn(y) = (a*x + c) % m
1499 *
1500 * where the following constants ensure maximal period:
1501 *
1502 * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4.
1503 * c == Odd number (relatively prime to 2^n).
1504 * m == 2^32
1505 *
1506 * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints.
1507 *
1508 * This choice of m has the disadvantage that the quality of the bits is
1509 * proportional to bit position. For example. the lowest bit has a cycle of 2,
1510 * the next has a cycle of 4, etc. For this reason, we prefer to use the upper
1511 * bits.
1512 */
1513# define PRN_DEFINE(suffix, var, a, c) \
1514static inline void \
1515sprn_##suffix(uint32_t seed) \
1516{ \
1517 var = seed; \
1518} \
1519 \
1520static inline uint32_t \
1521prn_##suffix(uint32_t lg_range) \
1522{ \
1523 uint32_t ret, x; \
1524 \
1525 assert(lg_range > 0); \
1526 assert(lg_range <= 32); \
1527 \
1528 x = (var * (a)) + (c); \
1529 var = x; \
1530 ret = x >> (32 - lg_range); \
1531 \
1532 return (ret); \
1533}
1534# define SPRN(suffix, seed) sprn_##suffix(seed)
1535# define PRN(suffix, lg_range) prn_##suffix(lg_range)
1536#endif
1537
Jason Evansb7924f52009-06-23 19:01:18 -07001538#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001539/* Define the PRNG used for arena assignment. */
1540static __thread uint32_t balance_x;
1541PRN_DEFINE(balance, balance_x, 1297, 1301)
1542#endif
1543
Jason Evans289053c2009-06-22 12:08:42 -07001544/******************************************************************************/
1545
Jason Evansb7924f52009-06-23 19:01:18 -07001546#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001547static bool
1548base_pages_alloc_dss(size_t minsize)
1549{
1550
1551 /*
1552 * Do special DSS allocation here, since base allocations don't need to
1553 * be chunk-aligned.
1554 */
1555 malloc_mutex_lock(&dss_mtx);
1556 if (dss_prev != (void *)-1) {
1557 intptr_t incr;
1558 size_t csize = CHUNK_CEILING(minsize);
1559
1560 do {
1561 /* Get the current end of the DSS. */
1562 dss_max = sbrk(0);
1563
1564 /*
1565 * Calculate how much padding is necessary to
1566 * chunk-align the end of the DSS. Don't worry about
1567 * dss_max not being chunk-aligned though.
1568 */
1569 incr = (intptr_t)chunksize
1570 - (intptr_t)CHUNK_ADDR2OFFSET(dss_max);
1571 assert(incr >= 0);
1572 if ((size_t)incr < minsize)
1573 incr += csize;
1574
1575 dss_prev = sbrk(incr);
1576 if (dss_prev == dss_max) {
1577 /* Success. */
1578 dss_max = (void *)((intptr_t)dss_prev + incr);
1579 base_pages = dss_prev;
1580 base_next_addr = base_pages;
1581 base_past_addr = dss_max;
Jason Evansb7924f52009-06-23 19:01:18 -07001582#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001583 base_mapped += incr;
1584#endif
1585 malloc_mutex_unlock(&dss_mtx);
1586 return (false);
1587 }
1588 } while (dss_prev != (void *)-1);
1589 }
1590 malloc_mutex_unlock(&dss_mtx);
1591
1592 return (true);
1593}
1594#endif
1595
1596static bool
1597base_pages_alloc_mmap(size_t minsize)
1598{
1599 size_t csize;
1600
1601 assert(minsize != 0);
1602 csize = PAGE_CEILING(minsize);
1603 base_pages = pages_map(NULL, csize);
1604 if (base_pages == NULL)
1605 return (true);
1606 base_next_addr = base_pages;
1607 base_past_addr = (void *)((uintptr_t)base_pages + csize);
Jason Evansb7924f52009-06-23 19:01:18 -07001608#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001609 base_mapped += csize;
1610#endif
1611
1612 return (false);
1613}
1614
1615static bool
1616base_pages_alloc(size_t minsize)
1617{
1618
Jason Evansb7924f52009-06-23 19:01:18 -07001619#ifdef JEMALLOC_DSS
Jason Evansc9658dd2009-06-22 14:44:08 -07001620 if (opt_dss) {
1621 if (base_pages_alloc_dss(minsize) == false)
1622 return (false);
1623 }
1624
Jason Evans289053c2009-06-22 12:08:42 -07001625 if (opt_mmap && minsize != 0)
1626#endif
1627 {
1628 if (base_pages_alloc_mmap(minsize) == false)
1629 return (false);
1630 }
1631
Jason Evans289053c2009-06-22 12:08:42 -07001632 return (true);
1633}
1634
1635static void *
1636base_alloc(size_t size)
1637{
1638 void *ret;
1639 size_t csize;
1640
1641 /* Round size up to nearest multiple of the cacheline size. */
1642 csize = CACHELINE_CEILING(size);
1643
1644 malloc_mutex_lock(&base_mtx);
1645 /* Make sure there's enough space for the allocation. */
1646 if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
1647 if (base_pages_alloc(csize)) {
1648 malloc_mutex_unlock(&base_mtx);
1649 return (NULL);
1650 }
1651 }
1652 /* Allocate. */
1653 ret = base_next_addr;
1654 base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
1655 malloc_mutex_unlock(&base_mtx);
1656
1657 return (ret);
1658}
1659
Jason Evans289053c2009-06-22 12:08:42 -07001660static extent_node_t *
1661base_node_alloc(void)
1662{
1663 extent_node_t *ret;
1664
1665 malloc_mutex_lock(&base_mtx);
1666 if (base_nodes != NULL) {
1667 ret = base_nodes;
1668 base_nodes = *(extent_node_t **)ret;
1669 malloc_mutex_unlock(&base_mtx);
1670 } else {
1671 malloc_mutex_unlock(&base_mtx);
1672 ret = (extent_node_t *)base_alloc(sizeof(extent_node_t));
1673 }
1674
1675 return (ret);
1676}
1677
1678static void
1679base_node_dealloc(extent_node_t *node)
1680{
1681
1682 malloc_mutex_lock(&base_mtx);
1683 *(extent_node_t **)node = base_nodes;
1684 base_nodes = node;
1685 malloc_mutex_unlock(&base_mtx);
1686}
1687
1688/******************************************************************************/
1689
Jason Evansb7924f52009-06-23 19:01:18 -07001690#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001691static void
1692stats_print(arena_t *arena)
1693{
1694 unsigned i, gap_start;
1695
1696 malloc_printf("dirty: %zu page%s dirty, %llu sweep%s,"
1697 " %llu madvise%s, %llu page%s purged\n",
1698 arena->ndirty, arena->ndirty == 1 ? "" : "s",
1699 arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s",
1700 arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s",
1701 arena->stats.purged, arena->stats.purged == 1 ? "" : "s");
1702
1703 malloc_printf(" allocated nmalloc ndalloc\n");
1704 malloc_printf("small: %12zu %12llu %12llu\n",
1705 arena->stats.allocated_small, arena->stats.nmalloc_small,
1706 arena->stats.ndalloc_small);
1707 malloc_printf("large: %12zu %12llu %12llu\n",
1708 arena->stats.allocated_large, arena->stats.nmalloc_large,
1709 arena->stats.ndalloc_large);
1710 malloc_printf("total: %12zu %12llu %12llu\n",
1711 arena->stats.allocated_small + arena->stats.allocated_large,
1712 arena->stats.nmalloc_small + arena->stats.nmalloc_large,
1713 arena->stats.ndalloc_small + arena->stats.ndalloc_large);
1714 malloc_printf("mapped: %12zu\n", arena->stats.mapped);
1715
Jason Evansb7924f52009-06-23 19:01:18 -07001716#ifdef JEMALLOC_MAG
1717 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07001718 malloc_printf("bins: bin size regs pgs mags "
1719 "newruns reruns maxruns curruns\n");
1720 } else {
1721#endif
1722 malloc_printf("bins: bin size regs pgs requests "
1723 "newruns reruns maxruns curruns\n");
Jason Evansb7924f52009-06-23 19:01:18 -07001724#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001725 }
1726#endif
1727 for (i = 0, gap_start = UINT_MAX; i < nbins; i++) {
1728 if (arena->bins[i].stats.nruns == 0) {
1729 if (gap_start == UINT_MAX)
1730 gap_start = i;
1731 } else {
1732 if (gap_start != UINT_MAX) {
1733 if (i > gap_start + 1) {
1734 /* Gap of more than one size class. */
1735 malloc_printf("[%u..%u]\n",
1736 gap_start, i - 1);
1737 } else {
1738 /* Gap of one size class. */
1739 malloc_printf("[%u]\n", gap_start);
1740 }
1741 gap_start = UINT_MAX;
1742 }
1743 malloc_printf(
1744 "%13u %1s %4u %4u %3u %9llu %9llu"
1745 " %9llu %7lu %7lu\n",
1746 i,
1747 i < ntbins ? "T" : i < ntbins + nqbins ? "Q" :
1748 i < ntbins + nqbins + ncbins ? "C" : "S",
1749 arena->bins[i].reg_size,
1750 arena->bins[i].nregs,
1751 arena->bins[i].run_size >> PAGE_SHIFT,
Jason Evansb7924f52009-06-23 19:01:18 -07001752#ifdef JEMALLOC_MAG
1753 (opt_mag) ? arena->bins[i].stats.nmags :
Jason Evans289053c2009-06-22 12:08:42 -07001754#endif
1755 arena->bins[i].stats.nrequests,
1756 arena->bins[i].stats.nruns,
1757 arena->bins[i].stats.reruns,
1758 arena->bins[i].stats.highruns,
1759 arena->bins[i].stats.curruns);
1760 }
1761 }
1762 if (gap_start != UINT_MAX) {
1763 if (i > gap_start + 1) {
1764 /* Gap of more than one size class. */
1765 malloc_printf("[%u..%u]\n", gap_start, i - 1);
1766 } else {
1767 /* Gap of one size class. */
1768 malloc_printf("[%u]\n", gap_start);
1769 }
1770 }
1771}
1772#endif
1773
1774/*
1775 * End Utility functions/macros.
1776 */
1777/******************************************************************************/
1778/*
1779 * Begin extent tree code.
1780 */
1781
Jason Evansb7924f52009-06-23 19:01:18 -07001782#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001783static inline int
1784extent_szad_comp(extent_node_t *a, extent_node_t *b)
1785{
1786 int ret;
1787 size_t a_size = a->size;
1788 size_t b_size = b->size;
1789
1790 ret = (a_size > b_size) - (a_size < b_size);
1791 if (ret == 0) {
1792 uintptr_t a_addr = (uintptr_t)a->addr;
1793 uintptr_t b_addr = (uintptr_t)b->addr;
1794
1795 ret = (a_addr > b_addr) - (a_addr < b_addr);
1796 }
1797
1798 return (ret);
1799}
1800
1801/* Wrap red-black tree macros in functions. */
Jason Evansb8f0a652009-06-29 09:41:43 -07001802rb_wrap(static __attribute__((unused)), extent_tree_szad_, extent_tree_t, extent_node_t,
Jason Evans289053c2009-06-22 12:08:42 -07001803 link_szad, extent_szad_comp)
1804#endif
1805
1806static inline int
1807extent_ad_comp(extent_node_t *a, extent_node_t *b)
1808{
1809 uintptr_t a_addr = (uintptr_t)a->addr;
1810 uintptr_t b_addr = (uintptr_t)b->addr;
1811
1812 return ((a_addr > b_addr) - (a_addr < b_addr));
1813}
1814
1815/* Wrap red-black tree macros in functions. */
Jason Evansb8f0a652009-06-29 09:41:43 -07001816rb_wrap(static __attribute__((unused)), extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
Jason Evans289053c2009-06-22 12:08:42 -07001817 extent_ad_comp)
1818
1819/*
1820 * End extent tree code.
1821 */
1822/******************************************************************************/
1823/*
1824 * Begin chunk management functions.
1825 */
1826
1827static void *
1828pages_map(void *addr, size_t size)
1829{
1830 void *ret;
1831
1832 /*
1833 * We don't use MAP_FIXED here, because it can cause the *replacement*
1834 * of existing mappings, and we only want to create new mappings.
1835 */
1836 ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
1837 -1, 0);
1838 assert(ret != NULL);
1839
1840 if (ret == MAP_FAILED)
1841 ret = NULL;
1842 else if (addr != NULL && ret != addr) {
1843 /*
1844 * We succeeded in mapping memory, but not in the right place.
1845 */
1846 if (munmap(ret, size) == -1) {
1847 char buf[STRERROR_BUF];
1848
1849 strerror_r(errno, buf, sizeof(buf));
Jason Evans804c9ec2009-06-22 17:44:33 -07001850 jemalloc_message("<jemalloc>",
1851 ": Error in munmap(): ", buf, "\n");
Jason Evans289053c2009-06-22 12:08:42 -07001852 if (opt_abort)
1853 abort();
1854 }
1855 ret = NULL;
1856 }
1857
1858 assert(ret == NULL || (addr == NULL && ret != addr)
1859 || (addr != NULL && ret == addr));
1860 return (ret);
1861}
1862
1863static void
1864pages_unmap(void *addr, size_t size)
1865{
1866
1867 if (munmap(addr, size) == -1) {
1868 char buf[STRERROR_BUF];
1869
1870 strerror_r(errno, buf, sizeof(buf));
Jason Evans804c9ec2009-06-22 17:44:33 -07001871 jemalloc_message("<jemalloc>",
1872 ": Error in munmap(): ", buf, "\n");
Jason Evans289053c2009-06-22 12:08:42 -07001873 if (opt_abort)
1874 abort();
1875 }
1876}
1877
Jason Evansb7924f52009-06-23 19:01:18 -07001878#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001879static void *
1880chunk_alloc_dss(size_t size)
1881{
1882
1883 /*
1884 * sbrk() uses a signed increment argument, so take care not to
1885 * interpret a huge allocation request as a negative increment.
1886 */
1887 if ((intptr_t)size < 0)
1888 return (NULL);
1889
1890 malloc_mutex_lock(&dss_mtx);
1891 if (dss_prev != (void *)-1) {
1892 intptr_t incr;
1893
1894 /*
1895 * The loop is necessary to recover from races with other
1896 * threads that are using the DSS for something other than
1897 * malloc.
1898 */
1899 do {
1900 void *ret;
1901
1902 /* Get the current end of the DSS. */
1903 dss_max = sbrk(0);
1904
1905 /*
1906 * Calculate how much padding is necessary to
1907 * chunk-align the end of the DSS.
1908 */
1909 incr = (intptr_t)size
1910 - (intptr_t)CHUNK_ADDR2OFFSET(dss_max);
1911 if (incr == (intptr_t)size)
1912 ret = dss_max;
1913 else {
1914 ret = (void *)((intptr_t)dss_max + incr);
1915 incr += size;
1916 }
1917
1918 dss_prev = sbrk(incr);
1919 if (dss_prev == dss_max) {
1920 /* Success. */
1921 dss_max = (void *)((intptr_t)dss_prev + incr);
1922 malloc_mutex_unlock(&dss_mtx);
1923 return (ret);
1924 }
1925 } while (dss_prev != (void *)-1);
1926 }
1927 malloc_mutex_unlock(&dss_mtx);
1928
1929 return (NULL);
1930}
1931
1932static void *
1933chunk_recycle_dss(size_t size, bool zero)
1934{
1935 extent_node_t *node, key;
1936
1937 key.addr = NULL;
1938 key.size = size;
1939 malloc_mutex_lock(&dss_mtx);
1940 node = extent_tree_szad_nsearch(&dss_chunks_szad, &key);
1941 if (node != NULL) {
1942 void *ret = node->addr;
1943
1944 /* Remove node from the tree. */
1945 extent_tree_szad_remove(&dss_chunks_szad, node);
1946 if (node->size == size) {
1947 extent_tree_ad_remove(&dss_chunks_ad, node);
1948 base_node_dealloc(node);
1949 } else {
1950 /*
1951 * Insert the remainder of node's address range as a
1952 * smaller chunk. Its position within dss_chunks_ad
1953 * does not change.
1954 */
1955 assert(node->size > size);
1956 node->addr = (void *)((uintptr_t)node->addr + size);
1957 node->size -= size;
1958 extent_tree_szad_insert(&dss_chunks_szad, node);
1959 }
1960 malloc_mutex_unlock(&dss_mtx);
1961
1962 if (zero)
1963 memset(ret, 0, size);
1964 return (ret);
1965 }
1966 malloc_mutex_unlock(&dss_mtx);
1967
1968 return (NULL);
1969}
1970#endif
1971
1972static void *
1973chunk_alloc_mmap(size_t size)
1974{
1975 void *ret;
1976 size_t offset;
1977
1978 /*
1979 * Ideally, there would be a way to specify alignment to mmap() (like
1980 * NetBSD has), but in the absence of such a feature, we have to work
1981 * hard to efficiently create aligned mappings. The reliable, but
1982 * expensive method is to create a mapping that is over-sized, then
1983 * trim the excess. However, that always results in at least one call
1984 * to pages_unmap().
1985 *
1986 * A more optimistic approach is to try mapping precisely the right
1987 * amount, then try to append another mapping if alignment is off. In
1988 * practice, this works out well as long as the application is not
1989 * interleaving mappings via direct mmap() calls. If we do run into a
1990 * situation where there is an interleaved mapping and we are unable to
1991 * extend an unaligned mapping, our best option is to momentarily
1992 * revert to the reliable-but-expensive method. This will tend to
1993 * leave a gap in the memory map that is too small to cause later
1994 * problems for the optimistic method.
1995 */
1996
1997 ret = pages_map(NULL, size);
1998 if (ret == NULL)
1999 return (NULL);
2000
2001 offset = CHUNK_ADDR2OFFSET(ret);
2002 if (offset != 0) {
2003 /* Try to extend chunk boundary. */
2004 if (pages_map((void *)((uintptr_t)ret + size),
2005 chunksize - offset) == NULL) {
2006 /*
2007 * Extension failed. Clean up, then revert to the
2008 * reliable-but-expensive method.
2009 */
2010 pages_unmap(ret, size);
2011
2012 /* Beware size_t wrap-around. */
2013 if (size + chunksize <= size)
2014 return NULL;
2015
2016 ret = pages_map(NULL, size + chunksize);
2017 if (ret == NULL)
2018 return (NULL);
2019
2020 /* Clean up unneeded leading/trailing space. */
2021 offset = CHUNK_ADDR2OFFSET(ret);
2022 if (offset != 0) {
2023 /* Leading space. */
2024 pages_unmap(ret, chunksize - offset);
2025
2026 ret = (void *)((uintptr_t)ret +
2027 (chunksize - offset));
2028
2029 /* Trailing space. */
2030 pages_unmap((void *)((uintptr_t)ret + size),
2031 offset);
2032 } else {
2033 /* Trailing space only. */
2034 pages_unmap((void *)((uintptr_t)ret + size),
2035 chunksize);
2036 }
2037 } else {
2038 /* Clean up unneeded leading space. */
2039 pages_unmap(ret, chunksize - offset);
2040 ret = (void *)((uintptr_t)ret + (chunksize - offset));
2041 }
2042 }
2043
2044 return (ret);
2045}
2046
2047static void *
2048chunk_alloc(size_t size, bool zero)
2049{
2050 void *ret;
2051
2052 assert(size != 0);
2053 assert((size & chunksize_mask) == 0);
2054
Jason Evansb7924f52009-06-23 19:01:18 -07002055#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002056 if (opt_dss) {
2057 ret = chunk_recycle_dss(size, zero);
2058 if (ret != NULL) {
2059 goto RETURN;
2060 }
2061
2062 ret = chunk_alloc_dss(size);
2063 if (ret != NULL)
2064 goto RETURN;
2065 }
Jason Evansc9658dd2009-06-22 14:44:08 -07002066
2067 if (opt_mmap)
Jason Evans289053c2009-06-22 12:08:42 -07002068#endif
Jason Evansc9658dd2009-06-22 14:44:08 -07002069 {
2070 ret = chunk_alloc_mmap(size);
2071 if (ret != NULL)
2072 goto RETURN;
2073 }
Jason Evans289053c2009-06-22 12:08:42 -07002074
2075 /* All strategies for allocation failed. */
2076 ret = NULL;
2077RETURN:
Jason Evansb7924f52009-06-23 19:01:18 -07002078#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002079 if (ret != NULL) {
2080 stats_chunks.nchunks += (size / chunksize);
2081 stats_chunks.curchunks += (size / chunksize);
2082 }
2083 if (stats_chunks.curchunks > stats_chunks.highchunks)
2084 stats_chunks.highchunks = stats_chunks.curchunks;
2085#endif
2086
2087 assert(CHUNK_ADDR2BASE(ret) == ret);
2088 return (ret);
2089}
2090
Jason Evansb7924f52009-06-23 19:01:18 -07002091#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002092static extent_node_t *
2093chunk_dealloc_dss_record(void *chunk, size_t size)
2094{
2095 extent_node_t *node, *prev, key;
2096
2097 key.addr = (void *)((uintptr_t)chunk + size);
2098 node = extent_tree_ad_nsearch(&dss_chunks_ad, &key);
2099 /* Try to coalesce forward. */
2100 if (node != NULL && node->addr == key.addr) {
2101 /*
2102 * Coalesce chunk with the following address range. This does
2103 * not change the position within dss_chunks_ad, so only
2104 * remove/insert from/into dss_chunks_szad.
2105 */
2106 extent_tree_szad_remove(&dss_chunks_szad, node);
2107 node->addr = chunk;
2108 node->size += size;
2109 extent_tree_szad_insert(&dss_chunks_szad, node);
2110 } else {
2111 /*
2112 * Coalescing forward failed, so insert a new node. Drop
2113 * dss_mtx during node allocation, since it is possible that a
2114 * new base chunk will be allocated.
2115 */
2116 malloc_mutex_unlock(&dss_mtx);
2117 node = base_node_alloc();
2118 malloc_mutex_lock(&dss_mtx);
2119 if (node == NULL)
2120 return (NULL);
2121 node->addr = chunk;
2122 node->size = size;
2123 extent_tree_ad_insert(&dss_chunks_ad, node);
2124 extent_tree_szad_insert(&dss_chunks_szad, node);
2125 }
2126
2127 /* Try to coalesce backward. */
2128 prev = extent_tree_ad_prev(&dss_chunks_ad, node);
2129 if (prev != NULL && (void *)((uintptr_t)prev->addr + prev->size) ==
2130 chunk) {
2131 /*
2132 * Coalesce chunk with the previous address range. This does
2133 * not change the position within dss_chunks_ad, so only
2134 * remove/insert node from/into dss_chunks_szad.
2135 */
2136 extent_tree_szad_remove(&dss_chunks_szad, prev);
2137 extent_tree_ad_remove(&dss_chunks_ad, prev);
2138
2139 extent_tree_szad_remove(&dss_chunks_szad, node);
2140 node->addr = prev->addr;
2141 node->size += prev->size;
2142 extent_tree_szad_insert(&dss_chunks_szad, node);
2143
2144 base_node_dealloc(prev);
2145 }
2146
2147 return (node);
2148}
2149
2150static bool
2151chunk_dealloc_dss(void *chunk, size_t size)
2152{
2153
2154 malloc_mutex_lock(&dss_mtx);
2155 if ((uintptr_t)chunk >= (uintptr_t)dss_base
2156 && (uintptr_t)chunk < (uintptr_t)dss_max) {
2157 extent_node_t *node;
2158
2159 /* Try to coalesce with other unused chunks. */
2160 node = chunk_dealloc_dss_record(chunk, size);
2161 if (node != NULL) {
2162 chunk = node->addr;
2163 size = node->size;
2164 }
2165
2166 /* Get the current end of the DSS. */
2167 dss_max = sbrk(0);
2168
2169 /*
2170 * Try to shrink the DSS if this chunk is at the end of the
2171 * DSS. The sbrk() call here is subject to a race condition
2172 * with threads that use brk(2) or sbrk(2) directly, but the
2173 * alternative would be to leak memory for the sake of poorly
2174 * designed multi-threaded programs.
2175 */
2176 if ((void *)((uintptr_t)chunk + size) == dss_max
2177 && (dss_prev = sbrk(-(intptr_t)size)) == dss_max) {
2178 /* Success. */
2179 dss_max = (void *)((intptr_t)dss_prev - (intptr_t)size);
2180
2181 if (node != NULL) {
2182 extent_tree_szad_remove(&dss_chunks_szad, node);
2183 extent_tree_ad_remove(&dss_chunks_ad, node);
2184 base_node_dealloc(node);
2185 }
2186 malloc_mutex_unlock(&dss_mtx);
2187 } else {
2188 malloc_mutex_unlock(&dss_mtx);
Jason Evansc9658dd2009-06-22 14:44:08 -07002189 madvise(chunk, size, MADV_DONTNEED);
Jason Evans289053c2009-06-22 12:08:42 -07002190 }
2191
2192 return (false);
2193 }
2194 malloc_mutex_unlock(&dss_mtx);
2195
2196 return (true);
2197}
2198#endif
2199
2200static void
2201chunk_dealloc_mmap(void *chunk, size_t size)
2202{
2203
2204 pages_unmap(chunk, size);
2205}
2206
2207static void
2208chunk_dealloc(void *chunk, size_t size)
2209{
2210
2211 assert(chunk != NULL);
2212 assert(CHUNK_ADDR2BASE(chunk) == chunk);
2213 assert(size != 0);
2214 assert((size & chunksize_mask) == 0);
2215
Jason Evansb7924f52009-06-23 19:01:18 -07002216#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002217 stats_chunks.curchunks -= (size / chunksize);
2218#endif
2219
Jason Evansb7924f52009-06-23 19:01:18 -07002220#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002221 if (opt_dss) {
2222 if (chunk_dealloc_dss(chunk, size) == false)
2223 return;
2224 }
2225
2226 if (opt_mmap)
2227#endif
2228 chunk_dealloc_mmap(chunk, size);
2229}
2230
2231/*
2232 * End chunk management functions.
2233 */
2234/******************************************************************************/
2235/*
2236 * Begin arena.
2237 */
2238
2239/*
2240 * Choose an arena based on a per-thread value (fast-path code, calls slow-path
2241 * code if necessary).
2242 */
2243static inline arena_t *
2244choose_arena(void)
2245{
2246 arena_t *ret;
2247
2248 /*
2249 * We can only use TLS if this is a PIC library, since for the static
2250 * library version, libc's malloc is used by TLS allocation, which
2251 * introduces a bootstrapping issue.
2252 */
2253#ifndef NO_TLS
Jason Evans289053c2009-06-22 12:08:42 -07002254 ret = arenas_map;
2255 if (ret == NULL) {
2256 ret = choose_arena_hard();
2257 assert(ret != NULL);
2258 }
2259#else
Jason Evansb7924f52009-06-23 19:01:18 -07002260 if (isthreaded && narenas > 1) {
Jason Evans289053c2009-06-22 12:08:42 -07002261 unsigned long ind;
2262
2263 /*
Jason Evansc9658dd2009-06-22 14:44:08 -07002264 * Hash pthread_self() to one of the arenas. There is a prime
Jason Evans289053c2009-06-22 12:08:42 -07002265 * number of arenas, so this has a reasonable chance of
2266 * working. Even so, the hashing can be easily thwarted by
Jason Evansc9658dd2009-06-22 14:44:08 -07002267 * inconvenient pthread_self() values. Without specific
2268 * knowledge of how pthread_self() calculates values, we can't
Jason Evans289053c2009-06-22 12:08:42 -07002269 * easily do much better than this.
2270 */
Jason Evansc9658dd2009-06-22 14:44:08 -07002271 ind = (unsigned long) pthread_self() % narenas;
Jason Evans289053c2009-06-22 12:08:42 -07002272
2273 /*
2274 * Optimistially assume that arenas[ind] has been initialized.
2275 * At worst, we find out that some other thread has already
2276 * done so, after acquiring the lock in preparation. Note that
2277 * this lazy locking also has the effect of lazily forcing
2278 * cache coherency; without the lock acquisition, there's no
2279 * guarantee that modification of arenas[ind] by another thread
2280 * would be seen on this CPU for an arbitrary amount of time.
2281 *
2282 * In general, this approach to modifying a synchronized value
2283 * isn't a good idea, but in this case we only ever modify the
2284 * value once, so things work out well.
2285 */
2286 ret = arenas[ind];
2287 if (ret == NULL) {
2288 /*
2289 * Avoid races with another thread that may have already
2290 * initialized arenas[ind].
2291 */
2292 malloc_spin_lock(&arenas_lock);
2293 if (arenas[ind] == NULL)
2294 ret = arenas_extend((unsigned)ind);
2295 else
2296 ret = arenas[ind];
2297 malloc_spin_unlock(&arenas_lock);
2298 }
2299 } else
2300 ret = arenas[0];
2301#endif
2302
2303 assert(ret != NULL);
2304 return (ret);
2305}
2306
2307#ifndef NO_TLS
2308/*
2309 * Choose an arena based on a per-thread value (slow-path code only, called
2310 * only by choose_arena()).
2311 */
2312static arena_t *
2313choose_arena_hard(void)
2314{
2315 arena_t *ret;
2316
Jason Evansb7924f52009-06-23 19:01:18 -07002317 assert(isthreaded);
Jason Evans289053c2009-06-22 12:08:42 -07002318
Jason Evansb7924f52009-06-23 19:01:18 -07002319#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07002320 /* Seed the PRNG used for arena load balancing. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002321 SPRN(balance, (uint32_t)(uintptr_t)(pthread_self()));
Jason Evans289053c2009-06-22 12:08:42 -07002322#endif
2323
2324 if (narenas > 1) {
Jason Evansb7924f52009-06-23 19:01:18 -07002325#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07002326 unsigned ind;
2327
2328 ind = PRN(balance, narenas_2pow);
2329 if ((ret = arenas[ind]) == NULL) {
2330 malloc_spin_lock(&arenas_lock);
2331 if ((ret = arenas[ind]) == NULL)
2332 ret = arenas_extend(ind);
2333 malloc_spin_unlock(&arenas_lock);
2334 }
2335#else
2336 malloc_spin_lock(&arenas_lock);
2337 if ((ret = arenas[next_arena]) == NULL)
2338 ret = arenas_extend(next_arena);
2339 next_arena = (next_arena + 1) % narenas;
2340 malloc_spin_unlock(&arenas_lock);
2341#endif
2342 } else
2343 ret = arenas[0];
2344
2345 arenas_map = ret;
2346
2347 return (ret);
2348}
2349#endif
2350
2351static inline int
2352arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
2353{
2354 uintptr_t a_chunk = (uintptr_t)a;
2355 uintptr_t b_chunk = (uintptr_t)b;
2356
2357 assert(a != NULL);
2358 assert(b != NULL);
2359
2360 return ((a_chunk > b_chunk) - (a_chunk < b_chunk));
2361}
2362
2363/* Wrap red-black tree macros in functions. */
Jason Evansb8f0a652009-06-29 09:41:43 -07002364rb_wrap(static __attribute__((unused)), arena_chunk_tree_dirty_, arena_chunk_tree_t,
Jason Evans289053c2009-06-22 12:08:42 -07002365 arena_chunk_t, link_dirty, arena_chunk_comp)
2366
2367static inline int
2368arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
2369{
2370 uintptr_t a_mapelm = (uintptr_t)a;
2371 uintptr_t b_mapelm = (uintptr_t)b;
2372
2373 assert(a != NULL);
2374 assert(b != NULL);
2375
2376 return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm));
2377}
2378
2379/* Wrap red-black tree macros in functions. */
Jason Evansb8f0a652009-06-29 09:41:43 -07002380rb_wrap(static __attribute__((unused)), arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
Jason Evans289053c2009-06-22 12:08:42 -07002381 link, arena_run_comp)
2382
2383static inline int
2384arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
2385{
2386 int ret;
2387 size_t a_size = a->bits & ~PAGE_MASK;
2388 size_t b_size = b->bits & ~PAGE_MASK;
2389
2390 ret = (a_size > b_size) - (a_size < b_size);
2391 if (ret == 0) {
2392 uintptr_t a_mapelm, b_mapelm;
2393
2394 if ((a->bits & CHUNK_MAP_KEY) == 0)
2395 a_mapelm = (uintptr_t)a;
2396 else {
2397 /*
2398 * Treat keys as though they are lower than anything
2399 * else.
2400 */
2401 a_mapelm = 0;
2402 }
2403 b_mapelm = (uintptr_t)b;
2404
2405 ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
2406 }
2407
2408 return (ret);
2409}
2410
2411/* Wrap red-black tree macros in functions. */
Jason Evansb8f0a652009-06-29 09:41:43 -07002412rb_wrap(static __attribute__((unused)), arena_avail_tree_, arena_avail_tree_t,
Jason Evans289053c2009-06-22 12:08:42 -07002413 arena_chunk_map_t, link, arena_avail_comp)
2414
2415static inline void *
2416arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
2417{
2418 void *ret;
2419 unsigned i, mask, bit, regind;
2420
2421 assert(run->magic == ARENA_RUN_MAGIC);
2422 assert(run->regs_minelm < bin->regs_mask_nelms);
2423
2424 /*
2425 * Move the first check outside the loop, so that run->regs_minelm can
2426 * be updated unconditionally, without the possibility of updating it
2427 * multiple times.
2428 */
2429 i = run->regs_minelm;
2430 mask = run->regs_mask[i];
2431 if (mask != 0) {
2432 /* Usable allocation found. */
2433 bit = ffs((int)mask) - 1;
2434
2435 regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
2436 assert(regind < bin->nregs);
2437 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
2438 + (bin->reg_size * regind));
2439
2440 /* Clear bit. */
2441 mask ^= (1U << bit);
2442 run->regs_mask[i] = mask;
2443
2444 return (ret);
2445 }
2446
2447 for (i++; i < bin->regs_mask_nelms; i++) {
2448 mask = run->regs_mask[i];
2449 if (mask != 0) {
2450 /* Usable allocation found. */
2451 bit = ffs((int)mask) - 1;
2452
2453 regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
2454 assert(regind < bin->nregs);
2455 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
2456 + (bin->reg_size * regind));
2457
2458 /* Clear bit. */
2459 mask ^= (1U << bit);
2460 run->regs_mask[i] = mask;
2461
2462 /*
2463 * Make a note that nothing before this element
2464 * contains a free region.
2465 */
2466 run->regs_minelm = i; /* Low payoff: + (mask == 0); */
2467
2468 return (ret);
2469 }
2470 }
2471 /* Not reached. */
2472 assert(0);
2473 return (NULL);
2474}
2475
2476static inline void
2477arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
2478{
2479 unsigned diff, regind, elm, bit;
2480
2481 assert(run->magic == ARENA_RUN_MAGIC);
2482
2483 /*
2484 * Avoid doing division with a variable divisor if possible. Using
2485 * actual division here can reduce allocator throughput by over 20%!
2486 */
2487 diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
2488 if ((size & (size - 1)) == 0) {
2489 /*
2490 * log2_table allows fast division of a power of two in the
2491 * [1..128] range.
2492 *
2493 * (x / divisor) becomes (x >> log2_table[divisor - 1]).
2494 */
2495 static const unsigned char log2_table[] = {
2496 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
2497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
2498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
2500 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
2504 };
2505
2506 if (size <= 128)
2507 regind = (diff >> log2_table[size - 1]);
2508 else if (size <= 32768)
2509 regind = diff >> (8 + log2_table[(size >> 8) - 1]);
2510 else
2511 regind = diff / size;
2512 } else if (size < qspace_max) {
2513 /*
2514 * To divide by a number D that is not a power of two we
2515 * multiply by (2^21 / D) and then right shift by 21 positions.
2516 *
2517 * X / D
2518 *
2519 * becomes
2520 *
2521 * (X * qsize_invs[(D >> QUANTUM_2POW) - 3])
2522 * >> SIZE_INV_SHIFT
2523 *
2524 * We can omit the first three elements, because we never
2525 * divide by 0, and QUANTUM and 2*QUANTUM are both powers of
2526 * two, which are handled above.
2527 */
2528#define SIZE_INV_SHIFT 21
2529#define QSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << QUANTUM_2POW)) + 1)
2530 static const unsigned qsize_invs[] = {
2531 QSIZE_INV(3),
2532 QSIZE_INV(4), QSIZE_INV(5), QSIZE_INV(6), QSIZE_INV(7)
2533#if (QUANTUM_2POW < 4)
2534 ,
2535 QSIZE_INV(8), QSIZE_INV(9), QSIZE_INV(10), QSIZE_INV(11),
2536 QSIZE_INV(12),QSIZE_INV(13), QSIZE_INV(14), QSIZE_INV(15)
2537#endif
2538 };
2539 assert(QUANTUM * (((sizeof(qsize_invs)) / sizeof(unsigned)) + 3)
2540 >= (1U << QSPACE_MAX_2POW_DEFAULT));
2541
2542 if (size <= (((sizeof(qsize_invs) / sizeof(unsigned)) + 2) <<
2543 QUANTUM_2POW)) {
2544 regind = qsize_invs[(size >> QUANTUM_2POW) - 3] * diff;
2545 regind >>= SIZE_INV_SHIFT;
2546 } else
2547 regind = diff / size;
2548#undef QSIZE_INV
2549 } else if (size < cspace_max) {
2550#define CSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << CACHELINE_2POW)) + 1)
2551 static const unsigned csize_invs[] = {
2552 CSIZE_INV(3),
2553 CSIZE_INV(4), CSIZE_INV(5), CSIZE_INV(6), CSIZE_INV(7)
2554 };
2555 assert(CACHELINE * (((sizeof(csize_invs)) / sizeof(unsigned)) +
2556 3) >= (1U << CSPACE_MAX_2POW_DEFAULT));
2557
2558 if (size <= (((sizeof(csize_invs) / sizeof(unsigned)) + 2) <<
2559 CACHELINE_2POW)) {
2560 regind = csize_invs[(size >> CACHELINE_2POW) - 3] *
2561 diff;
2562 regind >>= SIZE_INV_SHIFT;
2563 } else
2564 regind = diff / size;
2565#undef CSIZE_INV
2566 } else {
2567#define SSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << SUBPAGE_2POW)) + 1)
2568 static const unsigned ssize_invs[] = {
2569 SSIZE_INV(3),
2570 SSIZE_INV(4), SSIZE_INV(5), SSIZE_INV(6), SSIZE_INV(7),
2571 SSIZE_INV(8), SSIZE_INV(9), SSIZE_INV(10), SSIZE_INV(11),
2572 SSIZE_INV(12), SSIZE_INV(13), SSIZE_INV(14), SSIZE_INV(15)
Jason Evansb7924f52009-06-23 19:01:18 -07002573#if (STATIC_PAGE_SHIFT == 13)
Jason Evans289053c2009-06-22 12:08:42 -07002574 ,
2575 SSIZE_INV(16), SSIZE_INV(17), SSIZE_INV(18), SSIZE_INV(19),
2576 SSIZE_INV(20), SSIZE_INV(21), SSIZE_INV(22), SSIZE_INV(23),
2577 SSIZE_INV(24), SSIZE_INV(25), SSIZE_INV(26), SSIZE_INV(27),
2578 SSIZE_INV(28), SSIZE_INV(29), SSIZE_INV(29), SSIZE_INV(30)
2579#endif
2580 };
2581 assert(SUBPAGE * (((sizeof(ssize_invs)) / sizeof(unsigned)) + 3)
2582 >= PAGE_SIZE);
2583
2584 if (size < (((sizeof(ssize_invs) / sizeof(unsigned)) + 2) <<
2585 SUBPAGE_2POW)) {
2586 regind = ssize_invs[(size >> SUBPAGE_2POW) - 3] * diff;
2587 regind >>= SIZE_INV_SHIFT;
2588 } else
2589 regind = diff / size;
2590#undef SSIZE_INV
2591 }
2592#undef SIZE_INV_SHIFT
2593 assert(diff == regind * size);
2594 assert(regind < bin->nregs);
2595
2596 elm = regind >> (SIZEOF_INT_2POW + 3);
2597 if (elm < run->regs_minelm)
2598 run->regs_minelm = elm;
2599 bit = regind - (elm << (SIZEOF_INT_2POW + 3));
2600 assert((run->regs_mask[elm] & (1U << bit)) == 0);
2601 run->regs_mask[elm] |= (1U << bit);
2602}
2603
2604static void
2605arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large,
2606 bool zero)
2607{
2608 arena_chunk_t *chunk;
2609 size_t old_ndirty, run_ind, total_pages, need_pages, rem_pages, i;
2610
2611 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
2612 old_ndirty = chunk->ndirty;
2613 run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
2614 >> PAGE_SHIFT);
2615 total_pages = (chunk->map[run_ind].bits & ~PAGE_MASK) >>
2616 PAGE_SHIFT;
2617 need_pages = (size >> PAGE_SHIFT);
2618 assert(need_pages > 0);
2619 assert(need_pages <= total_pages);
2620 rem_pages = total_pages - need_pages;
2621
2622 arena_avail_tree_remove(&arena->runs_avail, &chunk->map[run_ind]);
2623
2624 /* Keep track of trailing unused pages for later use. */
2625 if (rem_pages > 0) {
2626 chunk->map[run_ind+need_pages].bits = (rem_pages <<
2627 PAGE_SHIFT) | (chunk->map[run_ind+need_pages].bits &
2628 PAGE_MASK);
2629 chunk->map[run_ind+total_pages-1].bits = (rem_pages <<
2630 PAGE_SHIFT) | (chunk->map[run_ind+total_pages-1].bits &
2631 PAGE_MASK);
2632 arena_avail_tree_insert(&arena->runs_avail,
2633 &chunk->map[run_ind+need_pages]);
2634 }
2635
2636 for (i = 0; i < need_pages; i++) {
2637 /* Zero if necessary. */
2638 if (zero) {
2639 if ((chunk->map[run_ind + i].bits & CHUNK_MAP_ZEROED)
2640 == 0) {
2641 memset((void *)((uintptr_t)chunk + ((run_ind
2642 + i) << PAGE_SHIFT)), 0, PAGE_SIZE);
2643 /* CHUNK_MAP_ZEROED is cleared below. */
2644 }
2645 }
2646
2647 /* Update dirty page accounting. */
2648 if (chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) {
2649 chunk->ndirty--;
2650 arena->ndirty--;
2651 /* CHUNK_MAP_DIRTY is cleared below. */
2652 }
2653
2654 /* Initialize the chunk map. */
2655 if (large) {
2656 chunk->map[run_ind + i].bits = CHUNK_MAP_LARGE
2657 | CHUNK_MAP_ALLOCATED;
2658 } else {
2659 chunk->map[run_ind + i].bits = (size_t)run
2660 | CHUNK_MAP_ALLOCATED;
2661 }
2662 }
2663
2664 /*
2665 * Set the run size only in the first element for large runs. This is
2666 * primarily a debugging aid, since the lack of size info for trailing
2667 * pages only matters if the application tries to operate on an
2668 * interior pointer.
2669 */
2670 if (large)
2671 chunk->map[run_ind].bits |= size;
2672
2673 if (chunk->ndirty == 0 && old_ndirty > 0)
2674 arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk);
2675}
2676
2677static arena_chunk_t *
2678arena_chunk_alloc(arena_t *arena)
2679{
2680 arena_chunk_t *chunk;
2681 size_t i;
2682
2683 if (arena->spare != NULL) {
2684 chunk = arena->spare;
2685 arena->spare = NULL;
2686 } else {
2687 chunk = (arena_chunk_t *)chunk_alloc(chunksize, true);
2688 if (chunk == NULL)
2689 return (NULL);
Jason Evansb7924f52009-06-23 19:01:18 -07002690#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002691 arena->stats.mapped += chunksize;
2692#endif
2693
2694 chunk->arena = arena;
2695
2696 /*
2697 * Claim that no pages are in use, since the header is merely
2698 * overhead.
2699 */
2700 chunk->ndirty = 0;
2701
2702 /*
2703 * Initialize the map to contain one maximal free untouched run.
2704 */
2705 for (i = 0; i < arena_chunk_header_npages; i++)
2706 chunk->map[i].bits = 0;
2707 chunk->map[i].bits = arena_maxclass | CHUNK_MAP_ZEROED;
2708 for (i++; i < chunk_npages-1; i++) {
2709 chunk->map[i].bits = CHUNK_MAP_ZEROED;
2710 }
2711 chunk->map[chunk_npages-1].bits = arena_maxclass |
2712 CHUNK_MAP_ZEROED;
2713 }
2714
2715 /* Insert the run into the runs_avail tree. */
2716 arena_avail_tree_insert(&arena->runs_avail,
2717 &chunk->map[arena_chunk_header_npages]);
2718
2719 return (chunk);
2720}
2721
2722static void
2723arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
2724{
2725
2726 if (arena->spare != NULL) {
2727 if (arena->spare->ndirty > 0) {
2728 arena_chunk_tree_dirty_remove(
2729 &chunk->arena->chunks_dirty, arena->spare);
2730 arena->ndirty -= arena->spare->ndirty;
2731 }
2732 chunk_dealloc((void *)arena->spare, chunksize);
Jason Evansb7924f52009-06-23 19:01:18 -07002733#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002734 arena->stats.mapped -= chunksize;
2735#endif
2736 }
2737
2738 /*
2739 * Remove run from runs_avail, regardless of whether this chunk
2740 * will be cached, so that the arena does not use it. Dirty page
2741 * flushing only uses the chunks_dirty tree, so leaving this chunk in
2742 * the chunks_* trees is sufficient for that purpose.
2743 */
2744 arena_avail_tree_remove(&arena->runs_avail,
2745 &chunk->map[arena_chunk_header_npages]);
2746
2747 arena->spare = chunk;
2748}
2749
2750static arena_run_t *
2751arena_run_alloc(arena_t *arena, size_t size, bool large, bool zero)
2752{
2753 arena_chunk_t *chunk;
2754 arena_run_t *run;
2755 arena_chunk_map_t *mapelm, key;
2756
2757 assert(size <= arena_maxclass);
2758 assert((size & PAGE_MASK) == 0);
2759
2760 /* Search the arena's chunks for the lowest best fit. */
2761 key.bits = size | CHUNK_MAP_KEY;
2762 mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
2763 if (mapelm != NULL) {
2764 arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
2765 size_t pageind = ((uintptr_t)mapelm - (uintptr_t)run_chunk->map)
2766 / sizeof(arena_chunk_map_t);
2767
2768 run = (arena_run_t *)((uintptr_t)run_chunk + (pageind
2769 << PAGE_SHIFT));
2770 arena_run_split(arena, run, size, large, zero);
2771 return (run);
2772 }
2773
2774 /*
2775 * No usable runs. Create a new chunk from which to allocate the run.
2776 */
2777 chunk = arena_chunk_alloc(arena);
2778 if (chunk == NULL)
2779 return (NULL);
2780 run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages <<
2781 PAGE_SHIFT));
2782 /* Update page map. */
2783 arena_run_split(arena, run, size, large, zero);
2784 return (run);
2785}
2786
2787static void
2788arena_purge(arena_t *arena)
2789{
2790 arena_chunk_t *chunk;
2791 size_t i, npages;
Jason Evansb7924f52009-06-23 19:01:18 -07002792#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07002793 size_t ndirty = 0;
2794
2795 rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty,
2796 chunk) {
2797 ndirty += chunk->ndirty;
2798 } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk)
2799 assert(ndirty == arena->ndirty);
2800#endif
2801 assert(arena->ndirty > opt_dirty_max);
2802
Jason Evansb7924f52009-06-23 19:01:18 -07002803#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002804 arena->stats.npurge++;
2805#endif
2806
2807 /*
2808 * Iterate downward through chunks until enough dirty memory has been
2809 * purged. Terminate as soon as possible in order to minimize the
2810 * number of system calls, even if a chunk has only been partially
2811 * purged.
2812 */
2813 while (arena->ndirty > (opt_dirty_max >> 1)) {
2814 chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty);
2815 assert(chunk != NULL);
2816
2817 for (i = chunk_npages - 1; chunk->ndirty > 0; i--) {
2818 assert(i >= arena_chunk_header_npages);
2819
2820 if (chunk->map[i].bits & CHUNK_MAP_DIRTY) {
2821 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
2822 /* Find adjacent dirty run(s). */
2823 for (npages = 1; i > arena_chunk_header_npages
2824 && (chunk->map[i - 1].bits &
2825 CHUNK_MAP_DIRTY); npages++) {
2826 i--;
2827 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
2828 }
2829 chunk->ndirty -= npages;
2830 arena->ndirty -= npages;
2831
2832 madvise((void *)((uintptr_t)chunk + (i <<
2833 PAGE_SHIFT)), (npages << PAGE_SHIFT),
Jason Evansc9658dd2009-06-22 14:44:08 -07002834 MADV_DONTNEED);
Jason Evansb7924f52009-06-23 19:01:18 -07002835#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002836 arena->stats.nmadvise++;
2837 arena->stats.purged += npages;
2838#endif
2839 if (arena->ndirty <= (opt_dirty_max >> 1))
2840 break;
2841 }
2842 }
2843
2844 if (chunk->ndirty == 0) {
2845 arena_chunk_tree_dirty_remove(&arena->chunks_dirty,
2846 chunk);
2847 }
2848 }
2849}
2850
2851static void
2852arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty)
2853{
2854 arena_chunk_t *chunk;
2855 size_t size, run_ind, run_pages;
2856
2857 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
2858 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk)
2859 >> PAGE_SHIFT);
2860 assert(run_ind >= arena_chunk_header_npages);
2861 assert(run_ind < chunk_npages);
2862 if ((chunk->map[run_ind].bits & CHUNK_MAP_LARGE) != 0)
2863 size = chunk->map[run_ind].bits & ~PAGE_MASK;
2864 else
2865 size = run->bin->run_size;
2866 run_pages = (size >> PAGE_SHIFT);
2867
2868 /* Mark pages as unallocated in the chunk map. */
2869 if (dirty) {
2870 size_t i;
2871
2872 for (i = 0; i < run_pages; i++) {
2873 assert((chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY)
2874 == 0);
2875 chunk->map[run_ind + i].bits = CHUNK_MAP_DIRTY;
2876 }
2877
2878 if (chunk->ndirty == 0) {
2879 arena_chunk_tree_dirty_insert(&arena->chunks_dirty,
2880 chunk);
2881 }
2882 chunk->ndirty += run_pages;
2883 arena->ndirty += run_pages;
2884 } else {
2885 size_t i;
2886
2887 for (i = 0; i < run_pages; i++) {
2888 chunk->map[run_ind + i].bits &= ~(CHUNK_MAP_LARGE |
2889 CHUNK_MAP_ALLOCATED);
2890 }
2891 }
2892 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2893 PAGE_MASK);
2894 chunk->map[run_ind+run_pages-1].bits = size |
2895 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2896
2897 /* Try to coalesce forward. */
2898 if (run_ind + run_pages < chunk_npages &&
2899 (chunk->map[run_ind+run_pages].bits & CHUNK_MAP_ALLOCATED) == 0) {
2900 size_t nrun_size = chunk->map[run_ind+run_pages].bits &
2901 ~PAGE_MASK;
2902
2903 /*
2904 * Remove successor from runs_avail; the coalesced run is
2905 * inserted later.
2906 */
2907 arena_avail_tree_remove(&arena->runs_avail,
2908 &chunk->map[run_ind+run_pages]);
2909
2910 size += nrun_size;
2911 run_pages = size >> PAGE_SHIFT;
2912
2913 assert((chunk->map[run_ind+run_pages-1].bits & ~PAGE_MASK)
2914 == nrun_size);
2915 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2916 PAGE_MASK);
2917 chunk->map[run_ind+run_pages-1].bits = size |
2918 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2919 }
2920
2921 /* Try to coalesce backward. */
2922 if (run_ind > arena_chunk_header_npages && (chunk->map[run_ind-1].bits &
2923 CHUNK_MAP_ALLOCATED) == 0) {
2924 size_t prun_size = chunk->map[run_ind-1].bits & ~PAGE_MASK;
2925
2926 run_ind -= prun_size >> PAGE_SHIFT;
2927
2928 /*
2929 * Remove predecessor from runs_avail; the coalesced run is
2930 * inserted later.
2931 */
2932 arena_avail_tree_remove(&arena->runs_avail,
2933 &chunk->map[run_ind]);
2934
2935 size += prun_size;
2936 run_pages = size >> PAGE_SHIFT;
2937
2938 assert((chunk->map[run_ind].bits & ~PAGE_MASK) ==
2939 prun_size);
2940 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2941 PAGE_MASK);
2942 chunk->map[run_ind+run_pages-1].bits = size |
2943 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2944 }
2945
2946 /* Insert into runs_avail, now that coalescing is complete. */
2947 arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind]);
2948
2949 /* Deallocate chunk if it is now completely unused. */
2950 if ((chunk->map[arena_chunk_header_npages].bits & (~PAGE_MASK |
2951 CHUNK_MAP_ALLOCATED)) == arena_maxclass)
2952 arena_chunk_dealloc(arena, chunk);
2953
2954 /* Enforce opt_dirty_max. */
2955 if (arena->ndirty > opt_dirty_max)
2956 arena_purge(arena);
2957}
2958
2959static void
2960arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
2961 size_t oldsize, size_t newsize)
2962{
2963 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
2964 size_t head_npages = (oldsize - newsize) >> PAGE_SHIFT;
2965
2966 assert(oldsize > newsize);
2967
2968 /*
2969 * Update the chunk map so that arena_run_dalloc() can treat the
2970 * leading run as separately allocated.
2971 */
2972 chunk->map[pageind].bits = (oldsize - newsize) | CHUNK_MAP_LARGE |
2973 CHUNK_MAP_ALLOCATED;
2974 chunk->map[pageind+head_npages].bits = newsize | CHUNK_MAP_LARGE |
2975 CHUNK_MAP_ALLOCATED;
2976
2977 arena_run_dalloc(arena, run, false);
2978}
2979
2980static void
2981arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
2982 size_t oldsize, size_t newsize, bool dirty)
2983{
2984 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
2985 size_t npages = newsize >> PAGE_SHIFT;
2986
2987 assert(oldsize > newsize);
2988
2989 /*
2990 * Update the chunk map so that arena_run_dalloc() can treat the
2991 * trailing run as separately allocated.
2992 */
2993 chunk->map[pageind].bits = newsize | CHUNK_MAP_LARGE |
2994 CHUNK_MAP_ALLOCATED;
2995 chunk->map[pageind+npages].bits = (oldsize - newsize) | CHUNK_MAP_LARGE
2996 | CHUNK_MAP_ALLOCATED;
2997
2998 arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize),
2999 dirty);
3000}
3001
3002static arena_run_t *
3003arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
3004{
3005 arena_chunk_map_t *mapelm;
3006 arena_run_t *run;
3007 unsigned i, remainder;
3008
3009 /* Look for a usable run. */
3010 mapelm = arena_run_tree_first(&bin->runs);
3011 if (mapelm != NULL) {
3012 /* run is guaranteed to have available space. */
3013 arena_run_tree_remove(&bin->runs, mapelm);
3014 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
Jason Evansb7924f52009-06-23 19:01:18 -07003015#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003016 bin->stats.reruns++;
3017#endif
3018 return (run);
3019 }
3020 /* No existing runs have any space available. */
3021
3022 /* Allocate a new run. */
3023 run = arena_run_alloc(arena, bin->run_size, false, false);
3024 if (run == NULL)
3025 return (NULL);
3026
3027 /* Initialize run internals. */
3028 run->bin = bin;
3029
3030 for (i = 0; i < bin->regs_mask_nelms - 1; i++)
3031 run->regs_mask[i] = UINT_MAX;
3032 remainder = bin->nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1);
3033 if (remainder == 0)
3034 run->regs_mask[i] = UINT_MAX;
3035 else {
3036 /* The last element has spare bits that need to be unset. */
3037 run->regs_mask[i] = (UINT_MAX >> ((1U << (SIZEOF_INT_2POW + 3))
3038 - remainder));
3039 }
3040
3041 run->regs_minelm = 0;
3042
3043 run->nfree = bin->nregs;
Jason Evansb7924f52009-06-23 19:01:18 -07003044#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07003045 run->magic = ARENA_RUN_MAGIC;
3046#endif
3047
Jason Evansb7924f52009-06-23 19:01:18 -07003048#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003049 bin->stats.nruns++;
3050 bin->stats.curruns++;
3051 if (bin->stats.curruns > bin->stats.highruns)
3052 bin->stats.highruns = bin->stats.curruns;
3053#endif
3054 return (run);
3055}
3056
3057/* bin->runcur must have space available before this function is called. */
3058static inline void *
3059arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run)
3060{
3061 void *ret;
3062
3063 assert(run->magic == ARENA_RUN_MAGIC);
3064 assert(run->nfree > 0);
3065
3066 ret = arena_run_reg_alloc(run, bin);
3067 assert(ret != NULL);
3068 run->nfree--;
3069
3070 return (ret);
3071}
3072
3073/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
3074static void *
3075arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
3076{
3077
3078 bin->runcur = arena_bin_nonfull_run_get(arena, bin);
3079 if (bin->runcur == NULL)
3080 return (NULL);
3081 assert(bin->runcur->magic == ARENA_RUN_MAGIC);
3082 assert(bin->runcur->nfree > 0);
3083
3084 return (arena_bin_malloc_easy(arena, bin, bin->runcur));
3085}
3086
3087/*
3088 * Calculate bin->run_size such that it meets the following constraints:
3089 *
3090 * *) bin->run_size >= min_run_size
3091 * *) bin->run_size <= arena_maxclass
3092 * *) bin->run_size <= RUN_MAX_SMALL
3093 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
3094 *
3095 * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
3096 * also calculated here, since these settings are all interdependent.
3097 */
3098static size_t
3099arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size)
3100{
3101 size_t try_run_size, good_run_size;
3102 unsigned good_nregs, good_mask_nelms, good_reg0_offset;
3103 unsigned try_nregs, try_mask_nelms, try_reg0_offset;
3104
3105 assert(min_run_size >= PAGE_SIZE);
3106 assert(min_run_size <= arena_maxclass);
3107 assert(min_run_size <= RUN_MAX_SMALL);
3108
3109 /*
3110 * Calculate known-valid settings before entering the run_size
3111 * expansion loop, so that the first part of the loop always copies
3112 * valid settings.
3113 *
3114 * The do..while loop iteratively reduces the number of regions until
3115 * the run header and the regions no longer overlap. A closed formula
3116 * would be quite messy, since there is an interdependency between the
3117 * header's mask length and the number of regions.
3118 */
3119 try_run_size = min_run_size;
3120 try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size)
3121 + 1; /* Counter-act try_nregs-- in loop. */
3122 do {
3123 try_nregs--;
3124 try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
3125 ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0);
3126 try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
3127 } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))
3128 > try_reg0_offset);
3129
3130 /* run_size expansion loop. */
3131 do {
3132 /*
3133 * Copy valid settings before trying more aggressive settings.
3134 */
3135 good_run_size = try_run_size;
3136 good_nregs = try_nregs;
3137 good_mask_nelms = try_mask_nelms;
3138 good_reg0_offset = try_reg0_offset;
3139
3140 /* Try more aggressive settings. */
3141 try_run_size += PAGE_SIZE;
3142 try_nregs = ((try_run_size - sizeof(arena_run_t)) /
3143 bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */
3144 do {
3145 try_nregs--;
3146 try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
3147 ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ?
3148 1 : 0);
3149 try_reg0_offset = try_run_size - (try_nregs *
3150 bin->reg_size);
3151 } while (sizeof(arena_run_t) + (sizeof(unsigned) *
3152 (try_mask_nelms - 1)) > try_reg0_offset);
3153 } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL
3154 && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX
3155 && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size);
3156
3157 assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1))
3158 <= good_reg0_offset);
3159 assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs);
3160
3161 /* Copy final settings. */
3162 bin->run_size = good_run_size;
3163 bin->nregs = good_nregs;
3164 bin->regs_mask_nelms = good_mask_nelms;
3165 bin->reg0_offset = good_reg0_offset;
3166
3167 return (good_run_size);
3168}
3169
Jason Evansb7924f52009-06-23 19:01:18 -07003170#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003171static inline void
3172arena_lock_balance(arena_t *arena)
3173{
3174 unsigned contention;
3175
3176 contention = malloc_spin_lock(&arena->lock);
3177 if (narenas > 1) {
3178 /*
3179 * Calculate the exponentially averaged contention for this
3180 * arena. Due to integer math always rounding down, this value
3181 * decays somewhat faster than normal.
3182 */
3183 arena->contention = (((uint64_t)arena->contention
3184 * (uint64_t)((1U << BALANCE_ALPHA_INV_2POW)-1))
3185 + (uint64_t)contention) >> BALANCE_ALPHA_INV_2POW;
3186 if (arena->contention >= opt_balance_threshold)
3187 arena_lock_balance_hard(arena);
3188 }
3189}
3190
3191static void
3192arena_lock_balance_hard(arena_t *arena)
3193{
3194 uint32_t ind;
3195
3196 arena->contention = 0;
Jason Evansb7924f52009-06-23 19:01:18 -07003197#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003198 arena->stats.nbalance++;
3199#endif
3200 ind = PRN(balance, narenas_2pow);
3201 if (arenas[ind] != NULL)
3202 arenas_map = arenas[ind];
3203 else {
3204 malloc_spin_lock(&arenas_lock);
3205 if (arenas[ind] != NULL)
3206 arenas_map = arenas[ind];
3207 else
3208 arenas_map = arenas_extend(ind);
3209 malloc_spin_unlock(&arenas_lock);
3210 }
3211}
3212#endif
3213
Jason Evansb7924f52009-06-23 19:01:18 -07003214#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003215static inline void *
3216mag_alloc(mag_t *mag)
3217{
3218
3219 if (mag->nrounds == 0)
3220 return (NULL);
3221 mag->nrounds--;
3222
3223 return (mag->rounds[mag->nrounds]);
3224}
3225
3226static void
3227mag_load(mag_t *mag)
3228{
3229 arena_t *arena;
3230 arena_bin_t *bin;
3231 arena_run_t *run;
3232 void *round;
3233 size_t i;
3234
3235 arena = choose_arena();
3236 bin = &arena->bins[mag->binind];
Jason Evansb7924f52009-06-23 19:01:18 -07003237#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003238 arena_lock_balance(arena);
3239#else
3240 malloc_spin_lock(&arena->lock);
3241#endif
3242 for (i = mag->nrounds; i < max_rounds; i++) {
3243 if ((run = bin->runcur) != NULL && run->nfree > 0)
3244 round = arena_bin_malloc_easy(arena, bin, run);
3245 else
3246 round = arena_bin_malloc_hard(arena, bin);
3247 if (round == NULL)
3248 break;
3249 mag->rounds[i] = round;
3250 }
Jason Evansb7924f52009-06-23 19:01:18 -07003251#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003252 bin->stats.nmags++;
3253 arena->stats.nmalloc_small += (i - mag->nrounds);
3254 arena->stats.allocated_small += (i - mag->nrounds) * bin->reg_size;
3255#endif
3256 malloc_spin_unlock(&arena->lock);
3257 mag->nrounds = i;
3258}
3259
3260static inline void *
3261mag_rack_alloc(mag_rack_t *rack, size_t size, bool zero)
3262{
3263 void *ret;
3264 bin_mags_t *bin_mags;
3265 mag_t *mag;
3266 size_t binind;
3267
3268 binind = size2bin[size];
3269 assert(binind < nbins);
3270 bin_mags = &rack->bin_mags[binind];
3271
3272 mag = bin_mags->curmag;
3273 if (mag == NULL) {
3274 /* Create an initial magazine for this size class. */
3275 assert(bin_mags->sparemag == NULL);
3276 mag = mag_create(choose_arena(), binind);
3277 if (mag == NULL)
3278 return (NULL);
3279 bin_mags->curmag = mag;
3280 mag_load(mag);
3281 }
3282
3283 ret = mag_alloc(mag);
3284 if (ret == NULL) {
3285 if (bin_mags->sparemag != NULL) {
3286 if (bin_mags->sparemag->nrounds > 0) {
3287 /* Swap magazines. */
3288 bin_mags->curmag = bin_mags->sparemag;
3289 bin_mags->sparemag = mag;
3290 mag = bin_mags->curmag;
3291 } else {
3292 /* Reload the current magazine. */
3293 mag_load(mag);
3294 }
3295 } else {
3296 /* Create a second magazine. */
3297 mag = mag_create(choose_arena(), binind);
3298 if (mag == NULL)
3299 return (NULL);
3300 mag_load(mag);
3301 bin_mags->sparemag = bin_mags->curmag;
3302 bin_mags->curmag = mag;
3303 }
3304 ret = mag_alloc(mag);
3305 if (ret == NULL)
3306 return (NULL);
3307 }
3308
3309 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003310#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003311 if (opt_junk)
3312 memset(ret, 0xa5, size);
3313 else if (opt_zero)
3314 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003315#endif
Jason Evans289053c2009-06-22 12:08:42 -07003316 } else
3317 memset(ret, 0, size);
3318
3319 return (ret);
3320}
3321#endif
3322
3323static inline void *
3324arena_malloc_small(arena_t *arena, size_t size, bool zero)
3325{
3326 void *ret;
3327 arena_bin_t *bin;
3328 arena_run_t *run;
3329 size_t binind;
3330
3331 binind = size2bin[size];
3332 assert(binind < nbins);
3333 bin = &arena->bins[binind];
3334 size = bin->reg_size;
3335
Jason Evansb7924f52009-06-23 19:01:18 -07003336#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003337 arena_lock_balance(arena);
3338#else
3339 malloc_spin_lock(&arena->lock);
3340#endif
3341 if ((run = bin->runcur) != NULL && run->nfree > 0)
3342 ret = arena_bin_malloc_easy(arena, bin, run);
3343 else
3344 ret = arena_bin_malloc_hard(arena, bin);
3345
3346 if (ret == NULL) {
3347 malloc_spin_unlock(&arena->lock);
3348 return (NULL);
3349 }
3350
Jason Evansb7924f52009-06-23 19:01:18 -07003351#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003352 bin->stats.nrequests++;
3353 arena->stats.nmalloc_small++;
3354 arena->stats.allocated_small += size;
3355#endif
3356 malloc_spin_unlock(&arena->lock);
3357
3358 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003359#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003360 if (opt_junk)
3361 memset(ret, 0xa5, size);
3362 else if (opt_zero)
3363 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003364#endif
Jason Evans289053c2009-06-22 12:08:42 -07003365 } else
3366 memset(ret, 0, size);
3367
3368 return (ret);
3369}
3370
3371static void *
3372arena_malloc_large(arena_t *arena, size_t size, bool zero)
3373{
3374 void *ret;
3375
3376 /* Large allocation. */
3377 size = PAGE_CEILING(size);
Jason Evansb7924f52009-06-23 19:01:18 -07003378#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003379 arena_lock_balance(arena);
3380#else
3381 malloc_spin_lock(&arena->lock);
3382#endif
3383 ret = (void *)arena_run_alloc(arena, size, true, zero);
3384 if (ret == NULL) {
3385 malloc_spin_unlock(&arena->lock);
3386 return (NULL);
3387 }
Jason Evansb7924f52009-06-23 19:01:18 -07003388#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003389 arena->stats.nmalloc_large++;
3390 arena->stats.allocated_large += size;
3391#endif
3392 malloc_spin_unlock(&arena->lock);
3393
3394 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003395#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003396 if (opt_junk)
3397 memset(ret, 0xa5, size);
3398 else if (opt_zero)
3399 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003400#endif
Jason Evans289053c2009-06-22 12:08:42 -07003401 }
3402
3403 return (ret);
3404}
3405
3406static inline void *
Jason Evanscc00a152009-06-25 18:06:48 -07003407arena_malloc(size_t size, bool zero)
Jason Evans289053c2009-06-22 12:08:42 -07003408{
3409
Jason Evans289053c2009-06-22 12:08:42 -07003410 assert(size != 0);
3411 assert(QUANTUM_CEILING(size) <= arena_maxclass);
3412
3413 if (size <= bin_maxclass) {
Jason Evansb7924f52009-06-23 19:01:18 -07003414#ifdef JEMALLOC_MAG
3415 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07003416 mag_rack_t *rack = mag_rack;
3417 if (rack == NULL) {
Jason Evanscc00a152009-06-25 18:06:48 -07003418 rack = mag_rack_create(choose_arena());
Jason Evans289053c2009-06-22 12:08:42 -07003419 if (rack == NULL)
3420 return (NULL);
3421 mag_rack = rack;
Jason Evansb7924f52009-06-23 19:01:18 -07003422 pthread_setspecific(mag_rack_tsd, rack);
Jason Evans289053c2009-06-22 12:08:42 -07003423 }
3424 return (mag_rack_alloc(rack, size, zero));
3425 } else
3426#endif
Jason Evanscc00a152009-06-25 18:06:48 -07003427 return (arena_malloc_small(choose_arena(), size, zero));
Jason Evans289053c2009-06-22 12:08:42 -07003428 } else
Jason Evanscc00a152009-06-25 18:06:48 -07003429 return (arena_malloc_large(choose_arena(), size, zero));
Jason Evans289053c2009-06-22 12:08:42 -07003430}
3431
3432static inline void *
3433imalloc(size_t size)
3434{
3435
3436 assert(size != 0);
3437
3438 if (size <= arena_maxclass)
Jason Evanscc00a152009-06-25 18:06:48 -07003439 return (arena_malloc(size, false));
Jason Evans289053c2009-06-22 12:08:42 -07003440 else
3441 return (huge_malloc(size, false));
3442}
3443
3444static inline void *
3445icalloc(size_t size)
3446{
3447
3448 if (size <= arena_maxclass)
Jason Evanscc00a152009-06-25 18:06:48 -07003449 return (arena_malloc(size, true));
Jason Evans289053c2009-06-22 12:08:42 -07003450 else
3451 return (huge_malloc(size, true));
3452}
3453
3454/* Only handles large allocations that require more than page alignment. */
3455static void *
3456arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size)
3457{
3458 void *ret;
3459 size_t offset;
3460 arena_chunk_t *chunk;
3461
3462 assert((size & PAGE_MASK) == 0);
3463 assert((alignment & PAGE_MASK) == 0);
3464
Jason Evansb7924f52009-06-23 19:01:18 -07003465#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003466 arena_lock_balance(arena);
3467#else
3468 malloc_spin_lock(&arena->lock);
3469#endif
3470 ret = (void *)arena_run_alloc(arena, alloc_size, true, false);
3471 if (ret == NULL) {
3472 malloc_spin_unlock(&arena->lock);
3473 return (NULL);
3474 }
3475
3476 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
3477
3478 offset = (uintptr_t)ret & (alignment - 1);
3479 assert((offset & PAGE_MASK) == 0);
3480 assert(offset < alloc_size);
3481 if (offset == 0)
3482 arena_run_trim_tail(arena, chunk, ret, alloc_size, size, false);
3483 else {
3484 size_t leadsize, trailsize;
3485
3486 leadsize = alignment - offset;
3487 if (leadsize > 0) {
3488 arena_run_trim_head(arena, chunk, ret, alloc_size,
3489 alloc_size - leadsize);
3490 ret = (void *)((uintptr_t)ret + leadsize);
3491 }
3492
3493 trailsize = alloc_size - leadsize - size;
3494 if (trailsize != 0) {
3495 /* Trim trailing space. */
3496 assert(trailsize < alloc_size);
3497 arena_run_trim_tail(arena, chunk, ret, size + trailsize,
3498 size, false);
3499 }
3500 }
3501
Jason Evansb7924f52009-06-23 19:01:18 -07003502#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003503 arena->stats.nmalloc_large++;
3504 arena->stats.allocated_large += size;
3505#endif
3506 malloc_spin_unlock(&arena->lock);
3507
Jason Evansb7924f52009-06-23 19:01:18 -07003508#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003509 if (opt_junk)
3510 memset(ret, 0xa5, size);
3511 else if (opt_zero)
3512 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003513#endif
Jason Evans289053c2009-06-22 12:08:42 -07003514 return (ret);
3515}
3516
3517static inline void *
3518ipalloc(size_t alignment, size_t size)
3519{
3520 void *ret;
3521 size_t ceil_size;
3522
3523 /*
3524 * Round size up to the nearest multiple of alignment.
3525 *
3526 * This done, we can take advantage of the fact that for each small
3527 * size class, every object is aligned at the smallest power of two
3528 * that is non-zero in the base two representation of the size. For
3529 * example:
3530 *
3531 * Size | Base 2 | Minimum alignment
3532 * -----+----------+------------------
3533 * 96 | 1100000 | 32
3534 * 144 | 10100000 | 32
3535 * 192 | 11000000 | 64
3536 *
3537 * Depending on runtime settings, it is possible that arena_malloc()
3538 * will further round up to a power of two, but that never causes
3539 * correctness issues.
3540 */
3541 ceil_size = (size + (alignment - 1)) & (-alignment);
3542 /*
3543 * (ceil_size < size) protects against the combination of maximal
3544 * alignment and size greater than maximal alignment.
3545 */
3546 if (ceil_size < size) {
3547 /* size_t overflow. */
3548 return (NULL);
3549 }
3550
3551 if (ceil_size <= PAGE_SIZE || (alignment <= PAGE_SIZE
3552 && ceil_size <= arena_maxclass))
Jason Evanscc00a152009-06-25 18:06:48 -07003553 ret = arena_malloc(ceil_size, false);
Jason Evans289053c2009-06-22 12:08:42 -07003554 else {
3555 size_t run_size;
3556
3557 /*
3558 * We can't achieve subpage alignment, so round up alignment
3559 * permanently; it makes later calculations simpler.
3560 */
3561 alignment = PAGE_CEILING(alignment);
3562 ceil_size = PAGE_CEILING(size);
3563 /*
3564 * (ceil_size < size) protects against very large sizes within
3565 * PAGE_SIZE of SIZE_T_MAX.
3566 *
3567 * (ceil_size + alignment < ceil_size) protects against the
3568 * combination of maximal alignment and ceil_size large enough
3569 * to cause overflow. This is similar to the first overflow
3570 * check above, but it needs to be repeated due to the new
3571 * ceil_size value, which may now be *equal* to maximal
3572 * alignment, whereas before we only detected overflow if the
3573 * original size was *greater* than maximal alignment.
3574 */
3575 if (ceil_size < size || ceil_size + alignment < ceil_size) {
3576 /* size_t overflow. */
3577 return (NULL);
3578 }
3579
3580 /*
3581 * Calculate the size of the over-size run that arena_palloc()
3582 * would need to allocate in order to guarantee the alignment.
3583 */
3584 if (ceil_size >= alignment)
3585 run_size = ceil_size + alignment - PAGE_SIZE;
3586 else {
3587 /*
3588 * It is possible that (alignment << 1) will cause
3589 * overflow, but it doesn't matter because we also
3590 * subtract PAGE_SIZE, which in the case of overflow
3591 * leaves us with a very large run_size. That causes
3592 * the first conditional below to fail, which means
3593 * that the bogus run_size value never gets used for
3594 * anything important.
3595 */
3596 run_size = (alignment << 1) - PAGE_SIZE;
3597 }
3598
3599 if (run_size <= arena_maxclass) {
3600 ret = arena_palloc(choose_arena(), alignment, ceil_size,
3601 run_size);
3602 } else if (alignment <= chunksize)
3603 ret = huge_malloc(ceil_size, false);
3604 else
3605 ret = huge_palloc(alignment, ceil_size);
3606 }
3607
3608 assert(((uintptr_t)ret & (alignment - 1)) == 0);
3609 return (ret);
3610}
3611
3612/* Return the size of the allocation pointed to by ptr. */
3613static size_t
3614arena_salloc(const void *ptr)
3615{
3616 size_t ret;
3617 arena_chunk_t *chunk;
3618 size_t pageind, mapbits;
3619
3620 assert(ptr != NULL);
3621 assert(CHUNK_ADDR2BASE(ptr) != ptr);
3622
3623 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3624 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3625 mapbits = chunk->map[pageind].bits;
3626 assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
3627 if ((mapbits & CHUNK_MAP_LARGE) == 0) {
3628 arena_run_t *run = (arena_run_t *)(mapbits & ~PAGE_MASK);
3629 assert(run->magic == ARENA_RUN_MAGIC);
3630 ret = run->bin->reg_size;
3631 } else {
3632 ret = mapbits & ~PAGE_MASK;
3633 assert(ret != 0);
3634 }
3635
3636 return (ret);
3637}
3638
3639static inline size_t
3640isalloc(const void *ptr)
3641{
3642 size_t ret;
3643 arena_chunk_t *chunk;
3644
3645 assert(ptr != NULL);
3646
3647 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3648 if (chunk != ptr) {
3649 /* Region. */
3650 assert(chunk->arena->magic == ARENA_MAGIC);
3651
3652 ret = arena_salloc(ptr);
3653 } else {
3654 extent_node_t *node, key;
3655
3656 /* Chunk (huge allocation). */
3657
3658 malloc_mutex_lock(&huge_mtx);
3659
3660 /* Extract from tree of huge allocations. */
3661 key.addr = __DECONST(void *, ptr);
3662 node = extent_tree_ad_search(&huge, &key);
3663 assert(node != NULL);
3664
3665 ret = node->size;
3666
3667 malloc_mutex_unlock(&huge_mtx);
3668 }
3669
3670 return (ret);
3671}
3672
3673static inline void
3674arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3675 arena_chunk_map_t *mapelm)
3676{
3677 arena_run_t *run;
3678 arena_bin_t *bin;
3679 size_t size;
3680
3681 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
3682 assert(run->magic == ARENA_RUN_MAGIC);
3683 bin = run->bin;
3684 size = bin->reg_size;
3685
Jason Evansb7924f52009-06-23 19:01:18 -07003686#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003687 if (opt_junk)
3688 memset(ptr, 0x5a, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003689#endif
Jason Evans289053c2009-06-22 12:08:42 -07003690
3691 arena_run_reg_dalloc(run, bin, ptr, size);
3692 run->nfree++;
3693
3694 if (run->nfree == bin->nregs) {
3695 /* Deallocate run. */
3696 if (run == bin->runcur)
3697 bin->runcur = NULL;
3698 else if (bin->nregs != 1) {
3699 size_t run_pageind = (((uintptr_t)run -
3700 (uintptr_t)chunk)) >> PAGE_SHIFT;
3701 arena_chunk_map_t *run_mapelm =
3702 &chunk->map[run_pageind];
3703 /*
3704 * This block's conditional is necessary because if the
3705 * run only contains one region, then it never gets
3706 * inserted into the non-full runs tree.
3707 */
3708 arena_run_tree_remove(&bin->runs, run_mapelm);
3709 }
Jason Evansb7924f52009-06-23 19:01:18 -07003710#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07003711 run->magic = 0;
3712#endif
3713 arena_run_dalloc(arena, run, true);
Jason Evansb7924f52009-06-23 19:01:18 -07003714#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003715 bin->stats.curruns--;
3716#endif
3717 } else if (run->nfree == 1 && run != bin->runcur) {
3718 /*
3719 * Make sure that bin->runcur always refers to the lowest
3720 * non-full run, if one exists.
3721 */
3722 if (bin->runcur == NULL)
3723 bin->runcur = run;
3724 else if ((uintptr_t)run < (uintptr_t)bin->runcur) {
3725 /* Switch runcur. */
3726 if (bin->runcur->nfree > 0) {
3727 arena_chunk_t *runcur_chunk =
3728 CHUNK_ADDR2BASE(bin->runcur);
3729 size_t runcur_pageind =
3730 (((uintptr_t)bin->runcur -
3731 (uintptr_t)runcur_chunk)) >> PAGE_SHIFT;
3732 arena_chunk_map_t *runcur_mapelm =
3733 &runcur_chunk->map[runcur_pageind];
3734
3735 /* Insert runcur. */
3736 arena_run_tree_insert(&bin->runs,
3737 runcur_mapelm);
3738 }
3739 bin->runcur = run;
3740 } else {
3741 size_t run_pageind = (((uintptr_t)run -
3742 (uintptr_t)chunk)) >> PAGE_SHIFT;
3743 arena_chunk_map_t *run_mapelm =
3744 &chunk->map[run_pageind];
3745
3746 assert(arena_run_tree_search(&bin->runs, run_mapelm) ==
3747 NULL);
3748 arena_run_tree_insert(&bin->runs, run_mapelm);
3749 }
3750 }
Jason Evansb7924f52009-06-23 19:01:18 -07003751#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003752 arena->stats.allocated_small -= size;
3753 arena->stats.ndalloc_small++;
3754#endif
3755}
3756
Jason Evansb7924f52009-06-23 19:01:18 -07003757#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003758static void
3759mag_unload(mag_t *mag)
3760{
3761 arena_chunk_t *chunk;
3762 arena_t *arena;
3763 void *round;
3764 size_t i, ndeferred, nrounds;
3765
3766 for (ndeferred = mag->nrounds; ndeferred > 0;) {
3767 nrounds = ndeferred;
3768 /* Lock the arena associated with the first round. */
3769 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mag->rounds[0]);
3770 arena = chunk->arena;
Jason Evansb7924f52009-06-23 19:01:18 -07003771#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003772 arena_lock_balance(arena);
3773#else
3774 malloc_spin_lock(&arena->lock);
3775#endif
3776 /* Deallocate every round that belongs to the locked arena. */
3777 for (i = ndeferred = 0; i < nrounds; i++) {
3778 round = mag->rounds[i];
3779 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(round);
3780 if (chunk->arena == arena) {
3781 size_t pageind = (((uintptr_t)round -
3782 (uintptr_t)chunk) >> PAGE_SHIFT);
3783 arena_chunk_map_t *mapelm =
3784 &chunk->map[pageind];
3785 arena_dalloc_small(arena, chunk, round, mapelm);
3786 } else {
3787 /*
3788 * This round was allocated via a different
3789 * arena than the one that is currently locked.
3790 * Stash the round, so that it can be handled
3791 * in a future pass.
3792 */
3793 mag->rounds[ndeferred] = round;
3794 ndeferred++;
3795 }
3796 }
3797 malloc_spin_unlock(&arena->lock);
3798 }
3799
3800 mag->nrounds = 0;
3801}
3802
3803static inline void
3804mag_rack_dalloc(mag_rack_t *rack, void *ptr)
3805{
3806 arena_t *arena;
3807 arena_chunk_t *chunk;
3808 arena_run_t *run;
3809 arena_bin_t *bin;
3810 bin_mags_t *bin_mags;
3811 mag_t *mag;
3812 size_t pageind, binind;
3813 arena_chunk_map_t *mapelm;
3814
3815 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3816 arena = chunk->arena;
3817 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3818 mapelm = &chunk->map[pageind];
3819 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
3820 assert(run->magic == ARENA_RUN_MAGIC);
3821 bin = run->bin;
3822 binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
3823 sizeof(arena_bin_t);
3824 assert(binind < nbins);
3825
Jason Evansb7924f52009-06-23 19:01:18 -07003826#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003827 if (opt_junk)
3828 memset(ptr, 0x5a, arena->bins[binind].reg_size);
Jason Evansb7924f52009-06-23 19:01:18 -07003829#endif
Jason Evans289053c2009-06-22 12:08:42 -07003830
3831 bin_mags = &rack->bin_mags[binind];
3832 mag = bin_mags->curmag;
3833 if (mag == NULL) {
3834 /* Create an initial magazine for this size class. */
3835 assert(bin_mags->sparemag == NULL);
3836 mag = mag_create(choose_arena(), binind);
3837 if (mag == NULL) {
3838 malloc_spin_lock(&arena->lock);
3839 arena_dalloc_small(arena, chunk, ptr, mapelm);
3840 malloc_spin_unlock(&arena->lock);
3841 return;
3842 }
3843 bin_mags->curmag = mag;
3844 }
3845
3846 if (mag->nrounds == max_rounds) {
3847 if (bin_mags->sparemag != NULL) {
3848 if (bin_mags->sparemag->nrounds < max_rounds) {
3849 /* Swap magazines. */
3850 bin_mags->curmag = bin_mags->sparemag;
3851 bin_mags->sparemag = mag;
3852 mag = bin_mags->curmag;
3853 } else {
3854 /* Unload the current magazine. */
3855 mag_unload(mag);
3856 }
3857 } else {
3858 /* Create a second magazine. */
3859 mag = mag_create(choose_arena(), binind);
3860 if (mag == NULL) {
3861 mag = rack->bin_mags[binind].curmag;
3862 mag_unload(mag);
3863 } else {
3864 bin_mags->sparemag = bin_mags->curmag;
3865 bin_mags->curmag = mag;
3866 }
3867 }
3868 assert(mag->nrounds < max_rounds);
3869 }
3870 mag->rounds[mag->nrounds] = ptr;
3871 mag->nrounds++;
3872}
3873#endif
3874
3875static void
3876arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr)
3877{
3878 /* Large allocation. */
3879 malloc_spin_lock(&arena->lock);
3880
Jason Evansb7924f52009-06-23 19:01:18 -07003881#ifdef JEMALLOC_FILL
3882#ifndef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003883 if (opt_junk)
3884#endif
Jason Evansb7924f52009-06-23 19:01:18 -07003885#endif
Jason Evans289053c2009-06-22 12:08:42 -07003886 {
Jason Evansb7924f52009-06-23 19:01:18 -07003887#if (defined(JEMALLOC_FILL) || defined(JEMALLOC_STATS))
Jason Evans289053c2009-06-22 12:08:42 -07003888 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >>
3889 PAGE_SHIFT;
3890 size_t size = chunk->map[pageind].bits & ~PAGE_MASK;
Jason Evansb7924f52009-06-23 19:01:18 -07003891#endif
Jason Evans289053c2009-06-22 12:08:42 -07003892
Jason Evansb7924f52009-06-23 19:01:18 -07003893#ifdef JEMALLOC_FILL
3894#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003895 if (opt_junk)
3896#endif
3897 memset(ptr, 0x5a, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003898#endif
3899#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003900 arena->stats.allocated_large -= size;
3901#endif
3902 }
Jason Evansb7924f52009-06-23 19:01:18 -07003903#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003904 arena->stats.ndalloc_large++;
3905#endif
3906
3907 arena_run_dalloc(arena, (arena_run_t *)ptr, true);
3908 malloc_spin_unlock(&arena->lock);
3909}
3910
3911static inline void
3912arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
3913{
3914 size_t pageind;
3915 arena_chunk_map_t *mapelm;
3916
3917 assert(arena != NULL);
3918 assert(arena->magic == ARENA_MAGIC);
3919 assert(chunk->arena == arena);
3920 assert(ptr != NULL);
3921 assert(CHUNK_ADDR2BASE(ptr) != ptr);
3922
3923 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3924 mapelm = &chunk->map[pageind];
3925 assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
3926 if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
3927 /* Small allocation. */
Jason Evansb7924f52009-06-23 19:01:18 -07003928#ifdef JEMALLOC_MAG
3929 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07003930 mag_rack_t *rack = mag_rack;
3931 if (rack == NULL) {
3932 rack = mag_rack_create(arena);
3933 if (rack == NULL) {
3934 malloc_spin_lock(&arena->lock);
3935 arena_dalloc_small(arena, chunk, ptr,
3936 mapelm);
3937 malloc_spin_unlock(&arena->lock);
3938 }
3939 mag_rack = rack;
Jason Evansb7924f52009-06-23 19:01:18 -07003940 pthread_setspecific(mag_rack_tsd, rack);
Jason Evans289053c2009-06-22 12:08:42 -07003941 }
3942 mag_rack_dalloc(rack, ptr);
3943 } else {
3944#endif
3945 malloc_spin_lock(&arena->lock);
3946 arena_dalloc_small(arena, chunk, ptr, mapelm);
3947 malloc_spin_unlock(&arena->lock);
Jason Evansb7924f52009-06-23 19:01:18 -07003948#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003949 }
3950#endif
3951 } else
3952 arena_dalloc_large(arena, chunk, ptr);
3953}
3954
3955static inline void
3956idalloc(void *ptr)
3957{
3958 arena_chunk_t *chunk;
3959
3960 assert(ptr != NULL);
3961
3962 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3963 if (chunk != ptr)
3964 arena_dalloc(chunk->arena, chunk, ptr);
3965 else
3966 huge_dalloc(ptr);
3967}
3968
3969static void
3970arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3971 size_t size, size_t oldsize)
3972{
3973
3974 assert(size < oldsize);
3975
3976 /*
3977 * Shrink the run, and make trailing pages available for other
3978 * allocations.
3979 */
Jason Evansb7924f52009-06-23 19:01:18 -07003980#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003981 arena_lock_balance(arena);
3982#else
3983 malloc_spin_lock(&arena->lock);
3984#endif
3985 arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size,
3986 true);
Jason Evansb7924f52009-06-23 19:01:18 -07003987#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003988 arena->stats.allocated_large -= oldsize - size;
3989#endif
3990 malloc_spin_unlock(&arena->lock);
3991}
3992
3993static bool
3994arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3995 size_t size, size_t oldsize)
3996{
3997 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
3998 size_t npages = oldsize >> PAGE_SHIFT;
3999
4000 assert(oldsize == (chunk->map[pageind].bits & ~PAGE_MASK));
4001
4002 /* Try to extend the run. */
4003 assert(size > oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004004#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004005 arena_lock_balance(arena);
4006#else
4007 malloc_spin_lock(&arena->lock);
4008#endif
4009 if (pageind + npages < chunk_npages && (chunk->map[pageind+npages].bits
4010 & CHUNK_MAP_ALLOCATED) == 0 && (chunk->map[pageind+npages].bits &
4011 ~PAGE_MASK) >= size - oldsize) {
4012 /*
4013 * The next run is available and sufficiently large. Split the
4014 * following run, then merge the first part with the existing
4015 * allocation.
4016 */
4017 arena_run_split(arena, (arena_run_t *)((uintptr_t)chunk +
4018 ((pageind+npages) << PAGE_SHIFT)), size - oldsize, true,
4019 false);
4020
4021 chunk->map[pageind].bits = size | CHUNK_MAP_LARGE |
4022 CHUNK_MAP_ALLOCATED;
4023 chunk->map[pageind+npages].bits = CHUNK_MAP_LARGE |
4024 CHUNK_MAP_ALLOCATED;
4025
Jason Evansb7924f52009-06-23 19:01:18 -07004026#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004027 arena->stats.allocated_large += size - oldsize;
4028#endif
4029 malloc_spin_unlock(&arena->lock);
4030 return (false);
4031 }
4032 malloc_spin_unlock(&arena->lock);
4033
4034 return (true);
4035}
4036
4037/*
4038 * Try to resize a large allocation, in order to avoid copying. This will
4039 * always fail if growing an object, and the following run is already in use.
4040 */
4041static bool
4042arena_ralloc_large(void *ptr, size_t size, size_t oldsize)
4043{
4044 size_t psize;
4045
4046 psize = PAGE_CEILING(size);
4047 if (psize == oldsize) {
4048 /* Same size class. */
Jason Evansb7924f52009-06-23 19:01:18 -07004049#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004050 if (opt_junk && size < oldsize) {
4051 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize -
4052 size);
4053 }
Jason Evansb7924f52009-06-23 19:01:18 -07004054#endif
Jason Evans289053c2009-06-22 12:08:42 -07004055 return (false);
4056 } else {
4057 arena_chunk_t *chunk;
4058 arena_t *arena;
4059
4060 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
4061 arena = chunk->arena;
4062 assert(arena->magic == ARENA_MAGIC);
4063
4064 if (psize < oldsize) {
Jason Evansb7924f52009-06-23 19:01:18 -07004065#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004066 /* Fill before shrinking in order avoid a race. */
4067 if (opt_junk) {
4068 memset((void *)((uintptr_t)ptr + size), 0x5a,
4069 oldsize - size);
4070 }
Jason Evansb7924f52009-06-23 19:01:18 -07004071#endif
Jason Evans289053c2009-06-22 12:08:42 -07004072 arena_ralloc_large_shrink(arena, chunk, ptr, psize,
4073 oldsize);
4074 return (false);
4075 } else {
4076 bool ret = arena_ralloc_large_grow(arena, chunk, ptr,
4077 psize, oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004078#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004079 if (ret == false && opt_zero) {
4080 memset((void *)((uintptr_t)ptr + oldsize), 0,
4081 size - oldsize);
4082 }
Jason Evansb7924f52009-06-23 19:01:18 -07004083#endif
Jason Evans289053c2009-06-22 12:08:42 -07004084 return (ret);
4085 }
4086 }
4087}
4088
4089static void *
4090arena_ralloc(void *ptr, size_t size, size_t oldsize)
4091{
4092 void *ret;
4093 size_t copysize;
4094
4095 /* Try to avoid moving the allocation. */
4096 if (size <= bin_maxclass) {
4097 if (oldsize <= bin_maxclass && size2bin[size] ==
4098 size2bin[oldsize])
4099 goto IN_PLACE;
4100 } else {
4101 if (oldsize > bin_maxclass && oldsize <= arena_maxclass) {
4102 assert(size > bin_maxclass);
4103 if (arena_ralloc_large(ptr, size, oldsize) == false)
4104 return (ptr);
4105 }
4106 }
4107
4108 /*
4109 * If we get here, then size and oldsize are different enough that we
4110 * need to move the object. In that case, fall back to allocating new
4111 * space and copying.
4112 */
Jason Evanscc00a152009-06-25 18:06:48 -07004113 ret = arena_malloc(size, false);
Jason Evans289053c2009-06-22 12:08:42 -07004114 if (ret == NULL)
4115 return (NULL);
4116
4117 /* Junk/zero-filling were already done by arena_malloc(). */
4118 copysize = (size < oldsize) ? size : oldsize;
4119 memcpy(ret, ptr, copysize);
4120 idalloc(ptr);
4121 return (ret);
4122IN_PLACE:
Jason Evansb7924f52009-06-23 19:01:18 -07004123#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004124 if (opt_junk && size < oldsize)
4125 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size);
4126 else if (opt_zero && size > oldsize)
4127 memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004128#endif
Jason Evans289053c2009-06-22 12:08:42 -07004129 return (ptr);
4130}
4131
4132static inline void *
4133iralloc(void *ptr, size_t size)
4134{
4135 size_t oldsize;
4136
4137 assert(ptr != NULL);
4138 assert(size != 0);
4139
4140 oldsize = isalloc(ptr);
4141
4142 if (size <= arena_maxclass)
4143 return (arena_ralloc(ptr, size, oldsize));
4144 else
4145 return (huge_ralloc(ptr, size, oldsize));
4146}
4147
4148static bool
4149arena_new(arena_t *arena)
4150{
4151 unsigned i;
4152 arena_bin_t *bin;
4153 size_t prev_run_size;
4154
4155 if (malloc_spin_init(&arena->lock))
4156 return (true);
4157
Jason Evansb7924f52009-06-23 19:01:18 -07004158#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004159 memset(&arena->stats, 0, sizeof(arena_stats_t));
4160#endif
4161
4162 /* Initialize chunks. */
4163 arena_chunk_tree_dirty_new(&arena->chunks_dirty);
4164 arena->spare = NULL;
4165
4166 arena->ndirty = 0;
4167
4168 arena_avail_tree_new(&arena->runs_avail);
4169
Jason Evansb7924f52009-06-23 19:01:18 -07004170#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004171 arena->contention = 0;
4172#endif
4173
4174 /* Initialize bins. */
4175 prev_run_size = PAGE_SIZE;
4176
4177 i = 0;
Jason Evansb7924f52009-06-23 19:01:18 -07004178#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004179 /* (2^n)-spaced tiny bins. */
4180 for (; i < ntbins; i++) {
4181 bin = &arena->bins[i];
4182 bin->runcur = NULL;
4183 arena_run_tree_new(&bin->runs);
4184
4185 bin->reg_size = (1U << (TINY_MIN_2POW + i));
4186
4187 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4188
Jason Evansb7924f52009-06-23 19:01:18 -07004189#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004190 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4191#endif
4192 }
4193#endif
4194
4195 /* Quantum-spaced bins. */
4196 for (; i < ntbins + nqbins; i++) {
4197 bin = &arena->bins[i];
4198 bin->runcur = NULL;
4199 arena_run_tree_new(&bin->runs);
4200
4201 bin->reg_size = (i - ntbins + 1) << QUANTUM_2POW;
4202
4203 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4204
Jason Evansb7924f52009-06-23 19:01:18 -07004205#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004206 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4207#endif
4208 }
4209
4210 /* Cacheline-spaced bins. */
4211 for (; i < ntbins + nqbins + ncbins; i++) {
4212 bin = &arena->bins[i];
4213 bin->runcur = NULL;
4214 arena_run_tree_new(&bin->runs);
4215
4216 bin->reg_size = cspace_min + ((i - (ntbins + nqbins)) <<
4217 CACHELINE_2POW);
4218
4219 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4220
Jason Evansb7924f52009-06-23 19:01:18 -07004221#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004222 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4223#endif
4224 }
4225
4226 /* Subpage-spaced bins. */
4227 for (; i < nbins; i++) {
4228 bin = &arena->bins[i];
4229 bin->runcur = NULL;
4230 arena_run_tree_new(&bin->runs);
4231
4232 bin->reg_size = sspace_min + ((i - (ntbins + nqbins + ncbins))
4233 << SUBPAGE_2POW);
4234
4235 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4236
Jason Evansb7924f52009-06-23 19:01:18 -07004237#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004238 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4239#endif
4240 }
4241
Jason Evansb7924f52009-06-23 19:01:18 -07004242#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004243 arena->magic = ARENA_MAGIC;
4244#endif
4245
4246 return (false);
4247}
4248
4249/* Create a new arena and insert it into the arenas array at index ind. */
4250static arena_t *
4251arenas_extend(unsigned ind)
4252{
4253 arena_t *ret;
4254
4255 /* Allocate enough space for trailing bins. */
4256 ret = (arena_t *)base_alloc(sizeof(arena_t)
4257 + (sizeof(arena_bin_t) * (nbins - 1)));
4258 if (ret != NULL && arena_new(ret) == false) {
4259 arenas[ind] = ret;
4260 return (ret);
4261 }
4262 /* Only reached if there is an OOM error. */
4263
4264 /*
4265 * OOM here is quite inconvenient to propagate, since dealing with it
4266 * would require a check for failure in the fast path. Instead, punt
4267 * by using arenas[0]. In practice, this is an extremely unlikely
4268 * failure.
4269 */
Jason Evans804c9ec2009-06-22 17:44:33 -07004270 jemalloc_message("<jemalloc>",
4271 ": Error initializing arena\n", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004272 if (opt_abort)
4273 abort();
4274
4275 return (arenas[0]);
4276}
4277
Jason Evansb7924f52009-06-23 19:01:18 -07004278#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07004279static mag_t *
4280mag_create(arena_t *arena, size_t binind)
4281{
4282 mag_t *ret;
4283
4284 if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <=
4285 bin_maxclass) {
4286 ret = arena_malloc_small(arena, sizeof(mag_t) + (sizeof(void *)
4287 * (max_rounds - 1)), false);
4288 } else {
4289 ret = imalloc(sizeof(mag_t) + (sizeof(void *) * (max_rounds -
4290 1)));
4291 }
4292 if (ret == NULL)
4293 return (NULL);
4294 ret->binind = binind;
4295 ret->nrounds = 0;
4296
4297 return (ret);
4298}
4299
4300static void
4301mag_destroy(mag_t *mag)
4302{
4303 arena_t *arena;
4304 arena_chunk_t *chunk;
4305 size_t pageind;
4306 arena_chunk_map_t *mapelm;
4307
4308 chunk = CHUNK_ADDR2BASE(mag);
4309 arena = chunk->arena;
4310 pageind = (((uintptr_t)mag - (uintptr_t)chunk) >> PAGE_SHIFT);
4311 mapelm = &chunk->map[pageind];
4312
4313 assert(mag->nrounds == 0);
4314 if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <=
4315 bin_maxclass) {
4316 malloc_spin_lock(&arena->lock);
4317 arena_dalloc_small(arena, chunk, mag, mapelm);
4318 malloc_spin_unlock(&arena->lock);
4319 } else
4320 idalloc(mag);
4321}
4322
4323static mag_rack_t *
4324mag_rack_create(arena_t *arena)
4325{
4326
4327 assert(sizeof(mag_rack_t) + (sizeof(bin_mags_t *) * (nbins - 1)) <=
4328 bin_maxclass);
4329 return (arena_malloc_small(arena, sizeof(mag_rack_t) +
4330 (sizeof(bin_mags_t) * (nbins - 1)), true));
4331}
4332
4333static void
4334mag_rack_destroy(mag_rack_t *rack)
4335{
4336 arena_t *arena;
4337 arena_chunk_t *chunk;
4338 bin_mags_t *bin_mags;
4339 size_t i, pageind;
4340 arena_chunk_map_t *mapelm;
4341
4342 for (i = 0; i < nbins; i++) {
4343 bin_mags = &rack->bin_mags[i];
4344 if (bin_mags->curmag != NULL) {
4345 assert(bin_mags->curmag->binind == i);
4346 mag_unload(bin_mags->curmag);
4347 mag_destroy(bin_mags->curmag);
4348 }
4349 if (bin_mags->sparemag != NULL) {
4350 assert(bin_mags->sparemag->binind == i);
4351 mag_unload(bin_mags->sparemag);
4352 mag_destroy(bin_mags->sparemag);
4353 }
4354 }
4355
4356 chunk = CHUNK_ADDR2BASE(rack);
4357 arena = chunk->arena;
4358 pageind = (((uintptr_t)rack - (uintptr_t)chunk) >> PAGE_SHIFT);
4359 mapelm = &chunk->map[pageind];
4360
4361 malloc_spin_lock(&arena->lock);
4362 arena_dalloc_small(arena, chunk, rack, mapelm);
4363 malloc_spin_unlock(&arena->lock);
4364}
4365#endif
4366
4367/*
4368 * End arena.
4369 */
4370/******************************************************************************/
4371/*
4372 * Begin general internal functions.
4373 */
4374
4375static void *
4376huge_malloc(size_t size, bool zero)
4377{
4378 void *ret;
4379 size_t csize;
4380 extent_node_t *node;
4381
4382 /* Allocate one or more contiguous chunks for this request. */
4383
4384 csize = CHUNK_CEILING(size);
4385 if (csize == 0) {
4386 /* size is large enough to cause size_t wrap-around. */
4387 return (NULL);
4388 }
4389
4390 /* Allocate an extent node with which to track the chunk. */
4391 node = base_node_alloc();
4392 if (node == NULL)
4393 return (NULL);
4394
4395 ret = chunk_alloc(csize, zero);
4396 if (ret == NULL) {
4397 base_node_dealloc(node);
4398 return (NULL);
4399 }
4400
4401 /* Insert node into huge. */
4402 node->addr = ret;
4403 node->size = csize;
4404
4405 malloc_mutex_lock(&huge_mtx);
4406 extent_tree_ad_insert(&huge, node);
Jason Evansb7924f52009-06-23 19:01:18 -07004407#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004408 huge_nmalloc++;
4409 huge_allocated += csize;
4410#endif
4411 malloc_mutex_unlock(&huge_mtx);
4412
Jason Evansb7924f52009-06-23 19:01:18 -07004413#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004414 if (zero == false) {
4415 if (opt_junk)
4416 memset(ret, 0xa5, csize);
4417 else if (opt_zero)
4418 memset(ret, 0, csize);
4419 }
Jason Evansb7924f52009-06-23 19:01:18 -07004420#endif
Jason Evans289053c2009-06-22 12:08:42 -07004421
4422 return (ret);
4423}
4424
4425/* Only handles large allocations that require more than chunk alignment. */
4426static void *
4427huge_palloc(size_t alignment, size_t size)
4428{
4429 void *ret;
4430 size_t alloc_size, chunk_size, offset;
4431 extent_node_t *node;
4432
4433 /*
4434 * This allocation requires alignment that is even larger than chunk
4435 * alignment. This means that huge_malloc() isn't good enough.
4436 *
4437 * Allocate almost twice as many chunks as are demanded by the size or
4438 * alignment, in order to assure the alignment can be achieved, then
4439 * unmap leading and trailing chunks.
4440 */
4441 assert(alignment >= chunksize);
4442
4443 chunk_size = CHUNK_CEILING(size);
4444
4445 if (size >= alignment)
4446 alloc_size = chunk_size + alignment - chunksize;
4447 else
4448 alloc_size = (alignment << 1) - chunksize;
4449
4450 /* Allocate an extent node with which to track the chunk. */
4451 node = base_node_alloc();
4452 if (node == NULL)
4453 return (NULL);
4454
4455 ret = chunk_alloc(alloc_size, false);
4456 if (ret == NULL) {
4457 base_node_dealloc(node);
4458 return (NULL);
4459 }
4460
4461 offset = (uintptr_t)ret & (alignment - 1);
4462 assert((offset & chunksize_mask) == 0);
4463 assert(offset < alloc_size);
4464 if (offset == 0) {
4465 /* Trim trailing space. */
4466 chunk_dealloc((void *)((uintptr_t)ret + chunk_size), alloc_size
4467 - chunk_size);
4468 } else {
4469 size_t trailsize;
4470
4471 /* Trim leading space. */
4472 chunk_dealloc(ret, alignment - offset);
4473
4474 ret = (void *)((uintptr_t)ret + (alignment - offset));
4475
4476 trailsize = alloc_size - (alignment - offset) - chunk_size;
4477 if (trailsize != 0) {
4478 /* Trim trailing space. */
4479 assert(trailsize < alloc_size);
4480 chunk_dealloc((void *)((uintptr_t)ret + chunk_size),
4481 trailsize);
4482 }
4483 }
4484
4485 /* Insert node into huge. */
4486 node->addr = ret;
4487 node->size = chunk_size;
4488
4489 malloc_mutex_lock(&huge_mtx);
4490 extent_tree_ad_insert(&huge, node);
Jason Evansb7924f52009-06-23 19:01:18 -07004491#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004492 huge_nmalloc++;
4493 huge_allocated += chunk_size;
4494#endif
4495 malloc_mutex_unlock(&huge_mtx);
4496
Jason Evansb7924f52009-06-23 19:01:18 -07004497#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004498 if (opt_junk)
4499 memset(ret, 0xa5, chunk_size);
4500 else if (opt_zero)
4501 memset(ret, 0, chunk_size);
Jason Evansb7924f52009-06-23 19:01:18 -07004502#endif
Jason Evans289053c2009-06-22 12:08:42 -07004503
4504 return (ret);
4505}
4506
4507static void *
4508huge_ralloc(void *ptr, size_t size, size_t oldsize)
4509{
4510 void *ret;
4511 size_t copysize;
4512
4513 /* Avoid moving the allocation if the size class would not change. */
4514 if (oldsize > arena_maxclass &&
4515 CHUNK_CEILING(size) == CHUNK_CEILING(oldsize)) {
Jason Evansb7924f52009-06-23 19:01:18 -07004516#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004517 if (opt_junk && size < oldsize) {
4518 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize
4519 - size);
4520 } else if (opt_zero && size > oldsize) {
4521 memset((void *)((uintptr_t)ptr + oldsize), 0, size
4522 - oldsize);
4523 }
Jason Evansb7924f52009-06-23 19:01:18 -07004524#endif
Jason Evans289053c2009-06-22 12:08:42 -07004525 return (ptr);
4526 }
4527
4528 /*
4529 * If we get here, then size and oldsize are different enough that we
4530 * need to use a different size class. In that case, fall back to
4531 * allocating new space and copying.
4532 */
4533 ret = huge_malloc(size, false);
4534 if (ret == NULL)
4535 return (NULL);
4536
4537 copysize = (size < oldsize) ? size : oldsize;
4538 memcpy(ret, ptr, copysize);
4539 idalloc(ptr);
4540 return (ret);
4541}
4542
4543static void
4544huge_dalloc(void *ptr)
4545{
4546 extent_node_t *node, key;
4547
4548 malloc_mutex_lock(&huge_mtx);
4549
4550 /* Extract from tree of huge allocations. */
4551 key.addr = ptr;
4552 node = extent_tree_ad_search(&huge, &key);
4553 assert(node != NULL);
4554 assert(node->addr == ptr);
4555 extent_tree_ad_remove(&huge, node);
4556
Jason Evansb7924f52009-06-23 19:01:18 -07004557#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004558 huge_ndalloc++;
4559 huge_allocated -= node->size;
4560#endif
4561
4562 malloc_mutex_unlock(&huge_mtx);
4563
4564 /* Unmap chunk. */
Jason Evansb7924f52009-06-23 19:01:18 -07004565#ifdef JEMALLOC_FILL
4566#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07004567 if (opt_dss && opt_junk)
4568 memset(node->addr, 0x5a, node->size);
4569#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004570#endif
Jason Evans289053c2009-06-22 12:08:42 -07004571 chunk_dealloc(node->addr, node->size);
4572
4573 base_node_dealloc(node);
4574}
4575
4576static void
4577malloc_print_stats(void)
4578{
4579
4580 if (opt_print_stats) {
4581 char s[UMAX2S_BUFSIZE];
Jason Evans804c9ec2009-06-22 17:44:33 -07004582 jemalloc_message("___ Begin jemalloc statistics ___\n", "", "",
Jason Evans289053c2009-06-22 12:08:42 -07004583 "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004584 jemalloc_message("Assertions ",
Jason Evans289053c2009-06-22 12:08:42 -07004585#ifdef NDEBUG
4586 "disabled",
4587#else
4588 "enabled",
4589#endif
4590 "\n", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004591 jemalloc_message("Boolean JEMALLOC_OPTIONS: ",
Jason Evans289053c2009-06-22 12:08:42 -07004592 opt_abort ? "A" : "a", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004593#ifdef JEMALLOC_DSS
Jason Evans804c9ec2009-06-22 17:44:33 -07004594 jemalloc_message(opt_dss ? "D" : "d", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004595#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004596#ifdef JEMALLOC_MAG
Jason Evans804c9ec2009-06-22 17:44:33 -07004597 jemalloc_message(opt_mag ? "G" : "g", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004598#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004599#ifdef JEMALLOC_FILL
Jason Evans804c9ec2009-06-22 17:44:33 -07004600 jemalloc_message(opt_junk ? "J" : "j", "", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004601#endif
4602#ifdef JEMALLOC_DSS
Jason Evans804c9ec2009-06-22 17:44:33 -07004603 jemalloc_message(opt_mmap ? "M" : "m", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004604#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004605 jemalloc_message("P", "", "", "");
4606#ifdef JEMALLOC_STATS
4607 jemalloc_message(opt_utrace ? "U" : "u", "", "", "");
4608#endif
4609#ifdef JEMALLOC_SYSV
4610 jemalloc_message(opt_sysv ? "V" : "v", "", "", "");
4611#endif
4612#ifdef JEMALLOC_XMALLOC
4613 jemalloc_message(opt_xmalloc ? "X" : "x", "", "", "");
4614#endif
4615#ifdef JEMALLOC_FILL
4616 jemalloc_message(opt_zero ? "Z" : "z", "", "", "");
4617#endif
4618 jemalloc_message("\n", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004619
Jason Evans804c9ec2009-06-22 17:44:33 -07004620 jemalloc_message("CPUs: ", umax2s(ncpus, s), "\n", "");
4621 jemalloc_message("Max arenas: ", umax2s(narenas, s), "\n", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004622#ifdef JEMALLOC_BALANCE
Jason Evans804c9ec2009-06-22 17:44:33 -07004623 jemalloc_message("Arena balance threshold: ",
Jason Evans289053c2009-06-22 12:08:42 -07004624 umax2s(opt_balance_threshold, s), "\n", "");
4625#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004626 jemalloc_message("Pointer size: ", umax2s(sizeof(void *), s),
Jason Evans289053c2009-06-22 12:08:42 -07004627 "\n", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004628 jemalloc_message("Quantum size: ", umax2s(QUANTUM, s), "\n",
4629 "");
4630 jemalloc_message("Cacheline size (assumed): ",
4631 umax2s(CACHELINE, s), "\n", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004632#ifdef JEMALLOC_TINY
Jason Evans804c9ec2009-06-22 17:44:33 -07004633 jemalloc_message("Tiny 2^n-spaced sizes: [", umax2s((1U <<
Jason Evans289053c2009-06-22 12:08:42 -07004634 TINY_MIN_2POW), s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004635 jemalloc_message(umax2s((qspace_min >> 1), s), "]\n", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004636#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004637 jemalloc_message("Quantum-spaced sizes: [", umax2s(qspace_min,
Jason Evans289053c2009-06-22 12:08:42 -07004638 s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004639 jemalloc_message(umax2s(qspace_max, s), "]\n", "", "");
4640 jemalloc_message("Cacheline-spaced sizes: [",
4641 umax2s(cspace_min, s), "..", "");
4642 jemalloc_message(umax2s(cspace_max, s), "]\n", "", "");
4643 jemalloc_message("Subpage-spaced sizes: [", umax2s(sspace_min,
Jason Evans289053c2009-06-22 12:08:42 -07004644 s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004645 jemalloc_message(umax2s(sspace_max, s), "]\n", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004646#ifdef JEMALLOC_MAG
Jason Evans804c9ec2009-06-22 17:44:33 -07004647 jemalloc_message("Rounds per magazine: ", umax2s(max_rounds,
4648 s), "\n", "");
Jason Evans289053c2009-06-22 12:08:42 -07004649#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004650 jemalloc_message("Max dirty pages per arena: ",
Jason Evans289053c2009-06-22 12:08:42 -07004651 umax2s(opt_dirty_max, s), "\n", "");
4652
Jason Evans804c9ec2009-06-22 17:44:33 -07004653 jemalloc_message("Chunk size: ", umax2s(chunksize, s), "", "");
4654 jemalloc_message(" (2^", umax2s(opt_chunk_2pow, s), ")\n", "");
Jason Evans289053c2009-06-22 12:08:42 -07004655
Jason Evansb7924f52009-06-23 19:01:18 -07004656#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004657 {
4658 size_t allocated, mapped;
Jason Evansb7924f52009-06-23 19:01:18 -07004659#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004660 uint64_t nbalance = 0;
4661#endif
4662 unsigned i;
4663 arena_t *arena;
4664
4665 /* Calculate and print allocated/mapped stats. */
4666
4667 /* arenas. */
4668 for (i = 0, allocated = 0; i < narenas; i++) {
4669 if (arenas[i] != NULL) {
4670 malloc_spin_lock(&arenas[i]->lock);
4671 allocated +=
4672 arenas[i]->stats.allocated_small;
4673 allocated +=
4674 arenas[i]->stats.allocated_large;
Jason Evansb7924f52009-06-23 19:01:18 -07004675#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004676 nbalance += arenas[i]->stats.nbalance;
4677#endif
4678 malloc_spin_unlock(&arenas[i]->lock);
4679 }
4680 }
4681
4682 /* huge/base. */
4683 malloc_mutex_lock(&huge_mtx);
4684 allocated += huge_allocated;
4685 mapped = stats_chunks.curchunks * chunksize;
4686 malloc_mutex_unlock(&huge_mtx);
4687
4688 malloc_mutex_lock(&base_mtx);
4689 mapped += base_mapped;
4690 malloc_mutex_unlock(&base_mtx);
4691
4692 malloc_printf("Allocated: %zu, mapped: %zu\n",
4693 allocated, mapped);
4694
Jason Evansb7924f52009-06-23 19:01:18 -07004695#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004696 malloc_printf("Arena balance reassignments: %llu\n",
4697 nbalance);
4698#endif
4699
4700 /* Print chunk stats. */
4701 {
4702 chunk_stats_t chunks_stats;
4703
4704 malloc_mutex_lock(&huge_mtx);
4705 chunks_stats = stats_chunks;
4706 malloc_mutex_unlock(&huge_mtx);
4707
4708 malloc_printf("chunks: nchunks "
4709 "highchunks curchunks\n");
4710 malloc_printf(" %13llu%13lu%13lu\n",
4711 chunks_stats.nchunks,
4712 chunks_stats.highchunks,
4713 chunks_stats.curchunks);
4714 }
4715
4716 /* Print chunk stats. */
4717 malloc_printf(
4718 "huge: nmalloc ndalloc allocated\n");
4719 malloc_printf(" %12llu %12llu %12zu\n",
4720 huge_nmalloc, huge_ndalloc, huge_allocated);
4721
4722 /* Print stats for each arena. */
4723 for (i = 0; i < narenas; i++) {
4724 arena = arenas[i];
4725 if (arena != NULL) {
4726 malloc_printf(
4727 "\narenas[%u]:\n", i);
4728 malloc_spin_lock(&arena->lock);
4729 stats_print(arena);
4730 malloc_spin_unlock(&arena->lock);
4731 }
4732 }
4733 }
Jason Evansb7924f52009-06-23 19:01:18 -07004734#endif /* #ifdef JEMALLOC_STATS */
Jason Evans804c9ec2009-06-22 17:44:33 -07004735 jemalloc_message("--- End jemalloc statistics ---\n", "", "",
4736 "");
Jason Evans289053c2009-06-22 12:08:42 -07004737 }
4738}
4739
Jason Evansb7924f52009-06-23 19:01:18 -07004740#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004741static void
4742size2bin_validate(void)
4743{
4744 size_t i, size, binind;
4745
4746 assert(size2bin[0] == 0xffU);
4747 i = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07004748# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004749 /* Tiny. */
4750 for (; i < (1U << TINY_MIN_2POW); i++) {
4751 size = pow2_ceil(1U << TINY_MIN_2POW);
4752 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4753 assert(size2bin[i] == binind);
4754 }
4755 for (; i < qspace_min; i++) {
4756 size = pow2_ceil(i);
4757 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4758 assert(size2bin[i] == binind);
4759 }
4760# endif
4761 /* Quantum-spaced. */
4762 for (; i <= qspace_max; i++) {
4763 size = QUANTUM_CEILING(i);
4764 binind = ntbins + (size >> QUANTUM_2POW) - 1;
4765 assert(size2bin[i] == binind);
4766 }
4767 /* Cacheline-spaced. */
4768 for (; i <= cspace_max; i++) {
4769 size = CACHELINE_CEILING(i);
4770 binind = ntbins + nqbins + ((size - cspace_min) >>
4771 CACHELINE_2POW);
4772 assert(size2bin[i] == binind);
4773 }
4774 /* Sub-page. */
4775 for (; i <= sspace_max; i++) {
4776 size = SUBPAGE_CEILING(i);
4777 binind = ntbins + nqbins + ncbins + ((size - sspace_min)
4778 >> SUBPAGE_2POW);
4779 assert(size2bin[i] == binind);
4780 }
4781}
4782#endif
4783
4784static bool
4785size2bin_init(void)
4786{
4787
4788 if (opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT
4789 || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT)
4790 return (size2bin_init_hard());
4791
4792 size2bin = const_size2bin;
Jason Evansb7924f52009-06-23 19:01:18 -07004793#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004794 assert(sizeof(const_size2bin) == bin_maxclass + 1);
4795 size2bin_validate();
4796#endif
4797 return (false);
4798}
4799
4800static bool
4801size2bin_init_hard(void)
4802{
4803 size_t i, size, binind;
4804 uint8_t *custom_size2bin;
4805
4806 assert(opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT
4807 || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT);
4808
4809 custom_size2bin = (uint8_t *)base_alloc(bin_maxclass + 1);
4810 if (custom_size2bin == NULL)
4811 return (true);
4812
4813 custom_size2bin[0] = 0xffU;
4814 i = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07004815#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004816 /* Tiny. */
4817 for (; i < (1U << TINY_MIN_2POW); i++) {
4818 size = pow2_ceil(1U << TINY_MIN_2POW);
4819 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4820 custom_size2bin[i] = binind;
4821 }
4822 for (; i < qspace_min; i++) {
4823 size = pow2_ceil(i);
4824 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4825 custom_size2bin[i] = binind;
4826 }
4827#endif
4828 /* Quantum-spaced. */
4829 for (; i <= qspace_max; i++) {
4830 size = QUANTUM_CEILING(i);
4831 binind = ntbins + (size >> QUANTUM_2POW) - 1;
4832 custom_size2bin[i] = binind;
4833 }
4834 /* Cacheline-spaced. */
4835 for (; i <= cspace_max; i++) {
4836 size = CACHELINE_CEILING(i);
4837 binind = ntbins + nqbins + ((size - cspace_min) >>
4838 CACHELINE_2POW);
4839 custom_size2bin[i] = binind;
4840 }
4841 /* Sub-page. */
4842 for (; i <= sspace_max; i++) {
4843 size = SUBPAGE_CEILING(i);
4844 binind = ntbins + nqbins + ncbins + ((size - sspace_min) >>
4845 SUBPAGE_2POW);
4846 custom_size2bin[i] = binind;
4847 }
4848
4849 size2bin = custom_size2bin;
Jason Evansb7924f52009-06-23 19:01:18 -07004850#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004851 size2bin_validate();
4852#endif
4853 return (false);
4854}
4855
Jason Evansc9658dd2009-06-22 14:44:08 -07004856static unsigned
4857malloc_ncpus(void)
4858{
4859 unsigned ret;
Jason Evansb7924f52009-06-23 19:01:18 -07004860 long result;
Jason Evansc9658dd2009-06-22 14:44:08 -07004861
Jason Evansb7924f52009-06-23 19:01:18 -07004862 result = sysconf(_SC_NPROCESSORS_ONLN);
4863 if (result == -1) {
4864 /* Error. */
4865 ret = 1;
Jason Evansc9658dd2009-06-22 14:44:08 -07004866 }
Jason Evansb7924f52009-06-23 19:01:18 -07004867 ret = (unsigned)result;
Jason Evansc9658dd2009-06-22 14:44:08 -07004868
4869 return (ret);
4870}
Jason Evansb7924f52009-06-23 19:01:18 -07004871
Jason Evans289053c2009-06-22 12:08:42 -07004872/*
4873 * FreeBSD's pthreads implementation calls malloc(3), so the malloc
4874 * implementation has to take pains to avoid infinite recursion during
4875 * initialization.
4876 */
4877static inline bool
4878malloc_init(void)
4879{
4880
4881 if (malloc_initialized == false)
4882 return (malloc_init_hard());
4883
4884 return (false);
4885}
4886
4887static bool
4888malloc_init_hard(void)
4889{
4890 unsigned i;
4891 int linklen;
4892 char buf[PATH_MAX + 1];
4893 const char *opts;
Jason Evansb7924f52009-06-23 19:01:18 -07004894 arena_t *init_arenas[1];
Jason Evans289053c2009-06-22 12:08:42 -07004895
4896 malloc_mutex_lock(&init_lock);
Jason Evansb7924f52009-06-23 19:01:18 -07004897 if (malloc_initialized || malloc_initializer == pthread_self()) {
Jason Evans289053c2009-06-22 12:08:42 -07004898 /*
4899 * Another thread initialized the allocator before this one
Jason Evansb7924f52009-06-23 19:01:18 -07004900 * acquired init_lock, or this thread is the inializing thread,
4901 * and it is recursively allocating.
Jason Evans289053c2009-06-22 12:08:42 -07004902 */
4903 malloc_mutex_unlock(&init_lock);
4904 return (false);
4905 }
Jason Evansb7924f52009-06-23 19:01:18 -07004906 if (malloc_initializer != (unsigned long)0) {
4907 /* Busy-wait until the initializing thread completes. */
4908 do {
4909 malloc_mutex_unlock(&init_lock);
4910 CPU_SPINWAIT;
4911 malloc_mutex_lock(&init_lock);
4912 } while (malloc_initialized == false);
4913 return (false);
4914 }
Jason Evans289053c2009-06-22 12:08:42 -07004915
Jason Evansb7924f52009-06-23 19:01:18 -07004916#ifdef DYNAMIC_PAGE_SHIFT
Jason Evansc9658dd2009-06-22 14:44:08 -07004917 /* Get page size. */
4918 {
4919 long result;
4920
4921 result = sysconf(_SC_PAGESIZE);
4922 assert(result != -1);
Jason Evansb7924f52009-06-23 19:01:18 -07004923 pagesize = (unsigned)result;
4924
4925 /*
4926 * We assume that pagesize is a power of 2 when calculating
4927 * pagesize_mask and pagesize_2pow.
4928 */
4929 assert(((result - 1) & result) == 0);
4930 pagesize_mask = result - 1;
4931 pagesize_2pow = ffs((int)result) - 1;
Jason Evans289053c2009-06-22 12:08:42 -07004932 }
Jason Evansc9658dd2009-06-22 14:44:08 -07004933#endif
Jason Evans289053c2009-06-22 12:08:42 -07004934
4935 for (i = 0; i < 3; i++) {
4936 unsigned j;
4937
4938 /* Get runtime configuration. */
4939 switch (i) {
4940 case 0:
Jason Evans804c9ec2009-06-22 17:44:33 -07004941 if ((linklen = readlink("/etc/jemalloc.conf", buf,
Jason Evans289053c2009-06-22 12:08:42 -07004942 sizeof(buf) - 1)) != -1) {
4943 /*
Jason Evans804c9ec2009-06-22 17:44:33 -07004944 * Use the contents of the "/etc/jemalloc.conf"
Jason Evans289053c2009-06-22 12:08:42 -07004945 * symbolic link's name.
4946 */
4947 buf[linklen] = '\0';
4948 opts = buf;
4949 } else {
4950 /* No configuration specified. */
4951 buf[0] = '\0';
4952 opts = buf;
4953 }
4954 break;
4955 case 1:
Jason Evansb7924f52009-06-23 19:01:18 -07004956 if ((opts = getenv("JEMALLOC_OPTIONS")) != NULL) {
Jason Evans289053c2009-06-22 12:08:42 -07004957 /*
4958 * Do nothing; opts is already initialized to
Jason Evans804c9ec2009-06-22 17:44:33 -07004959 * the value of the JEMALLOC_OPTIONS
4960 * environment variable.
Jason Evans289053c2009-06-22 12:08:42 -07004961 */
4962 } else {
4963 /* No configuration specified. */
4964 buf[0] = '\0';
4965 opts = buf;
4966 }
4967 break;
4968 case 2:
Jason Evans804c9ec2009-06-22 17:44:33 -07004969 if (jemalloc_options != NULL) {
Jason Evans289053c2009-06-22 12:08:42 -07004970 /*
4971 * Use options that were compiled into the
4972 * program.
4973 */
Jason Evans804c9ec2009-06-22 17:44:33 -07004974 opts = jemalloc_options;
Jason Evans289053c2009-06-22 12:08:42 -07004975 } else {
4976 /* No configuration specified. */
4977 buf[0] = '\0';
4978 opts = buf;
4979 }
4980 break;
4981 default:
4982 /* NOTREACHED */
4983 assert(false);
Jason Evansb7924f52009-06-23 19:01:18 -07004984 buf[0] = '\0';
4985 opts = buf;
Jason Evans289053c2009-06-22 12:08:42 -07004986 }
4987
4988 for (j = 0; opts[j] != '\0'; j++) {
4989 unsigned k, nreps;
4990 bool nseen;
4991
4992 /* Parse repetition count, if any. */
4993 for (nreps = 0, nseen = false;; j++, nseen = true) {
4994 switch (opts[j]) {
4995 case '0': case '1': case '2': case '3':
4996 case '4': case '5': case '6': case '7':
4997 case '8': case '9':
4998 nreps *= 10;
4999 nreps += opts[j] - '0';
5000 break;
5001 default:
5002 goto MALLOC_OUT;
5003 }
5004 }
5005MALLOC_OUT:
5006 if (nseen == false)
5007 nreps = 1;
5008
5009 for (k = 0; k < nreps; k++) {
5010 switch (opts[j]) {
5011 case 'a':
5012 opt_abort = false;
5013 break;
5014 case 'A':
5015 opt_abort = true;
5016 break;
5017 case 'b':
Jason Evansb7924f52009-06-23 19:01:18 -07005018#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005019 opt_balance_threshold >>= 1;
5020#endif
5021 break;
5022 case 'B':
Jason Evansb7924f52009-06-23 19:01:18 -07005023#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005024 if (opt_balance_threshold == 0)
5025 opt_balance_threshold = 1;
5026 else if ((opt_balance_threshold << 1)
5027 > opt_balance_threshold)
5028 opt_balance_threshold <<= 1;
5029#endif
5030 break;
5031 case 'c':
5032 if (opt_cspace_max_2pow - 1 >
5033 opt_qspace_max_2pow &&
5034 opt_cspace_max_2pow >
5035 CACHELINE_2POW)
5036 opt_cspace_max_2pow--;
5037 break;
5038 case 'C':
5039 if (opt_cspace_max_2pow < PAGE_SHIFT
5040 - 1)
5041 opt_cspace_max_2pow++;
5042 break;
5043 case 'd':
Jason Evansb7924f52009-06-23 19:01:18 -07005044#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005045 opt_dss = false;
5046#endif
5047 break;
5048 case 'D':
Jason Evansb7924f52009-06-23 19:01:18 -07005049#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005050 opt_dss = true;
5051#endif
5052 break;
5053 case 'f':
5054 opt_dirty_max >>= 1;
5055 break;
5056 case 'F':
5057 if (opt_dirty_max == 0)
5058 opt_dirty_max = 1;
5059 else if ((opt_dirty_max << 1) != 0)
5060 opt_dirty_max <<= 1;
5061 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005062#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005063 case 'g':
5064 opt_mag = false;
5065 break;
5066 case 'G':
5067 opt_mag = true;
5068 break;
5069#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005070#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07005071 case 'j':
5072 opt_junk = false;
5073 break;
5074 case 'J':
5075 opt_junk = true;
5076 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005077#endif
Jason Evans289053c2009-06-22 12:08:42 -07005078 case 'k':
5079 /*
5080 * Chunks always require at least one
5081 * header page, so chunks can never be
5082 * smaller than two pages.
5083 */
5084 if (opt_chunk_2pow > PAGE_SHIFT + 1)
5085 opt_chunk_2pow--;
5086 break;
5087 case 'K':
5088 if (opt_chunk_2pow + 1 <
5089 (sizeof(size_t) << 3))
5090 opt_chunk_2pow++;
5091 break;
5092 case 'm':
Jason Evansb7924f52009-06-23 19:01:18 -07005093#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005094 opt_mmap = false;
5095#endif
5096 break;
5097 case 'M':
Jason Evansb7924f52009-06-23 19:01:18 -07005098#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005099 opt_mmap = true;
5100#endif
5101 break;
5102 case 'n':
5103 opt_narenas_lshift--;
5104 break;
5105 case 'N':
5106 opt_narenas_lshift++;
5107 break;
5108 case 'p':
5109 opt_print_stats = false;
5110 break;
5111 case 'P':
5112 opt_print_stats = true;
5113 break;
5114 case 'q':
5115 if (opt_qspace_max_2pow > QUANTUM_2POW)
5116 opt_qspace_max_2pow--;
5117 break;
5118 case 'Q':
5119 if (opt_qspace_max_2pow + 1 <
5120 opt_cspace_max_2pow)
5121 opt_qspace_max_2pow++;
5122 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005123#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005124 case 'R':
5125 if (opt_mag_size_2pow + 1 < (8U <<
5126 SIZEOF_PTR_2POW))
5127 opt_mag_size_2pow++;
5128 break;
5129 case 'r':
5130 /*
5131 * Make sure there's always at least
5132 * one round per magazine.
5133 */
5134 if ((1U << (opt_mag_size_2pow-1)) >=
5135 sizeof(mag_t))
5136 opt_mag_size_2pow--;
5137 break;
5138#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005139#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005140 case 'u':
5141 opt_utrace = false;
5142 break;
5143 case 'U':
5144 opt_utrace = true;
5145 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005146#endif
5147#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005148 case 'v':
5149 opt_sysv = false;
5150 break;
5151 case 'V':
5152 opt_sysv = true;
5153 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005154#endif
5155#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005156 case 'x':
5157 opt_xmalloc = false;
5158 break;
5159 case 'X':
5160 opt_xmalloc = true;
5161 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005162#endif
5163#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07005164 case 'z':
5165 opt_zero = false;
5166 break;
5167 case 'Z':
5168 opt_zero = true;
5169 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005170#endif
Jason Evans289053c2009-06-22 12:08:42 -07005171 default: {
5172 char cbuf[2];
5173
5174 cbuf[0] = opts[j];
5175 cbuf[1] = '\0';
Jason Evans804c9ec2009-06-22 17:44:33 -07005176 jemalloc_message("<jemalloc>",
5177 ": Unsupported character "
Jason Evans289053c2009-06-22 12:08:42 -07005178 "in malloc options: '", cbuf,
5179 "'\n");
5180 }
5181 }
5182 }
5183 }
5184 }
5185
Jason Evansb7924f52009-06-23 19:01:18 -07005186#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005187 /* Make sure that there is some method for acquiring memory. */
5188 if (opt_dss == false && opt_mmap == false)
5189 opt_mmap = true;
5190#endif
5191
5192 /* Take care to call atexit() only once. */
5193 if (opt_print_stats) {
5194 /* Print statistics at exit. */
5195 atexit(malloc_print_stats);
5196 }
5197
Jason Evansc9658dd2009-06-22 14:44:08 -07005198 /* Register fork handlers. */
Jason Evans804c9ec2009-06-22 17:44:33 -07005199 pthread_atfork(jemalloc_prefork, jemalloc_postfork, jemalloc_postfork);
Jason Evansc9658dd2009-06-22 14:44:08 -07005200
Jason Evansb7924f52009-06-23 19:01:18 -07005201#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005202 /*
5203 * Calculate the actual number of rounds per magazine, taking into
5204 * account header overhead.
5205 */
5206 max_rounds = (1LLU << (opt_mag_size_2pow - SIZEOF_PTR_2POW)) -
5207 (sizeof(mag_t) >> SIZEOF_PTR_2POW) + 1;
5208#endif
5209
5210 /* Set variables according to the value of opt_[qc]space_max_2pow. */
5211 qspace_max = (1U << opt_qspace_max_2pow);
5212 cspace_min = CACHELINE_CEILING(qspace_max);
5213 if (cspace_min == qspace_max)
5214 cspace_min += CACHELINE;
5215 cspace_max = (1U << opt_cspace_max_2pow);
5216 sspace_min = SUBPAGE_CEILING(cspace_max);
5217 if (sspace_min == cspace_max)
5218 sspace_min += SUBPAGE;
5219 assert(sspace_min < PAGE_SIZE);
5220 sspace_max = PAGE_SIZE - SUBPAGE;
5221
Jason Evansb7924f52009-06-23 19:01:18 -07005222#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07005223 assert(QUANTUM_2POW >= TINY_MIN_2POW);
5224#endif
5225 assert(ntbins <= QUANTUM_2POW);
5226 nqbins = qspace_max >> QUANTUM_2POW;
5227 ncbins = ((cspace_max - cspace_min) >> CACHELINE_2POW) + 1;
5228 nsbins = ((sspace_max - sspace_min) >> SUBPAGE_2POW) + 1;
5229 nbins = ntbins + nqbins + ncbins + nsbins;
5230
5231 if (size2bin_init()) {
5232 malloc_mutex_unlock(&init_lock);
5233 return (true);
5234 }
5235
5236 /* Set variables according to the value of opt_chunk_2pow. */
5237 chunksize = (1LU << opt_chunk_2pow);
5238 chunksize_mask = chunksize - 1;
5239 chunk_npages = (chunksize >> PAGE_SHIFT);
5240 {
5241 size_t header_size;
5242
5243 /*
5244 * Compute the header size such that it is large enough to
5245 * contain the page map.
5246 */
5247 header_size = sizeof(arena_chunk_t) +
5248 (sizeof(arena_chunk_map_t) * (chunk_npages - 1));
5249 arena_chunk_header_npages = (header_size >> PAGE_SHIFT) +
5250 ((header_size & PAGE_MASK) != 0);
5251 }
5252 arena_maxclass = chunksize - (arena_chunk_header_npages <<
5253 PAGE_SHIFT);
5254
5255 UTRACE(0, 0, 0);
5256
Jason Evansb7924f52009-06-23 19:01:18 -07005257#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005258 memset(&stats_chunks, 0, sizeof(chunk_stats_t));
5259#endif
5260
5261 /* Various sanity checks that regard configuration. */
5262 assert(chunksize >= PAGE_SIZE);
5263
5264 /* Initialize chunks data. */
Jason Evansc9658dd2009-06-22 14:44:08 -07005265 if (malloc_mutex_init(&huge_mtx)) {
5266 malloc_mutex_unlock(&init_lock);
5267 return (true);
5268 }
Jason Evans289053c2009-06-22 12:08:42 -07005269 extent_tree_ad_new(&huge);
Jason Evansb7924f52009-06-23 19:01:18 -07005270#ifdef JEMALLOC_DSS
Jason Evansc9658dd2009-06-22 14:44:08 -07005271 if (malloc_mutex_init(&dss_mtx)) {
5272 malloc_mutex_unlock(&init_lock);
5273 return (true);
5274 }
Jason Evans289053c2009-06-22 12:08:42 -07005275 dss_base = sbrk(0);
5276 dss_prev = dss_base;
5277 dss_max = dss_base;
5278 extent_tree_szad_new(&dss_chunks_szad);
5279 extent_tree_ad_new(&dss_chunks_ad);
5280#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005281#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005282 huge_nmalloc = 0;
5283 huge_ndalloc = 0;
5284 huge_allocated = 0;
5285#endif
5286
5287 /* Initialize base allocation data structures. */
Jason Evansb7924f52009-06-23 19:01:18 -07005288#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005289 base_mapped = 0;
5290#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005291#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005292 /*
5293 * Allocate a base chunk here, since it doesn't actually have to be
5294 * chunk-aligned. Doing this before allocating any other chunks allows
5295 * the use of space that would otherwise be wasted.
5296 */
5297 if (opt_dss)
5298 base_pages_alloc(0);
5299#endif
5300 base_nodes = NULL;
Jason Evansc9658dd2009-06-22 14:44:08 -07005301 if (malloc_mutex_init(&base_mtx)) {
5302 malloc_mutex_unlock(&init_lock);
5303 return (true);
5304 }
Jason Evans289053c2009-06-22 12:08:42 -07005305
Jason Evansb7924f52009-06-23 19:01:18 -07005306 /*
5307 * Create enough scaffolding to allow recursive allocation in
5308 * malloc_ncpus().
5309 */
5310 narenas = 1;
5311 arenas = init_arenas;
5312 memset(arenas, 0, sizeof(arena_t *) * narenas);
5313
5314 /*
5315 * Initialize one arena here. The rest are lazily created in
5316 * choose_arena_hard().
5317 */
5318 arenas_extend(0);
5319 if (arenas[0] == NULL) {
5320 malloc_mutex_unlock(&init_lock);
5321 return (true);
5322 }
5323
5324#ifndef NO_TLS
5325 /*
5326 * Assign the initial arena to the initial thread, in order to avoid
5327 * spurious creation of an extra arena if the application switches to
5328 * threaded mode.
5329 */
5330 arenas_map = arenas[0];
5331#endif
5332
5333#ifdef JEMALLOC_MAG
5334 if (pthread_key_create(&mag_rack_tsd, thread_cleanup) != 0) {
5335 jemalloc_message("<jemalloc>",
5336 ": Error in pthread_key_create()\n", "", "");
5337 abort();
5338 }
5339#endif
5340 /*
5341 * Seed here for the initial thread, since choose_arena_hard() is only
5342 * called for other threads. The seed value doesn't really matter.
5343 */
5344#ifdef JEMALLOC_BALANCE
5345 SPRN(balance, 42);
5346#endif
5347
5348 malloc_spin_init(&arenas_lock);
5349
5350 /* Get number of CPUs. */
5351 malloc_initializer = pthread_self();
5352 malloc_mutex_unlock(&init_lock);
5353 ncpus = malloc_ncpus();
5354 malloc_mutex_lock(&init_lock);
5355
Jason Evans289053c2009-06-22 12:08:42 -07005356 if (ncpus > 1) {
5357 /*
5358 * For SMP systems, create twice as many arenas as there are
5359 * CPUs by default.
5360 */
5361 opt_narenas_lshift++;
5362 }
5363
5364 /* Determine how many arenas to use. */
5365 narenas = ncpus;
5366 if (opt_narenas_lshift > 0) {
5367 if ((narenas << opt_narenas_lshift) > narenas)
5368 narenas <<= opt_narenas_lshift;
5369 /*
5370 * Make sure not to exceed the limits of what base_alloc() can
5371 * handle.
5372 */
5373 if (narenas * sizeof(arena_t *) > chunksize)
5374 narenas = chunksize / sizeof(arena_t *);
5375 } else if (opt_narenas_lshift < 0) {
5376 if ((narenas >> -opt_narenas_lshift) < narenas)
5377 narenas >>= -opt_narenas_lshift;
5378 /* Make sure there is at least one arena. */
5379 if (narenas == 0)
5380 narenas = 1;
5381 }
Jason Evansb7924f52009-06-23 19:01:18 -07005382#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005383 assert(narenas != 0);
5384 for (narenas_2pow = 0;
5385 (narenas >> (narenas_2pow + 1)) != 0;
5386 narenas_2pow++);
5387#endif
5388
5389#ifdef NO_TLS
5390 if (narenas > 1) {
5391 static const unsigned primes[] = {1, 3, 5, 7, 11, 13, 17, 19,
5392 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
5393 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
5394 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
5395 223, 227, 229, 233, 239, 241, 251, 257, 263};
5396 unsigned nprimes, parenas;
5397
5398 /*
5399 * Pick a prime number of hash arenas that is more than narenas
5400 * so that direct hashing of pthread_self() pointers tends to
5401 * spread allocations evenly among the arenas.
5402 */
5403 assert((narenas & 1) == 0); /* narenas must be even. */
5404 nprimes = (sizeof(primes) >> SIZEOF_INT_2POW);
5405 parenas = primes[nprimes - 1]; /* In case not enough primes. */
5406 for (i = 1; i < nprimes; i++) {
5407 if (primes[i] > narenas) {
5408 parenas = primes[i];
5409 break;
5410 }
5411 }
5412 narenas = parenas;
5413 }
5414#endif
5415
5416#ifndef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -07005417# ifndef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005418 next_arena = 0;
5419# endif
5420#endif
5421
5422 /* Allocate and initialize arenas. */
5423 arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
5424 if (arenas == NULL) {
5425 malloc_mutex_unlock(&init_lock);
5426 return (true);
5427 }
5428 /*
5429 * Zero the array. In practice, this should always be pre-zeroed,
5430 * since it was just mmap()ed, but let's be sure.
5431 */
5432 memset(arenas, 0, sizeof(arena_t *) * narenas);
Jason Evansb7924f52009-06-23 19:01:18 -07005433 /* Copy the pointer to the one arena that was already initialized. */
5434 arenas[0] = init_arenas[0];
Jason Evans289053c2009-06-22 12:08:42 -07005435
5436 malloc_initialized = true;
5437 malloc_mutex_unlock(&init_lock);
5438 return (false);
5439}
5440
5441/*
5442 * End general internal functions.
5443 */
5444/******************************************************************************/
5445/*
5446 * Begin malloc(3)-compatible functions.
5447 */
5448
5449void *
5450malloc(size_t size)
5451{
5452 void *ret;
5453
5454 if (malloc_init()) {
5455 ret = NULL;
5456 goto RETURN;
5457 }
5458
5459 if (size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005460#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005461 if (opt_sysv == false)
Jason Evansb7924f52009-06-23 19:01:18 -07005462#endif
Jason Evans289053c2009-06-22 12:08:42 -07005463 size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005464#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005465 else {
5466 ret = NULL;
5467 goto RETURN;
5468 }
Jason Evansb7924f52009-06-23 19:01:18 -07005469#endif
Jason Evans289053c2009-06-22 12:08:42 -07005470 }
5471
5472 ret = imalloc(size);
5473
5474RETURN:
5475 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005476#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005477 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005478 jemalloc_message("<jemalloc>",
5479 ": Error in malloc(): out of memory\n", "",
Jason Evans289053c2009-06-22 12:08:42 -07005480 "");
5481 abort();
5482 }
Jason Evansb7924f52009-06-23 19:01:18 -07005483#endif
Jason Evans289053c2009-06-22 12:08:42 -07005484 errno = ENOMEM;
5485 }
5486
5487 UTRACE(0, size, ret);
5488 return (ret);
5489}
5490
5491int
5492posix_memalign(void **memptr, size_t alignment, size_t size)
5493{
5494 int ret;
5495 void *result;
5496
5497 if (malloc_init())
5498 result = NULL;
5499 else {
5500 /* Make sure that alignment is a large enough power of 2. */
5501 if (((alignment - 1) & alignment) != 0
5502 || alignment < sizeof(void *)) {
Jason Evansb7924f52009-06-23 19:01:18 -07005503#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005504 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005505 jemalloc_message("<jemalloc>",
5506 ": Error in posix_memalign(): "
Jason Evans289053c2009-06-22 12:08:42 -07005507 "invalid alignment\n", "", "");
5508 abort();
5509 }
Jason Evansb7924f52009-06-23 19:01:18 -07005510#endif
Jason Evans289053c2009-06-22 12:08:42 -07005511 result = NULL;
5512 ret = EINVAL;
5513 goto RETURN;
5514 }
5515
5516 result = ipalloc(alignment, size);
5517 }
5518
5519 if (result == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005520#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005521 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005522 jemalloc_message("<jemalloc>",
5523 ": Error in posix_memalign(): out of memory\n",
Jason Evans289053c2009-06-22 12:08:42 -07005524 "", "");
5525 abort();
5526 }
Jason Evansb7924f52009-06-23 19:01:18 -07005527#endif
Jason Evans289053c2009-06-22 12:08:42 -07005528 ret = ENOMEM;
5529 goto RETURN;
5530 }
5531
5532 *memptr = result;
5533 ret = 0;
5534
5535RETURN:
5536 UTRACE(0, size, result);
5537 return (ret);
5538}
5539
5540void *
5541calloc(size_t num, size_t size)
5542{
5543 void *ret;
5544 size_t num_size;
5545
5546 if (malloc_init()) {
5547 num_size = 0;
5548 ret = NULL;
5549 goto RETURN;
5550 }
5551
5552 num_size = num * size;
5553 if (num_size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005554#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005555 if ((opt_sysv == false) && ((num == 0) || (size == 0)))
Jason Evansb7924f52009-06-23 19:01:18 -07005556#endif
Jason Evans289053c2009-06-22 12:08:42 -07005557 num_size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005558#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005559 else {
5560 ret = NULL;
5561 goto RETURN;
5562 }
Jason Evansb7924f52009-06-23 19:01:18 -07005563#endif
Jason Evans289053c2009-06-22 12:08:42 -07005564 /*
5565 * Try to avoid division here. We know that it isn't possible to
5566 * overflow during multiplication if neither operand uses any of the
5567 * most significant half of the bits in a size_t.
5568 */
5569 } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2)))
5570 && (num_size / size != num)) {
5571 /* size_t overflow. */
5572 ret = NULL;
5573 goto RETURN;
5574 }
5575
5576 ret = icalloc(num_size);
5577
5578RETURN:
5579 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005580#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005581 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005582 jemalloc_message("<jemalloc>",
5583 ": Error in calloc(): out of memory\n", "",
Jason Evans289053c2009-06-22 12:08:42 -07005584 "");
5585 abort();
5586 }
Jason Evansb7924f52009-06-23 19:01:18 -07005587#endif
Jason Evans289053c2009-06-22 12:08:42 -07005588 errno = ENOMEM;
5589 }
5590
5591 UTRACE(0, num_size, ret);
5592 return (ret);
5593}
5594
5595void *
5596realloc(void *ptr, size_t size)
5597{
5598 void *ret;
5599
5600 if (size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005601#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005602 if (opt_sysv == false)
Jason Evansb7924f52009-06-23 19:01:18 -07005603#endif
Jason Evans289053c2009-06-22 12:08:42 -07005604 size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005605#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005606 else {
5607 if (ptr != NULL)
5608 idalloc(ptr);
5609 ret = NULL;
5610 goto RETURN;
5611 }
Jason Evansb7924f52009-06-23 19:01:18 -07005612#endif
Jason Evans289053c2009-06-22 12:08:42 -07005613 }
5614
5615 if (ptr != NULL) {
5616 assert(malloc_initialized);
5617
5618 ret = iralloc(ptr, size);
5619
5620 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005621#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005622 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005623 jemalloc_message("<jemalloc>",
5624 ": Error in realloc(): out of "
Jason Evans289053c2009-06-22 12:08:42 -07005625 "memory\n", "", "");
5626 abort();
5627 }
Jason Evansb7924f52009-06-23 19:01:18 -07005628#endif
Jason Evans289053c2009-06-22 12:08:42 -07005629 errno = ENOMEM;
5630 }
5631 } else {
5632 if (malloc_init())
5633 ret = NULL;
5634 else
5635 ret = imalloc(size);
5636
5637 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005638#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005639 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005640 jemalloc_message("<jemalloc>",
5641 ": Error in realloc(): out of "
Jason Evans289053c2009-06-22 12:08:42 -07005642 "memory\n", "", "");
5643 abort();
5644 }
Jason Evansb7924f52009-06-23 19:01:18 -07005645#endif
Jason Evans289053c2009-06-22 12:08:42 -07005646 errno = ENOMEM;
5647 }
5648 }
5649
Jason Evansb8f0a652009-06-29 09:41:43 -07005650#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005651RETURN:
Jason Evansb8f0a652009-06-29 09:41:43 -07005652#endif
Jason Evans289053c2009-06-22 12:08:42 -07005653 UTRACE(ptr, size, ret);
5654 return (ret);
5655}
5656
5657void
5658free(void *ptr)
5659{
5660
5661 UTRACE(ptr, 0, 0);
5662 if (ptr != NULL) {
5663 assert(malloc_initialized);
5664
5665 idalloc(ptr);
5666 }
5667}
5668
5669/*
5670 * End malloc(3)-compatible functions.
5671 */
5672/******************************************************************************/
5673/*
5674 * Begin non-standard functions.
5675 */
5676
5677size_t
5678malloc_usable_size(const void *ptr)
5679{
5680
5681 assert(ptr != NULL);
5682
5683 return (isalloc(ptr));
5684}
5685
5686/*
5687 * End non-standard functions.
5688 */
5689/******************************************************************************/
5690/*
5691 * Begin library-private functions.
5692 */
5693
5694/******************************************************************************/
5695/*
5696 * Begin thread cache.
5697 */
5698
5699/*
5700 * We provide an unpublished interface in order to receive notifications from
5701 * the pthreads library whenever a thread exits. This allows us to clean up
5702 * thread caches.
5703 */
Jason Evansb7924f52009-06-23 19:01:18 -07005704static void
5705thread_cleanup(void *arg)
Jason Evans289053c2009-06-22 12:08:42 -07005706{
5707
Jason Evansb7924f52009-06-23 19:01:18 -07005708#ifdef JEMALLOC_MAG
5709 assert((mag_rack_t *)arg == mag_rack);
Jason Evans289053c2009-06-22 12:08:42 -07005710 if (mag_rack != NULL) {
5711 assert(mag_rack != (void *)-1);
5712 mag_rack_destroy(mag_rack);
Jason Evansb7924f52009-06-23 19:01:18 -07005713#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07005714 mag_rack = (void *)-1;
5715#endif
5716 }
5717#endif
5718}
5719
5720/*
5721 * The following functions are used by threading libraries for protection of
5722 * malloc during fork(). These functions are only called if the program is
5723 * running in threaded mode, so there is no need to check whether the program
5724 * is threaded here.
5725 */
5726
Jason Evanscc00a152009-06-25 18:06:48 -07005727static void
Jason Evans804c9ec2009-06-22 17:44:33 -07005728jemalloc_prefork(void)
Jason Evans289053c2009-06-22 12:08:42 -07005729{
5730 bool again;
5731 unsigned i, j;
5732 arena_t *larenas[narenas], *tarenas[narenas];
5733
5734 /* Acquire all mutexes in a safe order. */
5735
5736 /*
5737 * arenas_lock must be acquired after all of the arena mutexes, in
5738 * order to avoid potential deadlock with arena_lock_balance[_hard]().
5739 * Since arenas_lock protects the arenas array, the following code has
5740 * to race with arenas_extend() callers until it succeeds in locking
5741 * all arenas before locking arenas_lock.
5742 */
5743 memset(larenas, 0, sizeof(arena_t *) * narenas);
5744 do {
5745 again = false;
5746
5747 malloc_spin_lock(&arenas_lock);
5748 for (i = 0; i < narenas; i++) {
5749 if (arenas[i] != larenas[i]) {
5750 memcpy(tarenas, arenas, sizeof(arena_t *) *
5751 narenas);
5752 malloc_spin_unlock(&arenas_lock);
5753 for (j = 0; j < narenas; j++) {
5754 if (larenas[j] != tarenas[j]) {
5755 larenas[j] = tarenas[j];
5756 malloc_spin_lock(
5757 &larenas[j]->lock);
5758 }
5759 }
5760 again = true;
5761 break;
5762 }
5763 }
5764 } while (again);
5765
5766 malloc_mutex_lock(&base_mtx);
5767
5768 malloc_mutex_lock(&huge_mtx);
5769
Jason Evansb7924f52009-06-23 19:01:18 -07005770#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005771 malloc_mutex_lock(&dss_mtx);
5772#endif
5773}
5774
Jason Evanscc00a152009-06-25 18:06:48 -07005775static void
Jason Evans804c9ec2009-06-22 17:44:33 -07005776jemalloc_postfork(void)
Jason Evans289053c2009-06-22 12:08:42 -07005777{
5778 unsigned i;
5779 arena_t *larenas[narenas];
5780
5781 /* Release all mutexes, now that fork() has completed. */
5782
Jason Evansb7924f52009-06-23 19:01:18 -07005783#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005784 malloc_mutex_unlock(&dss_mtx);
5785#endif
5786
5787 malloc_mutex_unlock(&huge_mtx);
5788
5789 malloc_mutex_unlock(&base_mtx);
5790
5791 memcpy(larenas, arenas, sizeof(arena_t *) * narenas);
5792 malloc_spin_unlock(&arenas_lock);
5793 for (i = 0; i < narenas; i++) {
5794 if (larenas[i] != NULL)
5795 malloc_spin_unlock(&larenas[i]->lock);
5796 }
5797}
5798
5799/*
5800 * End library-private functions.
5801 */
5802/******************************************************************************/