blob: 71b09c48556f5b53ad2178349c582884a5cd9cba [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 |
683 * 6 | 64 |
684 * : :
685 * : :
686 * 33 | 496 |
687 * 34 | 512 |
688 * --------+------+
689 * 35 | 1024 |
690 * 36 | 2048 |
691 * --------+------+
692 */
693 arena_bin_t bins[1]; /* Dynamically sized. */
694};
695
696/******************************************************************************/
697/*
698 * Magazine data structures.
699 */
700
Jason Evansb7924f52009-06-23 19:01:18 -0700701#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700702typedef struct mag_s mag_t;
703struct mag_s {
704 size_t binind; /* Index of associated bin. */
705 size_t nrounds;
706 void *rounds[1]; /* Dynamically sized. */
707};
708
709/*
710 * Magazines are lazily allocated, but once created, they remain until the
711 * associated mag_rack is destroyed.
712 */
713typedef struct bin_mags_s bin_mags_t;
714struct bin_mags_s {
715 mag_t *curmag;
716 mag_t *sparemag;
717};
718
719typedef struct mag_rack_s mag_rack_t;
720struct mag_rack_s {
721 bin_mags_t bin_mags[1]; /* Dynamically sized. */
722};
723#endif
724
725/******************************************************************************/
726/*
727 * Data.
728 */
729
Jason Evansb7924f52009-06-23 19:01:18 -0700730#ifdef JEMALLOC_LAZY_LOCK
731static bool isthreaded = false;
732#else
733# define isthreaded true
734#endif
735
Jason Evans289053c2009-06-22 12:08:42 -0700736/* Number of CPUs. */
737static unsigned ncpus;
738
Jason Evansb7924f52009-06-23 19:01:18 -0700739/*
740 * Page size. STATIC_PAGE_SHIFT is determined by the configure script. If
741 * DYNAMIC_PAGE_SHIFT is enabled, only use the STATIC_PAGE_* macros where
742 * compile-time values are required for the purposes of defining data
743 * structures.
744 */
745#define STATIC_PAGE_SIZE ((size_t)(1U << STATIC_PAGE_SHIFT))
746#define STATIC_PAGE_MASK ((size_t)(STATIC_PAGE_SIZE - 1))
747
748#ifdef DYNAMIC_PAGE_SHIFT
749static size_t pagesize;
750static size_t pagesize_mask;
751static size_t pagesize_2pow;
752# define PAGE_SHIFT pagesize_2pow
753# define PAGE_SIZE pagesize
754# define PAGE_MASK pagesize_mask
755#else
756# define PAGE_SHIFT STATIC_PAGE_SHIFT
757# define PAGE_SIZE STATIC_PAGE_SIZE
758# define PAGE_MASK STATIC_PAGE_MASK
759#endif
760
Jason Evans289053c2009-06-22 12:08:42 -0700761/* Various bin-related settings. */
Jason Evansb7924f52009-06-23 19:01:18 -0700762#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
Jason Evans289053c2009-06-22 12:08:42 -0700763# define ntbins ((unsigned)(QUANTUM_2POW - TINY_MIN_2POW))
764#else
765# define ntbins 0
766#endif
767static unsigned nqbins; /* Number of quantum-spaced bins. */
768static unsigned ncbins; /* Number of cacheline-spaced bins. */
769static unsigned nsbins; /* Number of subpage-spaced bins. */
770static unsigned nbins;
Jason Evansb7924f52009-06-23 19:01:18 -0700771#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700772# define tspace_max ((size_t)(QUANTUM >> 1))
773#endif
774#define qspace_min QUANTUM
775static size_t qspace_max;
776static size_t cspace_min;
777static size_t cspace_max;
778static size_t sspace_min;
779static size_t sspace_max;
780#define bin_maxclass sspace_max
781
782static uint8_t const *size2bin;
783/*
784 * const_size2bin is a static constant lookup table that in the common case can
785 * be used as-is for size2bin. For dynamically linked programs, this avoids
786 * a page of memory overhead per process.
787 */
788#define S2B_1(i) i,
789#define S2B_2(i) S2B_1(i) S2B_1(i)
790#define S2B_4(i) S2B_2(i) S2B_2(i)
791#define S2B_8(i) S2B_4(i) S2B_4(i)
792#define S2B_16(i) S2B_8(i) S2B_8(i)
793#define S2B_32(i) S2B_16(i) S2B_16(i)
794#define S2B_64(i) S2B_32(i) S2B_32(i)
795#define S2B_128(i) S2B_64(i) S2B_64(i)
796#define S2B_256(i) S2B_128(i) S2B_128(i)
Jason Evansb7924f52009-06-23 19:01:18 -0700797static const uint8_t const_size2bin[STATIC_PAGE_SIZE - 255] = {
Jason Evans289053c2009-06-22 12:08:42 -0700798 S2B_1(0xffU) /* 0 */
799#if (QUANTUM_2POW == 4)
800/* 64-bit system ************************/
Jason Evansb7924f52009-06-23 19:01:18 -0700801# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700802 S2B_2(0) /* 2 */
803 S2B_2(1) /* 4 */
804 S2B_4(2) /* 8 */
805 S2B_8(3) /* 16 */
806# define S2B_QMIN 3
807# else
808 S2B_16(0) /* 16 */
809# define S2B_QMIN 0
810# endif
811 S2B_16(S2B_QMIN + 1) /* 32 */
812 S2B_16(S2B_QMIN + 2) /* 48 */
813 S2B_16(S2B_QMIN + 3) /* 64 */
814 S2B_16(S2B_QMIN + 4) /* 80 */
815 S2B_16(S2B_QMIN + 5) /* 96 */
816 S2B_16(S2B_QMIN + 6) /* 112 */
817 S2B_16(S2B_QMIN + 7) /* 128 */
818# define S2B_CMIN (S2B_QMIN + 8)
819#else
820/* 32-bit system ************************/
Jason Evansb7924f52009-06-23 19:01:18 -0700821# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -0700822 S2B_2(0) /* 2 */
823 S2B_2(1) /* 4 */
824 S2B_4(2) /* 8 */
825# define S2B_QMIN 2
826# else
827 S2B_8(0) /* 8 */
828# define S2B_QMIN 0
829# endif
830 S2B_8(S2B_QMIN + 1) /* 16 */
831 S2B_8(S2B_QMIN + 2) /* 24 */
832 S2B_8(S2B_QMIN + 3) /* 32 */
833 S2B_8(S2B_QMIN + 4) /* 40 */
834 S2B_8(S2B_QMIN + 5) /* 48 */
835 S2B_8(S2B_QMIN + 6) /* 56 */
836 S2B_8(S2B_QMIN + 7) /* 64 */
837 S2B_8(S2B_QMIN + 8) /* 72 */
838 S2B_8(S2B_QMIN + 9) /* 80 */
839 S2B_8(S2B_QMIN + 10) /* 88 */
840 S2B_8(S2B_QMIN + 11) /* 96 */
841 S2B_8(S2B_QMIN + 12) /* 104 */
842 S2B_8(S2B_QMIN + 13) /* 112 */
843 S2B_8(S2B_QMIN + 14) /* 120 */
844 S2B_8(S2B_QMIN + 15) /* 128 */
845# define S2B_CMIN (S2B_QMIN + 16)
846#endif
847/****************************************/
848 S2B_64(S2B_CMIN + 0) /* 192 */
849 S2B_64(S2B_CMIN + 1) /* 256 */
850 S2B_64(S2B_CMIN + 2) /* 320 */
851 S2B_64(S2B_CMIN + 3) /* 384 */
852 S2B_64(S2B_CMIN + 4) /* 448 */
853 S2B_64(S2B_CMIN + 5) /* 512 */
854# define S2B_SMIN (S2B_CMIN + 6)
855 S2B_256(S2B_SMIN + 0) /* 768 */
856 S2B_256(S2B_SMIN + 1) /* 1024 */
857 S2B_256(S2B_SMIN + 2) /* 1280 */
858 S2B_256(S2B_SMIN + 3) /* 1536 */
859 S2B_256(S2B_SMIN + 4) /* 1792 */
860 S2B_256(S2B_SMIN + 5) /* 2048 */
861 S2B_256(S2B_SMIN + 6) /* 2304 */
862 S2B_256(S2B_SMIN + 7) /* 2560 */
863 S2B_256(S2B_SMIN + 8) /* 2816 */
864 S2B_256(S2B_SMIN + 9) /* 3072 */
865 S2B_256(S2B_SMIN + 10) /* 3328 */
866 S2B_256(S2B_SMIN + 11) /* 3584 */
867 S2B_256(S2B_SMIN + 12) /* 3840 */
Jason Evansb7924f52009-06-23 19:01:18 -0700868#if (STATIC_PAGE_SHIFT == 13)
Jason Evans289053c2009-06-22 12:08:42 -0700869 S2B_256(S2B_SMIN + 13) /* 4096 */
870 S2B_256(S2B_SMIN + 14) /* 4352 */
871 S2B_256(S2B_SMIN + 15) /* 4608 */
872 S2B_256(S2B_SMIN + 16) /* 4864 */
873 S2B_256(S2B_SMIN + 17) /* 5120 */
874 S2B_256(S2B_SMIN + 18) /* 5376 */
875 S2B_256(S2B_SMIN + 19) /* 5632 */
876 S2B_256(S2B_SMIN + 20) /* 5888 */
877 S2B_256(S2B_SMIN + 21) /* 6144 */
878 S2B_256(S2B_SMIN + 22) /* 6400 */
879 S2B_256(S2B_SMIN + 23) /* 6656 */
880 S2B_256(S2B_SMIN + 24) /* 6912 */
881 S2B_256(S2B_SMIN + 25) /* 7168 */
882 S2B_256(S2B_SMIN + 26) /* 7424 */
883 S2B_256(S2B_SMIN + 27) /* 7680 */
884 S2B_256(S2B_SMIN + 28) /* 7936 */
885#endif
886};
887#undef S2B_1
888#undef S2B_2
889#undef S2B_4
890#undef S2B_8
891#undef S2B_16
892#undef S2B_32
893#undef S2B_64
894#undef S2B_128
895#undef S2B_256
896#undef S2B_QMIN
897#undef S2B_CMIN
898#undef S2B_SMIN
899
Jason Evansb7924f52009-06-23 19:01:18 -0700900#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -0700901static size_t max_rounds;
902#endif
903
904/* Various chunk-related settings. */
905static size_t chunksize;
906static size_t chunksize_mask; /* (chunksize - 1). */
907static size_t chunk_npages;
908static size_t arena_chunk_header_npages;
909static size_t arena_maxclass; /* Max size class for arenas. */
910
911/********/
912/*
913 * Chunks.
914 */
915
916/* Protects chunk-related data structures. */
917static malloc_mutex_t huge_mtx;
918
919/* Tree of chunks that are stand-alone huge allocations. */
920static extent_tree_t huge;
921
Jason Evansb7924f52009-06-23 19:01:18 -0700922#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -0700923/*
924 * Protects sbrk() calls. This avoids malloc races among threads, though it
925 * does not protect against races with threads that call sbrk() directly.
926 */
927static malloc_mutex_t dss_mtx;
928/* Base address of the DSS. */
929static void *dss_base;
930/* Current end of the DSS, or ((void *)-1) if the DSS is exhausted. */
931static void *dss_prev;
932/* Current upper limit on DSS addresses. */
933static void *dss_max;
934
935/*
936 * Trees of chunks that were previously allocated (trees differ only in node
937 * ordering). These are used when allocating chunks, in an attempt to re-use
938 * address space. Depending on function, different tree orderings are needed,
939 * which is why there are two trees with the same contents.
940 */
941static extent_tree_t dss_chunks_szad;
942static extent_tree_t dss_chunks_ad;
943#endif
944
Jason Evansb7924f52009-06-23 19:01:18 -0700945#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700946/* Huge allocation statistics. */
947static uint64_t huge_nmalloc;
948static uint64_t huge_ndalloc;
949static size_t huge_allocated;
950#endif
951
952/****************************/
953/*
954 * base (internal allocation).
955 */
956
957/*
958 * Current pages that are being used for internal memory allocations. These
959 * pages are carved up in cacheline-size quanta, so that there is no chance of
960 * false cache line sharing.
961 */
962static void *base_pages;
963static void *base_next_addr;
964static void *base_past_addr; /* Addr immediately past base_pages. */
965static extent_node_t *base_nodes;
966static malloc_mutex_t base_mtx;
Jason Evansb7924f52009-06-23 19:01:18 -0700967#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -0700968static size_t base_mapped;
969#endif
970
971/********/
972/*
973 * Arenas.
974 */
975
976/*
977 * Arenas that are used to service external requests. Not all elements of the
978 * arenas array are necessarily used; arenas are created lazily as needed.
979 */
980static arena_t **arenas;
981static unsigned narenas;
982#ifndef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -0700983# ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -0700984static unsigned narenas_2pow;
985# else
986static unsigned next_arena;
987# endif
988#endif
989static pthread_mutex_t arenas_lock; /* Protects arenas initialization. */
990
991#ifndef NO_TLS
992/*
993 * Map of pthread_self() --> arenas[???], used for selecting an arena to use
994 * for allocations.
995 */
996static __thread arena_t *arenas_map;
997#endif
998
Jason Evansb7924f52009-06-23 19:01:18 -0700999#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001000/*
1001 * Map of thread-specific magazine racks, used for thread-specific object
1002 * caching.
1003 */
1004static __thread mag_rack_t *mag_rack;
Jason Evansb7924f52009-06-23 19:01:18 -07001005
1006/*
1007 * Same contents as mag_rack, but initialized such that the TSD destructor is
1008 * called when a thread exits, so that the cache can be cleaned up.
1009 */
1010static pthread_key_t mag_rack_tsd;
Jason Evans289053c2009-06-22 12:08:42 -07001011#endif
1012
Jason Evansb7924f52009-06-23 19:01:18 -07001013#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001014/* Chunk statistics. */
1015static chunk_stats_t stats_chunks;
1016#endif
1017
1018/*******************************/
1019/*
1020 * Runtime configuration options.
1021 */
Jason Evans804c9ec2009-06-22 17:44:33 -07001022const char *jemalloc_options;
Jason Evans289053c2009-06-22 12:08:42 -07001023
Jason Evansb7924f52009-06-23 19:01:18 -07001024#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07001025static bool opt_abort = true;
Jason Evansb7924f52009-06-23 19:01:18 -07001026# ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001027static bool opt_junk = true;
Jason Evansb7924f52009-06-23 19:01:18 -07001028# endif
Jason Evans289053c2009-06-22 12:08:42 -07001029#else
1030static bool opt_abort = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001031# ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001032static bool opt_junk = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001033# endif
Jason Evans289053c2009-06-22 12:08:42 -07001034#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001035#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001036static bool opt_dss = true;
1037static bool opt_mmap = true;
1038#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001039#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001040static bool opt_mag = true;
1041static size_t opt_mag_size_2pow = MAG_SIZE_2POW_DEFAULT;
1042#endif
1043static size_t opt_dirty_max = DIRTY_MAX_DEFAULT;
Jason Evansb7924f52009-06-23 19:01:18 -07001044#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001045static uint64_t opt_balance_threshold = BALANCE_THRESHOLD_DEFAULT;
1046#endif
1047static bool opt_print_stats = false;
1048static size_t opt_qspace_max_2pow = QSPACE_MAX_2POW_DEFAULT;
1049static size_t opt_cspace_max_2pow = CSPACE_MAX_2POW_DEFAULT;
1050static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT;
Jason Evansb7924f52009-06-23 19:01:18 -07001051#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001052static bool opt_utrace = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001053#endif
1054#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07001055static bool opt_sysv = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001056#endif
Jason Evans289053c2009-06-22 12:08:42 -07001057static bool opt_xmalloc = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001058#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07001059static bool opt_zero = false;
Jason Evansb7924f52009-06-23 19:01:18 -07001060#endif
Jason Evans289053c2009-06-22 12:08:42 -07001061static int opt_narenas_lshift = 0;
1062
Jason Evansb7924f52009-06-23 19:01:18 -07001063#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001064typedef struct {
1065 void *p;
1066 size_t s;
1067 void *r;
1068} malloc_utrace_t;
1069
1070#define UTRACE(a, b, c) \
1071 if (opt_utrace) { \
1072 malloc_utrace_t ut; \
1073 ut.p = (a); \
1074 ut.s = (b); \
1075 ut.r = (c); \
1076 utrace(&ut, sizeof(ut)); \
1077 }
Jason Evansc9658dd2009-06-22 14:44:08 -07001078#else
1079#define UTRACE(a, b, c)
1080#endif
Jason Evans289053c2009-06-22 12:08:42 -07001081
1082/******************************************************************************/
1083/*
1084 * Begin function prototypes for non-inline static functions.
1085 */
1086
Jason Evansc9658dd2009-06-22 14:44:08 -07001087static bool malloc_mutex_init(malloc_mutex_t *mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001088static bool malloc_spin_init(pthread_mutex_t *lock);
1089static void wrtmessage(const char *p1, const char *p2, const char *p3,
1090 const char *p4);
Jason Evansb7924f52009-06-23 19:01:18 -07001091#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001092static void malloc_printf(const char *format, ...);
1093#endif
1094static char *umax2s(uintmax_t x, char *s);
Jason Evansb7924f52009-06-23 19:01:18 -07001095#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001096static bool base_pages_alloc_dss(size_t minsize);
1097#endif
1098static bool base_pages_alloc_mmap(size_t minsize);
1099static bool base_pages_alloc(size_t minsize);
1100static void *base_alloc(size_t size);
1101static void *base_calloc(size_t number, size_t size);
1102static extent_node_t *base_node_alloc(void);
1103static void base_node_dealloc(extent_node_t *node);
Jason Evansb7924f52009-06-23 19:01:18 -07001104#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001105static void stats_print(arena_t *arena);
1106#endif
1107static void *pages_map(void *addr, size_t size);
1108static void pages_unmap(void *addr, size_t size);
Jason Evansb7924f52009-06-23 19:01:18 -07001109#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001110static void *chunk_alloc_dss(size_t size);
1111static void *chunk_recycle_dss(size_t size, bool zero);
1112#endif
1113static void *chunk_alloc_mmap(size_t size);
1114static void *chunk_alloc(size_t size, bool zero);
Jason Evansb7924f52009-06-23 19:01:18 -07001115#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001116static extent_node_t *chunk_dealloc_dss_record(void *chunk, size_t size);
1117static bool chunk_dealloc_dss(void *chunk, size_t size);
1118#endif
1119static void chunk_dealloc_mmap(void *chunk, size_t size);
1120static void chunk_dealloc(void *chunk, size_t size);
1121#ifndef NO_TLS
1122static arena_t *choose_arena_hard(void);
1123#endif
1124static void arena_run_split(arena_t *arena, arena_run_t *run, size_t size,
1125 bool large, bool zero);
1126static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
1127static void arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
1128static arena_run_t *arena_run_alloc(arena_t *arena, size_t size, bool large,
1129 bool zero);
1130static void arena_purge(arena_t *arena);
1131static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty);
1132static void arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk,
1133 arena_run_t *run, size_t oldsize, size_t newsize);
1134static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk,
1135 arena_run_t *run, size_t oldsize, size_t newsize, bool dirty);
1136static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
1137static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
1138static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size);
Jason Evansb7924f52009-06-23 19:01:18 -07001139#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001140static void arena_lock_balance_hard(arena_t *arena);
1141#endif
Jason Evansb7924f52009-06-23 19:01:18 -07001142#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001143static void mag_load(mag_t *mag);
1144#endif
1145static void *arena_malloc_large(arena_t *arena, size_t size, bool zero);
1146static void *arena_palloc(arena_t *arena, size_t alignment, size_t size,
1147 size_t alloc_size);
1148static size_t arena_salloc(const void *ptr);
Jason Evansb7924f52009-06-23 19:01:18 -07001149#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001150static void mag_unload(mag_t *mag);
1151#endif
1152static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk,
1153 void *ptr);
1154static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk,
1155 void *ptr, size_t size, size_t oldsize);
1156static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk,
1157 void *ptr, size_t size, size_t oldsize);
1158static bool arena_ralloc_large(void *ptr, size_t size, size_t oldsize);
1159static void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
1160static bool arena_new(arena_t *arena);
1161static arena_t *arenas_extend(unsigned ind);
Jason Evansb7924f52009-06-23 19:01:18 -07001162#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001163static mag_t *mag_create(arena_t *arena, size_t binind);
1164static void mag_destroy(mag_t *mag);
1165static mag_rack_t *mag_rack_create(arena_t *arena);
1166static void mag_rack_destroy(mag_rack_t *rack);
1167#endif
1168static void *huge_malloc(size_t size, bool zero);
1169static void *huge_palloc(size_t alignment, size_t size);
1170static void *huge_ralloc(void *ptr, size_t size, size_t oldsize);
1171static void huge_dalloc(void *ptr);
1172static void malloc_print_stats(void);
Jason Evansb7924f52009-06-23 19:01:18 -07001173#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07001174static void size2bin_validate(void);
1175#endif
1176static bool size2bin_init(void);
1177static bool size2bin_init_hard(void);
Jason Evansc9658dd2009-06-22 14:44:08 -07001178static unsigned malloc_ncpus(void);
Jason Evans289053c2009-06-22 12:08:42 -07001179static bool malloc_init_hard(void);
Jason Evansb7924f52009-06-23 19:01:18 -07001180static void thread_cleanup(void *arg);
Jason Evans804c9ec2009-06-22 17:44:33 -07001181void jemalloc_prefork(void);
1182void jemalloc_postfork(void);
Jason Evans289053c2009-06-22 12:08:42 -07001183
1184/*
1185 * End function prototypes.
1186 */
1187/******************************************************************************/
Jason Evans289053c2009-06-22 12:08:42 -07001188
1189static void
Jason Evansc9658dd2009-06-22 14:44:08 -07001190wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
1191{
1192
Jason Evansb7924f52009-06-23 19:01:18 -07001193 if (write(STDERR_FILENO, p1, strlen(p1)) < 0
1194 || write(STDERR_FILENO, p2, strlen(p2)) < 0
1195 || write(STDERR_FILENO, p3, strlen(p3)) < 0
1196 || write(STDERR_FILENO, p4, strlen(p4)) < 0)
1197 return;
Jason Evansc9658dd2009-06-22 14:44:08 -07001198}
1199
Jason Evans804c9ec2009-06-22 17:44:33 -07001200void (*jemalloc_message)(const char *p1, const char *p2, const char *p3,
Jason Evansc9658dd2009-06-22 14:44:08 -07001201 const char *p4) = wrtmessage;
1202
1203/*
1204 * We don't want to depend on vsnprintf() for production builds, since that can
1205 * cause unnecessary bloat for static binaries. umax2s() provides minimal
1206 * integer printing functionality, so that malloc_printf() use can be limited to
Jason Evansb7924f52009-06-23 19:01:18 -07001207 * JEMALLOC_STATS code.
Jason Evansc9658dd2009-06-22 14:44:08 -07001208 */
1209#define UMAX2S_BUFSIZE 21
1210static char *
1211umax2s(uintmax_t x, char *s)
1212{
1213 unsigned i;
1214
1215 i = UMAX2S_BUFSIZE - 1;
1216 s[i] = '\0';
1217 do {
1218 i--;
1219 s[i] = "0123456789"[x % 10];
1220 x /= 10;
1221 } while (x > 0);
1222
1223 return (&s[i]);
1224}
1225
1226/*
1227 * Define a custom assert() in order to reduce the chances of deadlock during
1228 * assertion failure.
1229 */
Jason Evansb7924f52009-06-23 19:01:18 -07001230#ifdef JEMALLOC_DEBUG
Jason Evansc9658dd2009-06-22 14:44:08 -07001231# define assert(e) do { \
1232 if (!(e)) { \
1233 char line_buf[UMAX2S_BUFSIZE]; \
Jason Evans804c9ec2009-06-22 17:44:33 -07001234 jemalloc_message(__FILE__, ":", umax2s(__LINE__, \
Jason Evansc9658dd2009-06-22 14:44:08 -07001235 line_buf), ": Failed assertion: "); \
Jason Evans804c9ec2009-06-22 17:44:33 -07001236 jemalloc_message("\"", #e, "\"\n", ""); \
Jason Evansc9658dd2009-06-22 14:44:08 -07001237 abort(); \
1238 } \
1239} while (0)
1240#else
1241#define assert(e)
1242#endif
1243
Jason Evansb7924f52009-06-23 19:01:18 -07001244#ifdef JEMALLOC_STATS
Jason Evansc9658dd2009-06-22 14:44:08 -07001245static int
1246utrace(const void *addr, size_t len)
1247{
1248 malloc_utrace_t *ut = (malloc_utrace_t *)addr;
1249
1250 assert(len == sizeof(malloc_utrace_t));
1251
1252 if (ut->p == NULL && ut->s == 0 && ut->r == NULL)
1253 malloc_printf("%d x USER malloc_init()\n", getpid());
1254 else if (ut->p == NULL && ut->r != NULL) {
1255 malloc_printf("%d x USER %p = malloc(%zu)\n", getpid(), ut->r,
1256 ut->s);
1257 } else if (ut->p != NULL && ut->r != NULL) {
1258 malloc_printf("%d x USER %p = realloc(%p, %zu)\n", getpid(),
1259 ut->r, ut->p, ut->s);
1260 } else
1261 malloc_printf("%d x USER free(%p)\n", getpid(), ut->p);
1262
1263 return (0);
1264}
1265#endif
1266
Jason Evansb7924f52009-06-23 19:01:18 -07001267#ifdef JEMALLOC_STATS
Jason Evansc9658dd2009-06-22 14:44:08 -07001268/*
1269 * Print to stderr in such a way as to (hopefully) avoid memory allocation.
1270 */
1271static void
1272malloc_printf(const char *format, ...)
1273{
1274 char buf[4096];
1275 va_list ap;
1276
1277 va_start(ap, format);
1278 vsnprintf(buf, sizeof(buf), format, ap);
1279 va_end(ap);
Jason Evans804c9ec2009-06-22 17:44:33 -07001280 jemalloc_message(buf, "", "", "");
Jason Evansc9658dd2009-06-22 14:44:08 -07001281}
1282#endif
1283
1284/******************************************************************************/
1285/*
Jason Evansb7924f52009-06-23 19:01:18 -07001286 * Begin pthreads integration. We intercept pthread_create() calls in order
1287 * to toggle isthreaded if the process goes multi-threaded.
1288 */
1289
1290#ifdef JEMALLOC_LAZY_LOCK
1291int (*pthread_create_fptr)(pthread_t *restrict, const pthread_attr_t *,
1292 void *(*)(void *), void *restrict);
1293
1294static void
1295get_pthread_create_fptr(void)
1296{
1297
1298 pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
1299 if (pthread_create_fptr == NULL) {
1300 jemalloc_message("<jemalloc>",
1301 ": Error in dlsym(RTLD_NEXT, \"pthread_create\")\n", "",
1302 "");
1303 abort();
1304 }
1305}
1306
1307int
1308pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,
1309 void *(*start_routine)(void *), void *restrict arg)
1310{
1311 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
1312
1313 pthread_once(&once_control, get_pthread_create_fptr);
1314
1315 isthreaded = true;
1316 return pthread_create_fptr(thread, attr, start_routine, arg);
1317}
1318#endif
1319
1320/******************************************************************************/
1321/*
Jason Evansc9658dd2009-06-22 14:44:08 -07001322 * Begin mutex.
1323 */
1324
1325static bool
Jason Evans289053c2009-06-22 12:08:42 -07001326malloc_mutex_init(malloc_mutex_t *mutex)
1327{
Jason Evansc9658dd2009-06-22 14:44:08 -07001328 pthread_mutexattr_t attr;
Jason Evans289053c2009-06-22 12:08:42 -07001329
Jason Evansc9658dd2009-06-22 14:44:08 -07001330 if (pthread_mutexattr_init(&attr) != 0)
1331 return (true);
1332 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1333 if (pthread_mutex_init(mutex, &attr) != 0) {
1334 pthread_mutexattr_destroy(&attr);
1335 return (true);
1336 }
1337 pthread_mutexattr_destroy(&attr);
1338
1339 return (false);
Jason Evans289053c2009-06-22 12:08:42 -07001340}
1341
1342static inline void
1343malloc_mutex_lock(malloc_mutex_t *mutex)
1344{
1345
Jason Evansb7924f52009-06-23 19:01:18 -07001346 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001347 pthread_mutex_lock(mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001348}
1349
1350static inline void
1351malloc_mutex_unlock(malloc_mutex_t *mutex)
1352{
1353
Jason Evansb7924f52009-06-23 19:01:18 -07001354 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001355 pthread_mutex_unlock(mutex);
Jason Evans289053c2009-06-22 12:08:42 -07001356}
1357
1358/*
1359 * End mutex.
1360 */
1361/******************************************************************************/
1362/*
1363 * Begin spin lock. Spin locks here are actually adaptive mutexes that block
1364 * after a period of spinning, because unbounded spinning would allow for
1365 * priority inversion.
1366 */
1367
Jason Evans289053c2009-06-22 12:08:42 -07001368static bool
1369malloc_spin_init(pthread_mutex_t *lock)
1370{
1371
Jason Evansc9658dd2009-06-22 14:44:08 -07001372 if (pthread_mutex_init(lock, NULL) != 0)
Jason Evans289053c2009-06-22 12:08:42 -07001373 return (true);
1374
1375 return (false);
1376}
1377
1378static inline unsigned
1379malloc_spin_lock(pthread_mutex_t *lock)
1380{
1381 unsigned ret = 0;
1382
Jason Evansb7924f52009-06-23 19:01:18 -07001383 if (isthreaded) {
Jason Evansc9658dd2009-06-22 14:44:08 -07001384 if (pthread_mutex_trylock(lock) != 0) {
Jason Evans289053c2009-06-22 12:08:42 -07001385 /* Exponentially back off if there are multiple CPUs. */
1386 if (ncpus > 1) {
1387 unsigned i;
1388 volatile unsigned j;
1389
1390 for (i = 1; i <= SPIN_LIMIT_2POW; i++) {
1391 for (j = 0; j < (1U << i); j++) {
1392 ret++;
1393 CPU_SPINWAIT;
1394 }
1395
Jason Evansc9658dd2009-06-22 14:44:08 -07001396 if (pthread_mutex_trylock(lock) == 0)
Jason Evans289053c2009-06-22 12:08:42 -07001397 return (ret);
1398 }
1399 }
1400
1401 /*
1402 * Spinning failed. Block until the lock becomes
1403 * available, in order to avoid indefinite priority
1404 * inversion.
1405 */
Jason Evansc9658dd2009-06-22 14:44:08 -07001406 pthread_mutex_lock(lock);
Jason Evans289053c2009-06-22 12:08:42 -07001407 assert((ret << BLOCK_COST_2POW) != 0 || ncpus == 1);
1408 return (ret << BLOCK_COST_2POW);
1409 }
1410 }
1411
1412 return (ret);
1413}
1414
1415static inline void
1416malloc_spin_unlock(pthread_mutex_t *lock)
1417{
1418
Jason Evansb7924f52009-06-23 19:01:18 -07001419 if (isthreaded)
Jason Evansc9658dd2009-06-22 14:44:08 -07001420 pthread_mutex_unlock(lock);
Jason Evans289053c2009-06-22 12:08:42 -07001421}
1422
1423/*
1424 * End spin lock.
1425 */
1426/******************************************************************************/
1427/*
1428 * Begin Utility functions/macros.
1429 */
1430
1431/* Return the chunk address for allocation address a. */
1432#define CHUNK_ADDR2BASE(a) \
1433 ((void *)((uintptr_t)(a) & ~chunksize_mask))
1434
1435/* Return the chunk offset of address a. */
1436#define CHUNK_ADDR2OFFSET(a) \
1437 ((size_t)((uintptr_t)(a) & chunksize_mask))
1438
1439/* Return the smallest chunk multiple that is >= s. */
1440#define CHUNK_CEILING(s) \
1441 (((s) + chunksize_mask) & ~chunksize_mask)
1442
1443/* Return the smallest quantum multiple that is >= a. */
1444#define QUANTUM_CEILING(a) \
1445 (((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
1446
1447/* Return the smallest cacheline multiple that is >= s. */
1448#define CACHELINE_CEILING(s) \
1449 (((s) + CACHELINE_MASK) & ~CACHELINE_MASK)
1450
1451/* Return the smallest subpage multiple that is >= s. */
1452#define SUBPAGE_CEILING(s) \
1453 (((s) + SUBPAGE_MASK) & ~SUBPAGE_MASK)
1454
Jason Evansc9658dd2009-06-22 14:44:08 -07001455/* Return the smallest pagesize multiple that is >= s. */
Jason Evans289053c2009-06-22 12:08:42 -07001456#define PAGE_CEILING(s) \
Jason Evansb7924f52009-06-23 19:01:18 -07001457 (((s) + PAGE_MASK) & ~PAGE_MASK)
Jason Evans289053c2009-06-22 12:08:42 -07001458
Jason Evansb7924f52009-06-23 19:01:18 -07001459#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07001460/* Compute the smallest power of 2 that is >= x. */
1461static inline size_t
1462pow2_ceil(size_t x)
1463{
1464
1465 x--;
1466 x |= x >> 1;
1467 x |= x >> 2;
1468 x |= x >> 4;
1469 x |= x >> 8;
1470 x |= x >> 16;
1471#if (SIZEOF_PTR == 8)
1472 x |= x >> 32;
1473#endif
1474 x++;
1475 return (x);
1476}
1477#endif
1478
Jason Evansb7924f52009-06-23 19:01:18 -07001479#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001480/*
1481 * Use a simple linear congruential pseudo-random number generator:
1482 *
1483 * prn(y) = (a*x + c) % m
1484 *
1485 * where the following constants ensure maximal period:
1486 *
1487 * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4.
1488 * c == Odd number (relatively prime to 2^n).
1489 * m == 2^32
1490 *
1491 * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints.
1492 *
1493 * This choice of m has the disadvantage that the quality of the bits is
1494 * proportional to bit position. For example. the lowest bit has a cycle of 2,
1495 * the next has a cycle of 4, etc. For this reason, we prefer to use the upper
1496 * bits.
1497 */
1498# define PRN_DEFINE(suffix, var, a, c) \
1499static inline void \
1500sprn_##suffix(uint32_t seed) \
1501{ \
1502 var = seed; \
1503} \
1504 \
1505static inline uint32_t \
1506prn_##suffix(uint32_t lg_range) \
1507{ \
1508 uint32_t ret, x; \
1509 \
1510 assert(lg_range > 0); \
1511 assert(lg_range <= 32); \
1512 \
1513 x = (var * (a)) + (c); \
1514 var = x; \
1515 ret = x >> (32 - lg_range); \
1516 \
1517 return (ret); \
1518}
1519# define SPRN(suffix, seed) sprn_##suffix(seed)
1520# define PRN(suffix, lg_range) prn_##suffix(lg_range)
1521#endif
1522
Jason Evansb7924f52009-06-23 19:01:18 -07001523#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07001524/* Define the PRNG used for arena assignment. */
1525static __thread uint32_t balance_x;
1526PRN_DEFINE(balance, balance_x, 1297, 1301)
1527#endif
1528
Jason Evans289053c2009-06-22 12:08:42 -07001529/******************************************************************************/
1530
Jason Evansb7924f52009-06-23 19:01:18 -07001531#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001532static bool
1533base_pages_alloc_dss(size_t minsize)
1534{
1535
1536 /*
1537 * Do special DSS allocation here, since base allocations don't need to
1538 * be chunk-aligned.
1539 */
1540 malloc_mutex_lock(&dss_mtx);
1541 if (dss_prev != (void *)-1) {
1542 intptr_t incr;
1543 size_t csize = CHUNK_CEILING(minsize);
1544
1545 do {
1546 /* Get the current end of the DSS. */
1547 dss_max = sbrk(0);
1548
1549 /*
1550 * Calculate how much padding is necessary to
1551 * chunk-align the end of the DSS. Don't worry about
1552 * dss_max not being chunk-aligned though.
1553 */
1554 incr = (intptr_t)chunksize
1555 - (intptr_t)CHUNK_ADDR2OFFSET(dss_max);
1556 assert(incr >= 0);
1557 if ((size_t)incr < minsize)
1558 incr += csize;
1559
1560 dss_prev = sbrk(incr);
1561 if (dss_prev == dss_max) {
1562 /* Success. */
1563 dss_max = (void *)((intptr_t)dss_prev + incr);
1564 base_pages = dss_prev;
1565 base_next_addr = base_pages;
1566 base_past_addr = dss_max;
Jason Evansb7924f52009-06-23 19:01:18 -07001567#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001568 base_mapped += incr;
1569#endif
1570 malloc_mutex_unlock(&dss_mtx);
1571 return (false);
1572 }
1573 } while (dss_prev != (void *)-1);
1574 }
1575 malloc_mutex_unlock(&dss_mtx);
1576
1577 return (true);
1578}
1579#endif
1580
1581static bool
1582base_pages_alloc_mmap(size_t minsize)
1583{
1584 size_t csize;
1585
1586 assert(minsize != 0);
1587 csize = PAGE_CEILING(minsize);
1588 base_pages = pages_map(NULL, csize);
1589 if (base_pages == NULL)
1590 return (true);
1591 base_next_addr = base_pages;
1592 base_past_addr = (void *)((uintptr_t)base_pages + csize);
Jason Evansb7924f52009-06-23 19:01:18 -07001593#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001594 base_mapped += csize;
1595#endif
1596
1597 return (false);
1598}
1599
1600static bool
1601base_pages_alloc(size_t minsize)
1602{
1603
Jason Evansb7924f52009-06-23 19:01:18 -07001604#ifdef JEMALLOC_DSS
Jason Evansc9658dd2009-06-22 14:44:08 -07001605 if (opt_dss) {
1606 if (base_pages_alloc_dss(minsize) == false)
1607 return (false);
1608 }
1609
Jason Evans289053c2009-06-22 12:08:42 -07001610 if (opt_mmap && minsize != 0)
1611#endif
1612 {
1613 if (base_pages_alloc_mmap(minsize) == false)
1614 return (false);
1615 }
1616
Jason Evans289053c2009-06-22 12:08:42 -07001617 return (true);
1618}
1619
1620static void *
1621base_alloc(size_t size)
1622{
1623 void *ret;
1624 size_t csize;
1625
1626 /* Round size up to nearest multiple of the cacheline size. */
1627 csize = CACHELINE_CEILING(size);
1628
1629 malloc_mutex_lock(&base_mtx);
1630 /* Make sure there's enough space for the allocation. */
1631 if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
1632 if (base_pages_alloc(csize)) {
1633 malloc_mutex_unlock(&base_mtx);
1634 return (NULL);
1635 }
1636 }
1637 /* Allocate. */
1638 ret = base_next_addr;
1639 base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
1640 malloc_mutex_unlock(&base_mtx);
1641
1642 return (ret);
1643}
1644
1645static void *
1646base_calloc(size_t number, size_t size)
1647{
1648 void *ret;
1649
1650 ret = base_alloc(number * size);
1651 memset(ret, 0, number * size);
1652
1653 return (ret);
1654}
1655
1656static extent_node_t *
1657base_node_alloc(void)
1658{
1659 extent_node_t *ret;
1660
1661 malloc_mutex_lock(&base_mtx);
1662 if (base_nodes != NULL) {
1663 ret = base_nodes;
1664 base_nodes = *(extent_node_t **)ret;
1665 malloc_mutex_unlock(&base_mtx);
1666 } else {
1667 malloc_mutex_unlock(&base_mtx);
1668 ret = (extent_node_t *)base_alloc(sizeof(extent_node_t));
1669 }
1670
1671 return (ret);
1672}
1673
1674static void
1675base_node_dealloc(extent_node_t *node)
1676{
1677
1678 malloc_mutex_lock(&base_mtx);
1679 *(extent_node_t **)node = base_nodes;
1680 base_nodes = node;
1681 malloc_mutex_unlock(&base_mtx);
1682}
1683
1684/******************************************************************************/
1685
Jason Evansb7924f52009-06-23 19:01:18 -07001686#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07001687static void
1688stats_print(arena_t *arena)
1689{
1690 unsigned i, gap_start;
1691
1692 malloc_printf("dirty: %zu page%s dirty, %llu sweep%s,"
1693 " %llu madvise%s, %llu page%s purged\n",
1694 arena->ndirty, arena->ndirty == 1 ? "" : "s",
1695 arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s",
1696 arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s",
1697 arena->stats.purged, arena->stats.purged == 1 ? "" : "s");
1698
1699 malloc_printf(" allocated nmalloc ndalloc\n");
1700 malloc_printf("small: %12zu %12llu %12llu\n",
1701 arena->stats.allocated_small, arena->stats.nmalloc_small,
1702 arena->stats.ndalloc_small);
1703 malloc_printf("large: %12zu %12llu %12llu\n",
1704 arena->stats.allocated_large, arena->stats.nmalloc_large,
1705 arena->stats.ndalloc_large);
1706 malloc_printf("total: %12zu %12llu %12llu\n",
1707 arena->stats.allocated_small + arena->stats.allocated_large,
1708 arena->stats.nmalloc_small + arena->stats.nmalloc_large,
1709 arena->stats.ndalloc_small + arena->stats.ndalloc_large);
1710 malloc_printf("mapped: %12zu\n", arena->stats.mapped);
1711
Jason Evansb7924f52009-06-23 19:01:18 -07001712#ifdef JEMALLOC_MAG
1713 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07001714 malloc_printf("bins: bin size regs pgs mags "
1715 "newruns reruns maxruns curruns\n");
1716 } else {
1717#endif
1718 malloc_printf("bins: bin size regs pgs requests "
1719 "newruns reruns maxruns curruns\n");
Jason Evansb7924f52009-06-23 19:01:18 -07001720#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07001721 }
1722#endif
1723 for (i = 0, gap_start = UINT_MAX; i < nbins; i++) {
1724 if (arena->bins[i].stats.nruns == 0) {
1725 if (gap_start == UINT_MAX)
1726 gap_start = i;
1727 } else {
1728 if (gap_start != UINT_MAX) {
1729 if (i > gap_start + 1) {
1730 /* Gap of more than one size class. */
1731 malloc_printf("[%u..%u]\n",
1732 gap_start, i - 1);
1733 } else {
1734 /* Gap of one size class. */
1735 malloc_printf("[%u]\n", gap_start);
1736 }
1737 gap_start = UINT_MAX;
1738 }
1739 malloc_printf(
1740 "%13u %1s %4u %4u %3u %9llu %9llu"
1741 " %9llu %7lu %7lu\n",
1742 i,
1743 i < ntbins ? "T" : i < ntbins + nqbins ? "Q" :
1744 i < ntbins + nqbins + ncbins ? "C" : "S",
1745 arena->bins[i].reg_size,
1746 arena->bins[i].nregs,
1747 arena->bins[i].run_size >> PAGE_SHIFT,
Jason Evansb7924f52009-06-23 19:01:18 -07001748#ifdef JEMALLOC_MAG
1749 (opt_mag) ? arena->bins[i].stats.nmags :
Jason Evans289053c2009-06-22 12:08:42 -07001750#endif
1751 arena->bins[i].stats.nrequests,
1752 arena->bins[i].stats.nruns,
1753 arena->bins[i].stats.reruns,
1754 arena->bins[i].stats.highruns,
1755 arena->bins[i].stats.curruns);
1756 }
1757 }
1758 if (gap_start != UINT_MAX) {
1759 if (i > gap_start + 1) {
1760 /* Gap of more than one size class. */
1761 malloc_printf("[%u..%u]\n", gap_start, i - 1);
1762 } else {
1763 /* Gap of one size class. */
1764 malloc_printf("[%u]\n", gap_start);
1765 }
1766 }
1767}
1768#endif
1769
1770/*
1771 * End Utility functions/macros.
1772 */
1773/******************************************************************************/
1774/*
1775 * Begin extent tree code.
1776 */
1777
Jason Evansb7924f52009-06-23 19:01:18 -07001778#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001779static inline int
1780extent_szad_comp(extent_node_t *a, extent_node_t *b)
1781{
1782 int ret;
1783 size_t a_size = a->size;
1784 size_t b_size = b->size;
1785
1786 ret = (a_size > b_size) - (a_size < b_size);
1787 if (ret == 0) {
1788 uintptr_t a_addr = (uintptr_t)a->addr;
1789 uintptr_t b_addr = (uintptr_t)b->addr;
1790
1791 ret = (a_addr > b_addr) - (a_addr < b_addr);
1792 }
1793
1794 return (ret);
1795}
1796
1797/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07001798rb_wrap(static, extent_tree_szad_, extent_tree_t, extent_node_t,
Jason Evans289053c2009-06-22 12:08:42 -07001799 link_szad, extent_szad_comp)
1800#endif
1801
1802static inline int
1803extent_ad_comp(extent_node_t *a, extent_node_t *b)
1804{
1805 uintptr_t a_addr = (uintptr_t)a->addr;
1806 uintptr_t b_addr = (uintptr_t)b->addr;
1807
1808 return ((a_addr > b_addr) - (a_addr < b_addr));
1809}
1810
1811/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07001812rb_wrap(static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
Jason Evans289053c2009-06-22 12:08:42 -07001813 extent_ad_comp)
1814
1815/*
1816 * End extent tree code.
1817 */
1818/******************************************************************************/
1819/*
1820 * Begin chunk management functions.
1821 */
1822
1823static void *
1824pages_map(void *addr, size_t size)
1825{
1826 void *ret;
1827
1828 /*
1829 * We don't use MAP_FIXED here, because it can cause the *replacement*
1830 * of existing mappings, and we only want to create new mappings.
1831 */
1832 ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
1833 -1, 0);
1834 assert(ret != NULL);
1835
1836 if (ret == MAP_FAILED)
1837 ret = NULL;
1838 else if (addr != NULL && ret != addr) {
1839 /*
1840 * We succeeded in mapping memory, but not in the right place.
1841 */
1842 if (munmap(ret, size) == -1) {
1843 char buf[STRERROR_BUF];
1844
1845 strerror_r(errno, buf, sizeof(buf));
Jason Evans804c9ec2009-06-22 17:44:33 -07001846 jemalloc_message("<jemalloc>",
1847 ": Error in munmap(): ", buf, "\n");
Jason Evans289053c2009-06-22 12:08:42 -07001848 if (opt_abort)
1849 abort();
1850 }
1851 ret = NULL;
1852 }
1853
1854 assert(ret == NULL || (addr == NULL && ret != addr)
1855 || (addr != NULL && ret == addr));
1856 return (ret);
1857}
1858
1859static void
1860pages_unmap(void *addr, size_t size)
1861{
1862
1863 if (munmap(addr, size) == -1) {
1864 char buf[STRERROR_BUF];
1865
1866 strerror_r(errno, buf, sizeof(buf));
Jason Evans804c9ec2009-06-22 17:44:33 -07001867 jemalloc_message("<jemalloc>",
1868 ": Error in munmap(): ", buf, "\n");
Jason Evans289053c2009-06-22 12:08:42 -07001869 if (opt_abort)
1870 abort();
1871 }
1872}
1873
Jason Evansb7924f52009-06-23 19:01:18 -07001874#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07001875static void *
1876chunk_alloc_dss(size_t size)
1877{
1878
1879 /*
1880 * sbrk() uses a signed increment argument, so take care not to
1881 * interpret a huge allocation request as a negative increment.
1882 */
1883 if ((intptr_t)size < 0)
1884 return (NULL);
1885
1886 malloc_mutex_lock(&dss_mtx);
1887 if (dss_prev != (void *)-1) {
1888 intptr_t incr;
1889
1890 /*
1891 * The loop is necessary to recover from races with other
1892 * threads that are using the DSS for something other than
1893 * malloc.
1894 */
1895 do {
1896 void *ret;
1897
1898 /* Get the current end of the DSS. */
1899 dss_max = sbrk(0);
1900
1901 /*
1902 * Calculate how much padding is necessary to
1903 * chunk-align the end of the DSS.
1904 */
1905 incr = (intptr_t)size
1906 - (intptr_t)CHUNK_ADDR2OFFSET(dss_max);
1907 if (incr == (intptr_t)size)
1908 ret = dss_max;
1909 else {
1910 ret = (void *)((intptr_t)dss_max + incr);
1911 incr += size;
1912 }
1913
1914 dss_prev = sbrk(incr);
1915 if (dss_prev == dss_max) {
1916 /* Success. */
1917 dss_max = (void *)((intptr_t)dss_prev + incr);
1918 malloc_mutex_unlock(&dss_mtx);
1919 return (ret);
1920 }
1921 } while (dss_prev != (void *)-1);
1922 }
1923 malloc_mutex_unlock(&dss_mtx);
1924
1925 return (NULL);
1926}
1927
1928static void *
1929chunk_recycle_dss(size_t size, bool zero)
1930{
1931 extent_node_t *node, key;
1932
1933 key.addr = NULL;
1934 key.size = size;
1935 malloc_mutex_lock(&dss_mtx);
1936 node = extent_tree_szad_nsearch(&dss_chunks_szad, &key);
1937 if (node != NULL) {
1938 void *ret = node->addr;
1939
1940 /* Remove node from the tree. */
1941 extent_tree_szad_remove(&dss_chunks_szad, node);
1942 if (node->size == size) {
1943 extent_tree_ad_remove(&dss_chunks_ad, node);
1944 base_node_dealloc(node);
1945 } else {
1946 /*
1947 * Insert the remainder of node's address range as a
1948 * smaller chunk. Its position within dss_chunks_ad
1949 * does not change.
1950 */
1951 assert(node->size > size);
1952 node->addr = (void *)((uintptr_t)node->addr + size);
1953 node->size -= size;
1954 extent_tree_szad_insert(&dss_chunks_szad, node);
1955 }
1956 malloc_mutex_unlock(&dss_mtx);
1957
1958 if (zero)
1959 memset(ret, 0, size);
1960 return (ret);
1961 }
1962 malloc_mutex_unlock(&dss_mtx);
1963
1964 return (NULL);
1965}
1966#endif
1967
1968static void *
1969chunk_alloc_mmap(size_t size)
1970{
1971 void *ret;
1972 size_t offset;
1973
1974 /*
1975 * Ideally, there would be a way to specify alignment to mmap() (like
1976 * NetBSD has), but in the absence of such a feature, we have to work
1977 * hard to efficiently create aligned mappings. The reliable, but
1978 * expensive method is to create a mapping that is over-sized, then
1979 * trim the excess. However, that always results in at least one call
1980 * to pages_unmap().
1981 *
1982 * A more optimistic approach is to try mapping precisely the right
1983 * amount, then try to append another mapping if alignment is off. In
1984 * practice, this works out well as long as the application is not
1985 * interleaving mappings via direct mmap() calls. If we do run into a
1986 * situation where there is an interleaved mapping and we are unable to
1987 * extend an unaligned mapping, our best option is to momentarily
1988 * revert to the reliable-but-expensive method. This will tend to
1989 * leave a gap in the memory map that is too small to cause later
1990 * problems for the optimistic method.
1991 */
1992
1993 ret = pages_map(NULL, size);
1994 if (ret == NULL)
1995 return (NULL);
1996
1997 offset = CHUNK_ADDR2OFFSET(ret);
1998 if (offset != 0) {
1999 /* Try to extend chunk boundary. */
2000 if (pages_map((void *)((uintptr_t)ret + size),
2001 chunksize - offset) == NULL) {
2002 /*
2003 * Extension failed. Clean up, then revert to the
2004 * reliable-but-expensive method.
2005 */
2006 pages_unmap(ret, size);
2007
2008 /* Beware size_t wrap-around. */
2009 if (size + chunksize <= size)
2010 return NULL;
2011
2012 ret = pages_map(NULL, size + chunksize);
2013 if (ret == NULL)
2014 return (NULL);
2015
2016 /* Clean up unneeded leading/trailing space. */
2017 offset = CHUNK_ADDR2OFFSET(ret);
2018 if (offset != 0) {
2019 /* Leading space. */
2020 pages_unmap(ret, chunksize - offset);
2021
2022 ret = (void *)((uintptr_t)ret +
2023 (chunksize - offset));
2024
2025 /* Trailing space. */
2026 pages_unmap((void *)((uintptr_t)ret + size),
2027 offset);
2028 } else {
2029 /* Trailing space only. */
2030 pages_unmap((void *)((uintptr_t)ret + size),
2031 chunksize);
2032 }
2033 } else {
2034 /* Clean up unneeded leading space. */
2035 pages_unmap(ret, chunksize - offset);
2036 ret = (void *)((uintptr_t)ret + (chunksize - offset));
2037 }
2038 }
2039
2040 return (ret);
2041}
2042
2043static void *
2044chunk_alloc(size_t size, bool zero)
2045{
2046 void *ret;
2047
2048 assert(size != 0);
2049 assert((size & chunksize_mask) == 0);
2050
Jason Evansb7924f52009-06-23 19:01:18 -07002051#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002052 if (opt_dss) {
2053 ret = chunk_recycle_dss(size, zero);
2054 if (ret != NULL) {
2055 goto RETURN;
2056 }
2057
2058 ret = chunk_alloc_dss(size);
2059 if (ret != NULL)
2060 goto RETURN;
2061 }
Jason Evansc9658dd2009-06-22 14:44:08 -07002062
2063 if (opt_mmap)
Jason Evans289053c2009-06-22 12:08:42 -07002064#endif
Jason Evansc9658dd2009-06-22 14:44:08 -07002065 {
2066 ret = chunk_alloc_mmap(size);
2067 if (ret != NULL)
2068 goto RETURN;
2069 }
Jason Evans289053c2009-06-22 12:08:42 -07002070
2071 /* All strategies for allocation failed. */
2072 ret = NULL;
2073RETURN:
Jason Evansb7924f52009-06-23 19:01:18 -07002074#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002075 if (ret != NULL) {
2076 stats_chunks.nchunks += (size / chunksize);
2077 stats_chunks.curchunks += (size / chunksize);
2078 }
2079 if (stats_chunks.curchunks > stats_chunks.highchunks)
2080 stats_chunks.highchunks = stats_chunks.curchunks;
2081#endif
2082
2083 assert(CHUNK_ADDR2BASE(ret) == ret);
2084 return (ret);
2085}
2086
Jason Evansb7924f52009-06-23 19:01:18 -07002087#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002088static extent_node_t *
2089chunk_dealloc_dss_record(void *chunk, size_t size)
2090{
2091 extent_node_t *node, *prev, key;
2092
2093 key.addr = (void *)((uintptr_t)chunk + size);
2094 node = extent_tree_ad_nsearch(&dss_chunks_ad, &key);
2095 /* Try to coalesce forward. */
2096 if (node != NULL && node->addr == key.addr) {
2097 /*
2098 * Coalesce chunk with the following address range. This does
2099 * not change the position within dss_chunks_ad, so only
2100 * remove/insert from/into dss_chunks_szad.
2101 */
2102 extent_tree_szad_remove(&dss_chunks_szad, node);
2103 node->addr = chunk;
2104 node->size += size;
2105 extent_tree_szad_insert(&dss_chunks_szad, node);
2106 } else {
2107 /*
2108 * Coalescing forward failed, so insert a new node. Drop
2109 * dss_mtx during node allocation, since it is possible that a
2110 * new base chunk will be allocated.
2111 */
2112 malloc_mutex_unlock(&dss_mtx);
2113 node = base_node_alloc();
2114 malloc_mutex_lock(&dss_mtx);
2115 if (node == NULL)
2116 return (NULL);
2117 node->addr = chunk;
2118 node->size = size;
2119 extent_tree_ad_insert(&dss_chunks_ad, node);
2120 extent_tree_szad_insert(&dss_chunks_szad, node);
2121 }
2122
2123 /* Try to coalesce backward. */
2124 prev = extent_tree_ad_prev(&dss_chunks_ad, node);
2125 if (prev != NULL && (void *)((uintptr_t)prev->addr + prev->size) ==
2126 chunk) {
2127 /*
2128 * Coalesce chunk with the previous address range. This does
2129 * not change the position within dss_chunks_ad, so only
2130 * remove/insert node from/into dss_chunks_szad.
2131 */
2132 extent_tree_szad_remove(&dss_chunks_szad, prev);
2133 extent_tree_ad_remove(&dss_chunks_ad, prev);
2134
2135 extent_tree_szad_remove(&dss_chunks_szad, node);
2136 node->addr = prev->addr;
2137 node->size += prev->size;
2138 extent_tree_szad_insert(&dss_chunks_szad, node);
2139
2140 base_node_dealloc(prev);
2141 }
2142
2143 return (node);
2144}
2145
2146static bool
2147chunk_dealloc_dss(void *chunk, size_t size)
2148{
2149
2150 malloc_mutex_lock(&dss_mtx);
2151 if ((uintptr_t)chunk >= (uintptr_t)dss_base
2152 && (uintptr_t)chunk < (uintptr_t)dss_max) {
2153 extent_node_t *node;
2154
2155 /* Try to coalesce with other unused chunks. */
2156 node = chunk_dealloc_dss_record(chunk, size);
2157 if (node != NULL) {
2158 chunk = node->addr;
2159 size = node->size;
2160 }
2161
2162 /* Get the current end of the DSS. */
2163 dss_max = sbrk(0);
2164
2165 /*
2166 * Try to shrink the DSS if this chunk is at the end of the
2167 * DSS. The sbrk() call here is subject to a race condition
2168 * with threads that use brk(2) or sbrk(2) directly, but the
2169 * alternative would be to leak memory for the sake of poorly
2170 * designed multi-threaded programs.
2171 */
2172 if ((void *)((uintptr_t)chunk + size) == dss_max
2173 && (dss_prev = sbrk(-(intptr_t)size)) == dss_max) {
2174 /* Success. */
2175 dss_max = (void *)((intptr_t)dss_prev - (intptr_t)size);
2176
2177 if (node != NULL) {
2178 extent_tree_szad_remove(&dss_chunks_szad, node);
2179 extent_tree_ad_remove(&dss_chunks_ad, node);
2180 base_node_dealloc(node);
2181 }
2182 malloc_mutex_unlock(&dss_mtx);
2183 } else {
2184 malloc_mutex_unlock(&dss_mtx);
Jason Evansc9658dd2009-06-22 14:44:08 -07002185 madvise(chunk, size, MADV_DONTNEED);
Jason Evans289053c2009-06-22 12:08:42 -07002186 }
2187
2188 return (false);
2189 }
2190 malloc_mutex_unlock(&dss_mtx);
2191
2192 return (true);
2193}
2194#endif
2195
2196static void
2197chunk_dealloc_mmap(void *chunk, size_t size)
2198{
2199
2200 pages_unmap(chunk, size);
2201}
2202
2203static void
2204chunk_dealloc(void *chunk, size_t size)
2205{
2206
2207 assert(chunk != NULL);
2208 assert(CHUNK_ADDR2BASE(chunk) == chunk);
2209 assert(size != 0);
2210 assert((size & chunksize_mask) == 0);
2211
Jason Evansb7924f52009-06-23 19:01:18 -07002212#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002213 stats_chunks.curchunks -= (size / chunksize);
2214#endif
2215
Jason Evansb7924f52009-06-23 19:01:18 -07002216#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07002217 if (opt_dss) {
2218 if (chunk_dealloc_dss(chunk, size) == false)
2219 return;
2220 }
2221
2222 if (opt_mmap)
2223#endif
2224 chunk_dealloc_mmap(chunk, size);
2225}
2226
2227/*
2228 * End chunk management functions.
2229 */
2230/******************************************************************************/
2231/*
2232 * Begin arena.
2233 */
2234
2235/*
2236 * Choose an arena based on a per-thread value (fast-path code, calls slow-path
2237 * code if necessary).
2238 */
2239static inline arena_t *
2240choose_arena(void)
2241{
2242 arena_t *ret;
2243
2244 /*
2245 * We can only use TLS if this is a PIC library, since for the static
2246 * library version, libc's malloc is used by TLS allocation, which
2247 * introduces a bootstrapping issue.
2248 */
2249#ifndef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -07002250 if (isthreaded == false) {
Jason Evans289053c2009-06-22 12:08:42 -07002251 /* Avoid the overhead of TLS for single-threaded operation. */
2252 return (arenas[0]);
2253 }
2254
2255 ret = arenas_map;
2256 if (ret == NULL) {
2257 ret = choose_arena_hard();
2258 assert(ret != NULL);
2259 }
2260#else
Jason Evansb7924f52009-06-23 19:01:18 -07002261 if (isthreaded && narenas > 1) {
Jason Evans289053c2009-06-22 12:08:42 -07002262 unsigned long ind;
2263
2264 /*
Jason Evansc9658dd2009-06-22 14:44:08 -07002265 * Hash pthread_self() to one of the arenas. There is a prime
Jason Evans289053c2009-06-22 12:08:42 -07002266 * number of arenas, so this has a reasonable chance of
2267 * working. Even so, the hashing can be easily thwarted by
Jason Evansc9658dd2009-06-22 14:44:08 -07002268 * inconvenient pthread_self() values. Without specific
2269 * knowledge of how pthread_self() calculates values, we can't
Jason Evans289053c2009-06-22 12:08:42 -07002270 * easily do much better than this.
2271 */
Jason Evansc9658dd2009-06-22 14:44:08 -07002272 ind = (unsigned long) pthread_self() % narenas;
Jason Evans289053c2009-06-22 12:08:42 -07002273
2274 /*
2275 * Optimistially assume that arenas[ind] has been initialized.
2276 * At worst, we find out that some other thread has already
2277 * done so, after acquiring the lock in preparation. Note that
2278 * this lazy locking also has the effect of lazily forcing
2279 * cache coherency; without the lock acquisition, there's no
2280 * guarantee that modification of arenas[ind] by another thread
2281 * would be seen on this CPU for an arbitrary amount of time.
2282 *
2283 * In general, this approach to modifying a synchronized value
2284 * isn't a good idea, but in this case we only ever modify the
2285 * value once, so things work out well.
2286 */
2287 ret = arenas[ind];
2288 if (ret == NULL) {
2289 /*
2290 * Avoid races with another thread that may have already
2291 * initialized arenas[ind].
2292 */
2293 malloc_spin_lock(&arenas_lock);
2294 if (arenas[ind] == NULL)
2295 ret = arenas_extend((unsigned)ind);
2296 else
2297 ret = arenas[ind];
2298 malloc_spin_unlock(&arenas_lock);
2299 }
2300 } else
2301 ret = arenas[0];
2302#endif
2303
2304 assert(ret != NULL);
2305 return (ret);
2306}
2307
2308#ifndef NO_TLS
2309/*
2310 * Choose an arena based on a per-thread value (slow-path code only, called
2311 * only by choose_arena()).
2312 */
2313static arena_t *
2314choose_arena_hard(void)
2315{
2316 arena_t *ret;
2317
Jason Evansb7924f52009-06-23 19:01:18 -07002318 assert(isthreaded);
Jason Evans289053c2009-06-22 12:08:42 -07002319
Jason Evansb7924f52009-06-23 19:01:18 -07002320#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07002321 /* Seed the PRNG used for arena load balancing. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002322 SPRN(balance, (uint32_t)(uintptr_t)(pthread_self()));
Jason Evans289053c2009-06-22 12:08:42 -07002323#endif
2324
2325 if (narenas > 1) {
Jason Evansb7924f52009-06-23 19:01:18 -07002326#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07002327 unsigned ind;
2328
2329 ind = PRN(balance, narenas_2pow);
2330 if ((ret = arenas[ind]) == NULL) {
2331 malloc_spin_lock(&arenas_lock);
2332 if ((ret = arenas[ind]) == NULL)
2333 ret = arenas_extend(ind);
2334 malloc_spin_unlock(&arenas_lock);
2335 }
2336#else
2337 malloc_spin_lock(&arenas_lock);
2338 if ((ret = arenas[next_arena]) == NULL)
2339 ret = arenas_extend(next_arena);
2340 next_arena = (next_arena + 1) % narenas;
2341 malloc_spin_unlock(&arenas_lock);
2342#endif
2343 } else
2344 ret = arenas[0];
2345
2346 arenas_map = ret;
2347
2348 return (ret);
2349}
2350#endif
2351
2352static inline int
2353arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
2354{
2355 uintptr_t a_chunk = (uintptr_t)a;
2356 uintptr_t b_chunk = (uintptr_t)b;
2357
2358 assert(a != NULL);
2359 assert(b != NULL);
2360
2361 return ((a_chunk > b_chunk) - (a_chunk < b_chunk));
2362}
2363
2364/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002365rb_wrap(static, arena_chunk_tree_dirty_, arena_chunk_tree_t,
Jason Evans289053c2009-06-22 12:08:42 -07002366 arena_chunk_t, link_dirty, arena_chunk_comp)
2367
2368static inline int
2369arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
2370{
2371 uintptr_t a_mapelm = (uintptr_t)a;
2372 uintptr_t b_mapelm = (uintptr_t)b;
2373
2374 assert(a != NULL);
2375 assert(b != NULL);
2376
2377 return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm));
2378}
2379
2380/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002381rb_wrap(static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
Jason Evans289053c2009-06-22 12:08:42 -07002382 link, arena_run_comp)
2383
2384static inline int
2385arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
2386{
2387 int ret;
2388 size_t a_size = a->bits & ~PAGE_MASK;
2389 size_t b_size = b->bits & ~PAGE_MASK;
2390
2391 ret = (a_size > b_size) - (a_size < b_size);
2392 if (ret == 0) {
2393 uintptr_t a_mapelm, b_mapelm;
2394
2395 if ((a->bits & CHUNK_MAP_KEY) == 0)
2396 a_mapelm = (uintptr_t)a;
2397 else {
2398 /*
2399 * Treat keys as though they are lower than anything
2400 * else.
2401 */
2402 a_mapelm = 0;
2403 }
2404 b_mapelm = (uintptr_t)b;
2405
2406 ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
2407 }
2408
2409 return (ret);
2410}
2411
2412/* Wrap red-black tree macros in functions. */
Jason Evansc9658dd2009-06-22 14:44:08 -07002413rb_wrap(static, arena_avail_tree_, arena_avail_tree_t,
Jason Evans289053c2009-06-22 12:08:42 -07002414 arena_chunk_map_t, link, arena_avail_comp)
2415
2416static inline void *
2417arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
2418{
2419 void *ret;
2420 unsigned i, mask, bit, regind;
2421
2422 assert(run->magic == ARENA_RUN_MAGIC);
2423 assert(run->regs_minelm < bin->regs_mask_nelms);
2424
2425 /*
2426 * Move the first check outside the loop, so that run->regs_minelm can
2427 * be updated unconditionally, without the possibility of updating it
2428 * multiple times.
2429 */
2430 i = run->regs_minelm;
2431 mask = run->regs_mask[i];
2432 if (mask != 0) {
2433 /* Usable allocation found. */
2434 bit = ffs((int)mask) - 1;
2435
2436 regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
2437 assert(regind < bin->nregs);
2438 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
2439 + (bin->reg_size * regind));
2440
2441 /* Clear bit. */
2442 mask ^= (1U << bit);
2443 run->regs_mask[i] = mask;
2444
2445 return (ret);
2446 }
2447
2448 for (i++; i < bin->regs_mask_nelms; i++) {
2449 mask = run->regs_mask[i];
2450 if (mask != 0) {
2451 /* Usable allocation found. */
2452 bit = ffs((int)mask) - 1;
2453
2454 regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
2455 assert(regind < bin->nregs);
2456 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
2457 + (bin->reg_size * regind));
2458
2459 /* Clear bit. */
2460 mask ^= (1U << bit);
2461 run->regs_mask[i] = mask;
2462
2463 /*
2464 * Make a note that nothing before this element
2465 * contains a free region.
2466 */
2467 run->regs_minelm = i; /* Low payoff: + (mask == 0); */
2468
2469 return (ret);
2470 }
2471 }
2472 /* Not reached. */
2473 assert(0);
2474 return (NULL);
2475}
2476
2477static inline void
2478arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
2479{
2480 unsigned diff, regind, elm, bit;
2481
2482 assert(run->magic == ARENA_RUN_MAGIC);
2483
2484 /*
2485 * Avoid doing division with a variable divisor if possible. Using
2486 * actual division here can reduce allocator throughput by over 20%!
2487 */
2488 diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
2489 if ((size & (size - 1)) == 0) {
2490 /*
2491 * log2_table allows fast division of a power of two in the
2492 * [1..128] range.
2493 *
2494 * (x / divisor) becomes (x >> log2_table[divisor - 1]).
2495 */
2496 static const unsigned char log2_table[] = {
2497 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
2498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
2499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2500 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
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, 0,
2504 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
2505 };
2506
2507 if (size <= 128)
2508 regind = (diff >> log2_table[size - 1]);
2509 else if (size <= 32768)
2510 regind = diff >> (8 + log2_table[(size >> 8) - 1]);
2511 else
2512 regind = diff / size;
2513 } else if (size < qspace_max) {
2514 /*
2515 * To divide by a number D that is not a power of two we
2516 * multiply by (2^21 / D) and then right shift by 21 positions.
2517 *
2518 * X / D
2519 *
2520 * becomes
2521 *
2522 * (X * qsize_invs[(D >> QUANTUM_2POW) - 3])
2523 * >> SIZE_INV_SHIFT
2524 *
2525 * We can omit the first three elements, because we never
2526 * divide by 0, and QUANTUM and 2*QUANTUM are both powers of
2527 * two, which are handled above.
2528 */
2529#define SIZE_INV_SHIFT 21
2530#define QSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << QUANTUM_2POW)) + 1)
2531 static const unsigned qsize_invs[] = {
2532 QSIZE_INV(3),
2533 QSIZE_INV(4), QSIZE_INV(5), QSIZE_INV(6), QSIZE_INV(7)
2534#if (QUANTUM_2POW < 4)
2535 ,
2536 QSIZE_INV(8), QSIZE_INV(9), QSIZE_INV(10), QSIZE_INV(11),
2537 QSIZE_INV(12),QSIZE_INV(13), QSIZE_INV(14), QSIZE_INV(15)
2538#endif
2539 };
2540 assert(QUANTUM * (((sizeof(qsize_invs)) / sizeof(unsigned)) + 3)
2541 >= (1U << QSPACE_MAX_2POW_DEFAULT));
2542
2543 if (size <= (((sizeof(qsize_invs) / sizeof(unsigned)) + 2) <<
2544 QUANTUM_2POW)) {
2545 regind = qsize_invs[(size >> QUANTUM_2POW) - 3] * diff;
2546 regind >>= SIZE_INV_SHIFT;
2547 } else
2548 regind = diff / size;
2549#undef QSIZE_INV
2550 } else if (size < cspace_max) {
2551#define CSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << CACHELINE_2POW)) + 1)
2552 static const unsigned csize_invs[] = {
2553 CSIZE_INV(3),
2554 CSIZE_INV(4), CSIZE_INV(5), CSIZE_INV(6), CSIZE_INV(7)
2555 };
2556 assert(CACHELINE * (((sizeof(csize_invs)) / sizeof(unsigned)) +
2557 3) >= (1U << CSPACE_MAX_2POW_DEFAULT));
2558
2559 if (size <= (((sizeof(csize_invs) / sizeof(unsigned)) + 2) <<
2560 CACHELINE_2POW)) {
2561 regind = csize_invs[(size >> CACHELINE_2POW) - 3] *
2562 diff;
2563 regind >>= SIZE_INV_SHIFT;
2564 } else
2565 regind = diff / size;
2566#undef CSIZE_INV
2567 } else {
2568#define SSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << SUBPAGE_2POW)) + 1)
2569 static const unsigned ssize_invs[] = {
2570 SSIZE_INV(3),
2571 SSIZE_INV(4), SSIZE_INV(5), SSIZE_INV(6), SSIZE_INV(7),
2572 SSIZE_INV(8), SSIZE_INV(9), SSIZE_INV(10), SSIZE_INV(11),
2573 SSIZE_INV(12), SSIZE_INV(13), SSIZE_INV(14), SSIZE_INV(15)
Jason Evansb7924f52009-06-23 19:01:18 -07002574#if (STATIC_PAGE_SHIFT == 13)
Jason Evans289053c2009-06-22 12:08:42 -07002575 ,
2576 SSIZE_INV(16), SSIZE_INV(17), SSIZE_INV(18), SSIZE_INV(19),
2577 SSIZE_INV(20), SSIZE_INV(21), SSIZE_INV(22), SSIZE_INV(23),
2578 SSIZE_INV(24), SSIZE_INV(25), SSIZE_INV(26), SSIZE_INV(27),
2579 SSIZE_INV(28), SSIZE_INV(29), SSIZE_INV(29), SSIZE_INV(30)
2580#endif
2581 };
2582 assert(SUBPAGE * (((sizeof(ssize_invs)) / sizeof(unsigned)) + 3)
2583 >= PAGE_SIZE);
2584
2585 if (size < (((sizeof(ssize_invs) / sizeof(unsigned)) + 2) <<
2586 SUBPAGE_2POW)) {
2587 regind = ssize_invs[(size >> SUBPAGE_2POW) - 3] * diff;
2588 regind >>= SIZE_INV_SHIFT;
2589 } else
2590 regind = diff / size;
2591#undef SSIZE_INV
2592 }
2593#undef SIZE_INV_SHIFT
2594 assert(diff == regind * size);
2595 assert(regind < bin->nregs);
2596
2597 elm = regind >> (SIZEOF_INT_2POW + 3);
2598 if (elm < run->regs_minelm)
2599 run->regs_minelm = elm;
2600 bit = regind - (elm << (SIZEOF_INT_2POW + 3));
2601 assert((run->regs_mask[elm] & (1U << bit)) == 0);
2602 run->regs_mask[elm] |= (1U << bit);
2603}
2604
2605static void
2606arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large,
2607 bool zero)
2608{
2609 arena_chunk_t *chunk;
2610 size_t old_ndirty, run_ind, total_pages, need_pages, rem_pages, i;
2611
2612 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
2613 old_ndirty = chunk->ndirty;
2614 run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
2615 >> PAGE_SHIFT);
2616 total_pages = (chunk->map[run_ind].bits & ~PAGE_MASK) >>
2617 PAGE_SHIFT;
2618 need_pages = (size >> PAGE_SHIFT);
2619 assert(need_pages > 0);
2620 assert(need_pages <= total_pages);
2621 rem_pages = total_pages - need_pages;
2622
2623 arena_avail_tree_remove(&arena->runs_avail, &chunk->map[run_ind]);
2624
2625 /* Keep track of trailing unused pages for later use. */
2626 if (rem_pages > 0) {
2627 chunk->map[run_ind+need_pages].bits = (rem_pages <<
2628 PAGE_SHIFT) | (chunk->map[run_ind+need_pages].bits &
2629 PAGE_MASK);
2630 chunk->map[run_ind+total_pages-1].bits = (rem_pages <<
2631 PAGE_SHIFT) | (chunk->map[run_ind+total_pages-1].bits &
2632 PAGE_MASK);
2633 arena_avail_tree_insert(&arena->runs_avail,
2634 &chunk->map[run_ind+need_pages]);
2635 }
2636
2637 for (i = 0; i < need_pages; i++) {
2638 /* Zero if necessary. */
2639 if (zero) {
2640 if ((chunk->map[run_ind + i].bits & CHUNK_MAP_ZEROED)
2641 == 0) {
2642 memset((void *)((uintptr_t)chunk + ((run_ind
2643 + i) << PAGE_SHIFT)), 0, PAGE_SIZE);
2644 /* CHUNK_MAP_ZEROED is cleared below. */
2645 }
2646 }
2647
2648 /* Update dirty page accounting. */
2649 if (chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) {
2650 chunk->ndirty--;
2651 arena->ndirty--;
2652 /* CHUNK_MAP_DIRTY is cleared below. */
2653 }
2654
2655 /* Initialize the chunk map. */
2656 if (large) {
2657 chunk->map[run_ind + i].bits = CHUNK_MAP_LARGE
2658 | CHUNK_MAP_ALLOCATED;
2659 } else {
2660 chunk->map[run_ind + i].bits = (size_t)run
2661 | CHUNK_MAP_ALLOCATED;
2662 }
2663 }
2664
2665 /*
2666 * Set the run size only in the first element for large runs. This is
2667 * primarily a debugging aid, since the lack of size info for trailing
2668 * pages only matters if the application tries to operate on an
2669 * interior pointer.
2670 */
2671 if (large)
2672 chunk->map[run_ind].bits |= size;
2673
2674 if (chunk->ndirty == 0 && old_ndirty > 0)
2675 arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk);
2676}
2677
2678static arena_chunk_t *
2679arena_chunk_alloc(arena_t *arena)
2680{
2681 arena_chunk_t *chunk;
2682 size_t i;
2683
2684 if (arena->spare != NULL) {
2685 chunk = arena->spare;
2686 arena->spare = NULL;
2687 } else {
2688 chunk = (arena_chunk_t *)chunk_alloc(chunksize, true);
2689 if (chunk == NULL)
2690 return (NULL);
Jason Evansb7924f52009-06-23 19:01:18 -07002691#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002692 arena->stats.mapped += chunksize;
2693#endif
2694
2695 chunk->arena = arena;
2696
2697 /*
2698 * Claim that no pages are in use, since the header is merely
2699 * overhead.
2700 */
2701 chunk->ndirty = 0;
2702
2703 /*
2704 * Initialize the map to contain one maximal free untouched run.
2705 */
2706 for (i = 0; i < arena_chunk_header_npages; i++)
2707 chunk->map[i].bits = 0;
2708 chunk->map[i].bits = arena_maxclass | CHUNK_MAP_ZEROED;
2709 for (i++; i < chunk_npages-1; i++) {
2710 chunk->map[i].bits = CHUNK_MAP_ZEROED;
2711 }
2712 chunk->map[chunk_npages-1].bits = arena_maxclass |
2713 CHUNK_MAP_ZEROED;
2714 }
2715
2716 /* Insert the run into the runs_avail tree. */
2717 arena_avail_tree_insert(&arena->runs_avail,
2718 &chunk->map[arena_chunk_header_npages]);
2719
2720 return (chunk);
2721}
2722
2723static void
2724arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
2725{
2726
2727 if (arena->spare != NULL) {
2728 if (arena->spare->ndirty > 0) {
2729 arena_chunk_tree_dirty_remove(
2730 &chunk->arena->chunks_dirty, arena->spare);
2731 arena->ndirty -= arena->spare->ndirty;
2732 }
2733 chunk_dealloc((void *)arena->spare, chunksize);
Jason Evansb7924f52009-06-23 19:01:18 -07002734#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002735 arena->stats.mapped -= chunksize;
2736#endif
2737 }
2738
2739 /*
2740 * Remove run from runs_avail, regardless of whether this chunk
2741 * will be cached, so that the arena does not use it. Dirty page
2742 * flushing only uses the chunks_dirty tree, so leaving this chunk in
2743 * the chunks_* trees is sufficient for that purpose.
2744 */
2745 arena_avail_tree_remove(&arena->runs_avail,
2746 &chunk->map[arena_chunk_header_npages]);
2747
2748 arena->spare = chunk;
2749}
2750
2751static arena_run_t *
2752arena_run_alloc(arena_t *arena, size_t size, bool large, bool zero)
2753{
2754 arena_chunk_t *chunk;
2755 arena_run_t *run;
2756 arena_chunk_map_t *mapelm, key;
2757
2758 assert(size <= arena_maxclass);
2759 assert((size & PAGE_MASK) == 0);
2760
2761 /* Search the arena's chunks for the lowest best fit. */
2762 key.bits = size | CHUNK_MAP_KEY;
2763 mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
2764 if (mapelm != NULL) {
2765 arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
2766 size_t pageind = ((uintptr_t)mapelm - (uintptr_t)run_chunk->map)
2767 / sizeof(arena_chunk_map_t);
2768
2769 run = (arena_run_t *)((uintptr_t)run_chunk + (pageind
2770 << PAGE_SHIFT));
2771 arena_run_split(arena, run, size, large, zero);
2772 return (run);
2773 }
2774
2775 /*
2776 * No usable runs. Create a new chunk from which to allocate the run.
2777 */
2778 chunk = arena_chunk_alloc(arena);
2779 if (chunk == NULL)
2780 return (NULL);
2781 run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages <<
2782 PAGE_SHIFT));
2783 /* Update page map. */
2784 arena_run_split(arena, run, size, large, zero);
2785 return (run);
2786}
2787
2788static void
2789arena_purge(arena_t *arena)
2790{
2791 arena_chunk_t *chunk;
2792 size_t i, npages;
Jason Evansb7924f52009-06-23 19:01:18 -07002793#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07002794 size_t ndirty = 0;
2795
2796 rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty,
2797 chunk) {
2798 ndirty += chunk->ndirty;
2799 } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk)
2800 assert(ndirty == arena->ndirty);
2801#endif
2802 assert(arena->ndirty > opt_dirty_max);
2803
Jason Evansb7924f52009-06-23 19:01:18 -07002804#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002805 arena->stats.npurge++;
2806#endif
2807
2808 /*
2809 * Iterate downward through chunks until enough dirty memory has been
2810 * purged. Terminate as soon as possible in order to minimize the
2811 * number of system calls, even if a chunk has only been partially
2812 * purged.
2813 */
2814 while (arena->ndirty > (opt_dirty_max >> 1)) {
2815 chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty);
2816 assert(chunk != NULL);
2817
2818 for (i = chunk_npages - 1; chunk->ndirty > 0; i--) {
2819 assert(i >= arena_chunk_header_npages);
2820
2821 if (chunk->map[i].bits & CHUNK_MAP_DIRTY) {
2822 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
2823 /* Find adjacent dirty run(s). */
2824 for (npages = 1; i > arena_chunk_header_npages
2825 && (chunk->map[i - 1].bits &
2826 CHUNK_MAP_DIRTY); npages++) {
2827 i--;
2828 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
2829 }
2830 chunk->ndirty -= npages;
2831 arena->ndirty -= npages;
2832
2833 madvise((void *)((uintptr_t)chunk + (i <<
2834 PAGE_SHIFT)), (npages << PAGE_SHIFT),
Jason Evansc9658dd2009-06-22 14:44:08 -07002835 MADV_DONTNEED);
Jason Evansb7924f52009-06-23 19:01:18 -07002836#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07002837 arena->stats.nmadvise++;
2838 arena->stats.purged += npages;
2839#endif
2840 if (arena->ndirty <= (opt_dirty_max >> 1))
2841 break;
2842 }
2843 }
2844
2845 if (chunk->ndirty == 0) {
2846 arena_chunk_tree_dirty_remove(&arena->chunks_dirty,
2847 chunk);
2848 }
2849 }
2850}
2851
2852static void
2853arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty)
2854{
2855 arena_chunk_t *chunk;
2856 size_t size, run_ind, run_pages;
2857
2858 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
2859 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk)
2860 >> PAGE_SHIFT);
2861 assert(run_ind >= arena_chunk_header_npages);
2862 assert(run_ind < chunk_npages);
2863 if ((chunk->map[run_ind].bits & CHUNK_MAP_LARGE) != 0)
2864 size = chunk->map[run_ind].bits & ~PAGE_MASK;
2865 else
2866 size = run->bin->run_size;
2867 run_pages = (size >> PAGE_SHIFT);
2868
2869 /* Mark pages as unallocated in the chunk map. */
2870 if (dirty) {
2871 size_t i;
2872
2873 for (i = 0; i < run_pages; i++) {
2874 assert((chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY)
2875 == 0);
2876 chunk->map[run_ind + i].bits = CHUNK_MAP_DIRTY;
2877 }
2878
2879 if (chunk->ndirty == 0) {
2880 arena_chunk_tree_dirty_insert(&arena->chunks_dirty,
2881 chunk);
2882 }
2883 chunk->ndirty += run_pages;
2884 arena->ndirty += run_pages;
2885 } else {
2886 size_t i;
2887
2888 for (i = 0; i < run_pages; i++) {
2889 chunk->map[run_ind + i].bits &= ~(CHUNK_MAP_LARGE |
2890 CHUNK_MAP_ALLOCATED);
2891 }
2892 }
2893 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2894 PAGE_MASK);
2895 chunk->map[run_ind+run_pages-1].bits = size |
2896 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2897
2898 /* Try to coalesce forward. */
2899 if (run_ind + run_pages < chunk_npages &&
2900 (chunk->map[run_ind+run_pages].bits & CHUNK_MAP_ALLOCATED) == 0) {
2901 size_t nrun_size = chunk->map[run_ind+run_pages].bits &
2902 ~PAGE_MASK;
2903
2904 /*
2905 * Remove successor from runs_avail; the coalesced run is
2906 * inserted later.
2907 */
2908 arena_avail_tree_remove(&arena->runs_avail,
2909 &chunk->map[run_ind+run_pages]);
2910
2911 size += nrun_size;
2912 run_pages = size >> PAGE_SHIFT;
2913
2914 assert((chunk->map[run_ind+run_pages-1].bits & ~PAGE_MASK)
2915 == nrun_size);
2916 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2917 PAGE_MASK);
2918 chunk->map[run_ind+run_pages-1].bits = size |
2919 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2920 }
2921
2922 /* Try to coalesce backward. */
2923 if (run_ind > arena_chunk_header_npages && (chunk->map[run_ind-1].bits &
2924 CHUNK_MAP_ALLOCATED) == 0) {
2925 size_t prun_size = chunk->map[run_ind-1].bits & ~PAGE_MASK;
2926
2927 run_ind -= prun_size >> PAGE_SHIFT;
2928
2929 /*
2930 * Remove predecessor from runs_avail; the coalesced run is
2931 * inserted later.
2932 */
2933 arena_avail_tree_remove(&arena->runs_avail,
2934 &chunk->map[run_ind]);
2935
2936 size += prun_size;
2937 run_pages = size >> PAGE_SHIFT;
2938
2939 assert((chunk->map[run_ind].bits & ~PAGE_MASK) ==
2940 prun_size);
2941 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
2942 PAGE_MASK);
2943 chunk->map[run_ind+run_pages-1].bits = size |
2944 (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK);
2945 }
2946
2947 /* Insert into runs_avail, now that coalescing is complete. */
2948 arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind]);
2949
2950 /* Deallocate chunk if it is now completely unused. */
2951 if ((chunk->map[arena_chunk_header_npages].bits & (~PAGE_MASK |
2952 CHUNK_MAP_ALLOCATED)) == arena_maxclass)
2953 arena_chunk_dealloc(arena, chunk);
2954
2955 /* Enforce opt_dirty_max. */
2956 if (arena->ndirty > opt_dirty_max)
2957 arena_purge(arena);
2958}
2959
2960static void
2961arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
2962 size_t oldsize, size_t newsize)
2963{
2964 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
2965 size_t head_npages = (oldsize - newsize) >> PAGE_SHIFT;
2966
2967 assert(oldsize > newsize);
2968
2969 /*
2970 * Update the chunk map so that arena_run_dalloc() can treat the
2971 * leading run as separately allocated.
2972 */
2973 chunk->map[pageind].bits = (oldsize - newsize) | CHUNK_MAP_LARGE |
2974 CHUNK_MAP_ALLOCATED;
2975 chunk->map[pageind+head_npages].bits = newsize | CHUNK_MAP_LARGE |
2976 CHUNK_MAP_ALLOCATED;
2977
2978 arena_run_dalloc(arena, run, false);
2979}
2980
2981static void
2982arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
2983 size_t oldsize, size_t newsize, bool dirty)
2984{
2985 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
2986 size_t npages = newsize >> PAGE_SHIFT;
2987
2988 assert(oldsize > newsize);
2989
2990 /*
2991 * Update the chunk map so that arena_run_dalloc() can treat the
2992 * trailing run as separately allocated.
2993 */
2994 chunk->map[pageind].bits = newsize | CHUNK_MAP_LARGE |
2995 CHUNK_MAP_ALLOCATED;
2996 chunk->map[pageind+npages].bits = (oldsize - newsize) | CHUNK_MAP_LARGE
2997 | CHUNK_MAP_ALLOCATED;
2998
2999 arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize),
3000 dirty);
3001}
3002
3003static arena_run_t *
3004arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
3005{
3006 arena_chunk_map_t *mapelm;
3007 arena_run_t *run;
3008 unsigned i, remainder;
3009
3010 /* Look for a usable run. */
3011 mapelm = arena_run_tree_first(&bin->runs);
3012 if (mapelm != NULL) {
3013 /* run is guaranteed to have available space. */
3014 arena_run_tree_remove(&bin->runs, mapelm);
3015 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
Jason Evansb7924f52009-06-23 19:01:18 -07003016#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003017 bin->stats.reruns++;
3018#endif
3019 return (run);
3020 }
3021 /* No existing runs have any space available. */
3022
3023 /* Allocate a new run. */
3024 run = arena_run_alloc(arena, bin->run_size, false, false);
3025 if (run == NULL)
3026 return (NULL);
3027
3028 /* Initialize run internals. */
3029 run->bin = bin;
3030
3031 for (i = 0; i < bin->regs_mask_nelms - 1; i++)
3032 run->regs_mask[i] = UINT_MAX;
3033 remainder = bin->nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1);
3034 if (remainder == 0)
3035 run->regs_mask[i] = UINT_MAX;
3036 else {
3037 /* The last element has spare bits that need to be unset. */
3038 run->regs_mask[i] = (UINT_MAX >> ((1U << (SIZEOF_INT_2POW + 3))
3039 - remainder));
3040 }
3041
3042 run->regs_minelm = 0;
3043
3044 run->nfree = bin->nregs;
Jason Evansb7924f52009-06-23 19:01:18 -07003045#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07003046 run->magic = ARENA_RUN_MAGIC;
3047#endif
3048
Jason Evansb7924f52009-06-23 19:01:18 -07003049#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003050 bin->stats.nruns++;
3051 bin->stats.curruns++;
3052 if (bin->stats.curruns > bin->stats.highruns)
3053 bin->stats.highruns = bin->stats.curruns;
3054#endif
3055 return (run);
3056}
3057
3058/* bin->runcur must have space available before this function is called. */
3059static inline void *
3060arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run)
3061{
3062 void *ret;
3063
3064 assert(run->magic == ARENA_RUN_MAGIC);
3065 assert(run->nfree > 0);
3066
3067 ret = arena_run_reg_alloc(run, bin);
3068 assert(ret != NULL);
3069 run->nfree--;
3070
3071 return (ret);
3072}
3073
3074/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
3075static void *
3076arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
3077{
3078
3079 bin->runcur = arena_bin_nonfull_run_get(arena, bin);
3080 if (bin->runcur == NULL)
3081 return (NULL);
3082 assert(bin->runcur->magic == ARENA_RUN_MAGIC);
3083 assert(bin->runcur->nfree > 0);
3084
3085 return (arena_bin_malloc_easy(arena, bin, bin->runcur));
3086}
3087
3088/*
3089 * Calculate bin->run_size such that it meets the following constraints:
3090 *
3091 * *) bin->run_size >= min_run_size
3092 * *) bin->run_size <= arena_maxclass
3093 * *) bin->run_size <= RUN_MAX_SMALL
3094 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
3095 *
3096 * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
3097 * also calculated here, since these settings are all interdependent.
3098 */
3099static size_t
3100arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size)
3101{
3102 size_t try_run_size, good_run_size;
3103 unsigned good_nregs, good_mask_nelms, good_reg0_offset;
3104 unsigned try_nregs, try_mask_nelms, try_reg0_offset;
3105
3106 assert(min_run_size >= PAGE_SIZE);
3107 assert(min_run_size <= arena_maxclass);
3108 assert(min_run_size <= RUN_MAX_SMALL);
3109
3110 /*
3111 * Calculate known-valid settings before entering the run_size
3112 * expansion loop, so that the first part of the loop always copies
3113 * valid settings.
3114 *
3115 * The do..while loop iteratively reduces the number of regions until
3116 * the run header and the regions no longer overlap. A closed formula
3117 * would be quite messy, since there is an interdependency between the
3118 * header's mask length and the number of regions.
3119 */
3120 try_run_size = min_run_size;
3121 try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size)
3122 + 1; /* Counter-act try_nregs-- in loop. */
3123 do {
3124 try_nregs--;
3125 try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
3126 ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0);
3127 try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
3128 } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))
3129 > try_reg0_offset);
3130
3131 /* run_size expansion loop. */
3132 do {
3133 /*
3134 * Copy valid settings before trying more aggressive settings.
3135 */
3136 good_run_size = try_run_size;
3137 good_nregs = try_nregs;
3138 good_mask_nelms = try_mask_nelms;
3139 good_reg0_offset = try_reg0_offset;
3140
3141 /* Try more aggressive settings. */
3142 try_run_size += PAGE_SIZE;
3143 try_nregs = ((try_run_size - sizeof(arena_run_t)) /
3144 bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */
3145 do {
3146 try_nregs--;
3147 try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
3148 ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ?
3149 1 : 0);
3150 try_reg0_offset = try_run_size - (try_nregs *
3151 bin->reg_size);
3152 } while (sizeof(arena_run_t) + (sizeof(unsigned) *
3153 (try_mask_nelms - 1)) > try_reg0_offset);
3154 } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL
3155 && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX
3156 && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size);
3157
3158 assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1))
3159 <= good_reg0_offset);
3160 assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs);
3161
3162 /* Copy final settings. */
3163 bin->run_size = good_run_size;
3164 bin->nregs = good_nregs;
3165 bin->regs_mask_nelms = good_mask_nelms;
3166 bin->reg0_offset = good_reg0_offset;
3167
3168 return (good_run_size);
3169}
3170
Jason Evansb7924f52009-06-23 19:01:18 -07003171#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003172static inline void
3173arena_lock_balance(arena_t *arena)
3174{
3175 unsigned contention;
3176
3177 contention = malloc_spin_lock(&arena->lock);
3178 if (narenas > 1) {
3179 /*
3180 * Calculate the exponentially averaged contention for this
3181 * arena. Due to integer math always rounding down, this value
3182 * decays somewhat faster than normal.
3183 */
3184 arena->contention = (((uint64_t)arena->contention
3185 * (uint64_t)((1U << BALANCE_ALPHA_INV_2POW)-1))
3186 + (uint64_t)contention) >> BALANCE_ALPHA_INV_2POW;
3187 if (arena->contention >= opt_balance_threshold)
3188 arena_lock_balance_hard(arena);
3189 }
3190}
3191
3192static void
3193arena_lock_balance_hard(arena_t *arena)
3194{
3195 uint32_t ind;
3196
3197 arena->contention = 0;
Jason Evansb7924f52009-06-23 19:01:18 -07003198#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003199 arena->stats.nbalance++;
3200#endif
3201 ind = PRN(balance, narenas_2pow);
3202 if (arenas[ind] != NULL)
3203 arenas_map = arenas[ind];
3204 else {
3205 malloc_spin_lock(&arenas_lock);
3206 if (arenas[ind] != NULL)
3207 arenas_map = arenas[ind];
3208 else
3209 arenas_map = arenas_extend(ind);
3210 malloc_spin_unlock(&arenas_lock);
3211 }
3212}
3213#endif
3214
Jason Evansb7924f52009-06-23 19:01:18 -07003215#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003216static inline void *
3217mag_alloc(mag_t *mag)
3218{
3219
3220 if (mag->nrounds == 0)
3221 return (NULL);
3222 mag->nrounds--;
3223
3224 return (mag->rounds[mag->nrounds]);
3225}
3226
3227static void
3228mag_load(mag_t *mag)
3229{
3230 arena_t *arena;
3231 arena_bin_t *bin;
3232 arena_run_t *run;
3233 void *round;
3234 size_t i;
3235
3236 arena = choose_arena();
3237 bin = &arena->bins[mag->binind];
Jason Evansb7924f52009-06-23 19:01:18 -07003238#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003239 arena_lock_balance(arena);
3240#else
3241 malloc_spin_lock(&arena->lock);
3242#endif
3243 for (i = mag->nrounds; i < max_rounds; i++) {
3244 if ((run = bin->runcur) != NULL && run->nfree > 0)
3245 round = arena_bin_malloc_easy(arena, bin, run);
3246 else
3247 round = arena_bin_malloc_hard(arena, bin);
3248 if (round == NULL)
3249 break;
3250 mag->rounds[i] = round;
3251 }
Jason Evansb7924f52009-06-23 19:01:18 -07003252#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003253 bin->stats.nmags++;
3254 arena->stats.nmalloc_small += (i - mag->nrounds);
3255 arena->stats.allocated_small += (i - mag->nrounds) * bin->reg_size;
3256#endif
3257 malloc_spin_unlock(&arena->lock);
3258 mag->nrounds = i;
3259}
3260
3261static inline void *
3262mag_rack_alloc(mag_rack_t *rack, size_t size, bool zero)
3263{
3264 void *ret;
3265 bin_mags_t *bin_mags;
3266 mag_t *mag;
3267 size_t binind;
3268
3269 binind = size2bin[size];
3270 assert(binind < nbins);
3271 bin_mags = &rack->bin_mags[binind];
3272
3273 mag = bin_mags->curmag;
3274 if (mag == NULL) {
3275 /* Create an initial magazine for this size class. */
3276 assert(bin_mags->sparemag == NULL);
3277 mag = mag_create(choose_arena(), binind);
3278 if (mag == NULL)
3279 return (NULL);
3280 bin_mags->curmag = mag;
3281 mag_load(mag);
3282 }
3283
3284 ret = mag_alloc(mag);
3285 if (ret == NULL) {
3286 if (bin_mags->sparemag != NULL) {
3287 if (bin_mags->sparemag->nrounds > 0) {
3288 /* Swap magazines. */
3289 bin_mags->curmag = bin_mags->sparemag;
3290 bin_mags->sparemag = mag;
3291 mag = bin_mags->curmag;
3292 } else {
3293 /* Reload the current magazine. */
3294 mag_load(mag);
3295 }
3296 } else {
3297 /* Create a second magazine. */
3298 mag = mag_create(choose_arena(), binind);
3299 if (mag == NULL)
3300 return (NULL);
3301 mag_load(mag);
3302 bin_mags->sparemag = bin_mags->curmag;
3303 bin_mags->curmag = mag;
3304 }
3305 ret = mag_alloc(mag);
3306 if (ret == NULL)
3307 return (NULL);
3308 }
3309
3310 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003311#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003312 if (opt_junk)
3313 memset(ret, 0xa5, size);
3314 else if (opt_zero)
3315 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003316#endif
Jason Evans289053c2009-06-22 12:08:42 -07003317 } else
3318 memset(ret, 0, size);
3319
3320 return (ret);
3321}
3322#endif
3323
3324static inline void *
3325arena_malloc_small(arena_t *arena, size_t size, bool zero)
3326{
3327 void *ret;
3328 arena_bin_t *bin;
3329 arena_run_t *run;
3330 size_t binind;
3331
3332 binind = size2bin[size];
3333 assert(binind < nbins);
3334 bin = &arena->bins[binind];
3335 size = bin->reg_size;
3336
Jason Evansb7924f52009-06-23 19:01:18 -07003337#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003338 arena_lock_balance(arena);
3339#else
3340 malloc_spin_lock(&arena->lock);
3341#endif
3342 if ((run = bin->runcur) != NULL && run->nfree > 0)
3343 ret = arena_bin_malloc_easy(arena, bin, run);
3344 else
3345 ret = arena_bin_malloc_hard(arena, bin);
3346
3347 if (ret == NULL) {
3348 malloc_spin_unlock(&arena->lock);
3349 return (NULL);
3350 }
3351
Jason Evansb7924f52009-06-23 19:01:18 -07003352#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003353 bin->stats.nrequests++;
3354 arena->stats.nmalloc_small++;
3355 arena->stats.allocated_small += size;
3356#endif
3357 malloc_spin_unlock(&arena->lock);
3358
3359 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003360#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003361 if (opt_junk)
3362 memset(ret, 0xa5, size);
3363 else if (opt_zero)
3364 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003365#endif
Jason Evans289053c2009-06-22 12:08:42 -07003366 } else
3367 memset(ret, 0, size);
3368
3369 return (ret);
3370}
3371
3372static void *
3373arena_malloc_large(arena_t *arena, size_t size, bool zero)
3374{
3375 void *ret;
3376
3377 /* Large allocation. */
3378 size = PAGE_CEILING(size);
Jason Evansb7924f52009-06-23 19:01:18 -07003379#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003380 arena_lock_balance(arena);
3381#else
3382 malloc_spin_lock(&arena->lock);
3383#endif
3384 ret = (void *)arena_run_alloc(arena, size, true, zero);
3385 if (ret == NULL) {
3386 malloc_spin_unlock(&arena->lock);
3387 return (NULL);
3388 }
Jason Evansb7924f52009-06-23 19:01:18 -07003389#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003390 arena->stats.nmalloc_large++;
3391 arena->stats.allocated_large += size;
3392#endif
3393 malloc_spin_unlock(&arena->lock);
3394
3395 if (zero == false) {
Jason Evansb7924f52009-06-23 19:01:18 -07003396#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003397 if (opt_junk)
3398 memset(ret, 0xa5, size);
3399 else if (opt_zero)
3400 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003401#endif
Jason Evans289053c2009-06-22 12:08:42 -07003402 }
3403
3404 return (ret);
3405}
3406
3407static inline void *
3408arena_malloc(arena_t *arena, size_t size, bool zero)
3409{
3410
3411 assert(arena != NULL);
3412 assert(arena->magic == ARENA_MAGIC);
3413 assert(size != 0);
3414 assert(QUANTUM_CEILING(size) <= arena_maxclass);
3415
3416 if (size <= bin_maxclass) {
Jason Evansb7924f52009-06-23 19:01:18 -07003417#ifdef JEMALLOC_MAG
3418 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07003419 mag_rack_t *rack = mag_rack;
3420 if (rack == NULL) {
3421 rack = mag_rack_create(arena);
3422 if (rack == NULL)
3423 return (NULL);
3424 mag_rack = rack;
Jason Evansb7924f52009-06-23 19:01:18 -07003425 pthread_setspecific(mag_rack_tsd, rack);
Jason Evans289053c2009-06-22 12:08:42 -07003426 }
3427 return (mag_rack_alloc(rack, size, zero));
3428 } else
3429#endif
3430 return (arena_malloc_small(arena, size, zero));
3431 } else
3432 return (arena_malloc_large(arena, size, zero));
3433}
3434
3435static inline void *
3436imalloc(size_t size)
3437{
3438
3439 assert(size != 0);
3440
3441 if (size <= arena_maxclass)
3442 return (arena_malloc(choose_arena(), size, false));
3443 else
3444 return (huge_malloc(size, false));
3445}
3446
3447static inline void *
3448icalloc(size_t size)
3449{
3450
3451 if (size <= arena_maxclass)
3452 return (arena_malloc(choose_arena(), size, true));
3453 else
3454 return (huge_malloc(size, true));
3455}
3456
3457/* Only handles large allocations that require more than page alignment. */
3458static void *
3459arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size)
3460{
3461 void *ret;
3462 size_t offset;
3463 arena_chunk_t *chunk;
3464
3465 assert((size & PAGE_MASK) == 0);
3466 assert((alignment & PAGE_MASK) == 0);
3467
Jason Evansb7924f52009-06-23 19:01:18 -07003468#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003469 arena_lock_balance(arena);
3470#else
3471 malloc_spin_lock(&arena->lock);
3472#endif
3473 ret = (void *)arena_run_alloc(arena, alloc_size, true, false);
3474 if (ret == NULL) {
3475 malloc_spin_unlock(&arena->lock);
3476 return (NULL);
3477 }
3478
3479 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
3480
3481 offset = (uintptr_t)ret & (alignment - 1);
3482 assert((offset & PAGE_MASK) == 0);
3483 assert(offset < alloc_size);
3484 if (offset == 0)
3485 arena_run_trim_tail(arena, chunk, ret, alloc_size, size, false);
3486 else {
3487 size_t leadsize, trailsize;
3488
3489 leadsize = alignment - offset;
3490 if (leadsize > 0) {
3491 arena_run_trim_head(arena, chunk, ret, alloc_size,
3492 alloc_size - leadsize);
3493 ret = (void *)((uintptr_t)ret + leadsize);
3494 }
3495
3496 trailsize = alloc_size - leadsize - size;
3497 if (trailsize != 0) {
3498 /* Trim trailing space. */
3499 assert(trailsize < alloc_size);
3500 arena_run_trim_tail(arena, chunk, ret, size + trailsize,
3501 size, false);
3502 }
3503 }
3504
Jason Evansb7924f52009-06-23 19:01:18 -07003505#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003506 arena->stats.nmalloc_large++;
3507 arena->stats.allocated_large += size;
3508#endif
3509 malloc_spin_unlock(&arena->lock);
3510
Jason Evansb7924f52009-06-23 19:01:18 -07003511#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003512 if (opt_junk)
3513 memset(ret, 0xa5, size);
3514 else if (opt_zero)
3515 memset(ret, 0, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003516#endif
Jason Evans289053c2009-06-22 12:08:42 -07003517 return (ret);
3518}
3519
3520static inline void *
3521ipalloc(size_t alignment, size_t size)
3522{
3523 void *ret;
3524 size_t ceil_size;
3525
3526 /*
3527 * Round size up to the nearest multiple of alignment.
3528 *
3529 * This done, we can take advantage of the fact that for each small
3530 * size class, every object is aligned at the smallest power of two
3531 * that is non-zero in the base two representation of the size. For
3532 * example:
3533 *
3534 * Size | Base 2 | Minimum alignment
3535 * -----+----------+------------------
3536 * 96 | 1100000 | 32
3537 * 144 | 10100000 | 32
3538 * 192 | 11000000 | 64
3539 *
3540 * Depending on runtime settings, it is possible that arena_malloc()
3541 * will further round up to a power of two, but that never causes
3542 * correctness issues.
3543 */
3544 ceil_size = (size + (alignment - 1)) & (-alignment);
3545 /*
3546 * (ceil_size < size) protects against the combination of maximal
3547 * alignment and size greater than maximal alignment.
3548 */
3549 if (ceil_size < size) {
3550 /* size_t overflow. */
3551 return (NULL);
3552 }
3553
3554 if (ceil_size <= PAGE_SIZE || (alignment <= PAGE_SIZE
3555 && ceil_size <= arena_maxclass))
3556 ret = arena_malloc(choose_arena(), ceil_size, false);
3557 else {
3558 size_t run_size;
3559
3560 /*
3561 * We can't achieve subpage alignment, so round up alignment
3562 * permanently; it makes later calculations simpler.
3563 */
3564 alignment = PAGE_CEILING(alignment);
3565 ceil_size = PAGE_CEILING(size);
3566 /*
3567 * (ceil_size < size) protects against very large sizes within
3568 * PAGE_SIZE of SIZE_T_MAX.
3569 *
3570 * (ceil_size + alignment < ceil_size) protects against the
3571 * combination of maximal alignment and ceil_size large enough
3572 * to cause overflow. This is similar to the first overflow
3573 * check above, but it needs to be repeated due to the new
3574 * ceil_size value, which may now be *equal* to maximal
3575 * alignment, whereas before we only detected overflow if the
3576 * original size was *greater* than maximal alignment.
3577 */
3578 if (ceil_size < size || ceil_size + alignment < ceil_size) {
3579 /* size_t overflow. */
3580 return (NULL);
3581 }
3582
3583 /*
3584 * Calculate the size of the over-size run that arena_palloc()
3585 * would need to allocate in order to guarantee the alignment.
3586 */
3587 if (ceil_size >= alignment)
3588 run_size = ceil_size + alignment - PAGE_SIZE;
3589 else {
3590 /*
3591 * It is possible that (alignment << 1) will cause
3592 * overflow, but it doesn't matter because we also
3593 * subtract PAGE_SIZE, which in the case of overflow
3594 * leaves us with a very large run_size. That causes
3595 * the first conditional below to fail, which means
3596 * that the bogus run_size value never gets used for
3597 * anything important.
3598 */
3599 run_size = (alignment << 1) - PAGE_SIZE;
3600 }
3601
3602 if (run_size <= arena_maxclass) {
3603 ret = arena_palloc(choose_arena(), alignment, ceil_size,
3604 run_size);
3605 } else if (alignment <= chunksize)
3606 ret = huge_malloc(ceil_size, false);
3607 else
3608 ret = huge_palloc(alignment, ceil_size);
3609 }
3610
3611 assert(((uintptr_t)ret & (alignment - 1)) == 0);
3612 return (ret);
3613}
3614
3615/* Return the size of the allocation pointed to by ptr. */
3616static size_t
3617arena_salloc(const void *ptr)
3618{
3619 size_t ret;
3620 arena_chunk_t *chunk;
3621 size_t pageind, mapbits;
3622
3623 assert(ptr != NULL);
3624 assert(CHUNK_ADDR2BASE(ptr) != ptr);
3625
3626 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3627 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3628 mapbits = chunk->map[pageind].bits;
3629 assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
3630 if ((mapbits & CHUNK_MAP_LARGE) == 0) {
3631 arena_run_t *run = (arena_run_t *)(mapbits & ~PAGE_MASK);
3632 assert(run->magic == ARENA_RUN_MAGIC);
3633 ret = run->bin->reg_size;
3634 } else {
3635 ret = mapbits & ~PAGE_MASK;
3636 assert(ret != 0);
3637 }
3638
3639 return (ret);
3640}
3641
3642static inline size_t
3643isalloc(const void *ptr)
3644{
3645 size_t ret;
3646 arena_chunk_t *chunk;
3647
3648 assert(ptr != NULL);
3649
3650 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3651 if (chunk != ptr) {
3652 /* Region. */
3653 assert(chunk->arena->magic == ARENA_MAGIC);
3654
3655 ret = arena_salloc(ptr);
3656 } else {
3657 extent_node_t *node, key;
3658
3659 /* Chunk (huge allocation). */
3660
3661 malloc_mutex_lock(&huge_mtx);
3662
3663 /* Extract from tree of huge allocations. */
3664 key.addr = __DECONST(void *, ptr);
3665 node = extent_tree_ad_search(&huge, &key);
3666 assert(node != NULL);
3667
3668 ret = node->size;
3669
3670 malloc_mutex_unlock(&huge_mtx);
3671 }
3672
3673 return (ret);
3674}
3675
3676static inline void
3677arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3678 arena_chunk_map_t *mapelm)
3679{
3680 arena_run_t *run;
3681 arena_bin_t *bin;
3682 size_t size;
3683
3684 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
3685 assert(run->magic == ARENA_RUN_MAGIC);
3686 bin = run->bin;
3687 size = bin->reg_size;
3688
Jason Evansb7924f52009-06-23 19:01:18 -07003689#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003690 if (opt_junk)
3691 memset(ptr, 0x5a, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003692#endif
Jason Evans289053c2009-06-22 12:08:42 -07003693
3694 arena_run_reg_dalloc(run, bin, ptr, size);
3695 run->nfree++;
3696
3697 if (run->nfree == bin->nregs) {
3698 /* Deallocate run. */
3699 if (run == bin->runcur)
3700 bin->runcur = NULL;
3701 else if (bin->nregs != 1) {
3702 size_t run_pageind = (((uintptr_t)run -
3703 (uintptr_t)chunk)) >> PAGE_SHIFT;
3704 arena_chunk_map_t *run_mapelm =
3705 &chunk->map[run_pageind];
3706 /*
3707 * This block's conditional is necessary because if the
3708 * run only contains one region, then it never gets
3709 * inserted into the non-full runs tree.
3710 */
3711 arena_run_tree_remove(&bin->runs, run_mapelm);
3712 }
Jason Evansb7924f52009-06-23 19:01:18 -07003713#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07003714 run->magic = 0;
3715#endif
3716 arena_run_dalloc(arena, run, true);
Jason Evansb7924f52009-06-23 19:01:18 -07003717#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003718 bin->stats.curruns--;
3719#endif
3720 } else if (run->nfree == 1 && run != bin->runcur) {
3721 /*
3722 * Make sure that bin->runcur always refers to the lowest
3723 * non-full run, if one exists.
3724 */
3725 if (bin->runcur == NULL)
3726 bin->runcur = run;
3727 else if ((uintptr_t)run < (uintptr_t)bin->runcur) {
3728 /* Switch runcur. */
3729 if (bin->runcur->nfree > 0) {
3730 arena_chunk_t *runcur_chunk =
3731 CHUNK_ADDR2BASE(bin->runcur);
3732 size_t runcur_pageind =
3733 (((uintptr_t)bin->runcur -
3734 (uintptr_t)runcur_chunk)) >> PAGE_SHIFT;
3735 arena_chunk_map_t *runcur_mapelm =
3736 &runcur_chunk->map[runcur_pageind];
3737
3738 /* Insert runcur. */
3739 arena_run_tree_insert(&bin->runs,
3740 runcur_mapelm);
3741 }
3742 bin->runcur = run;
3743 } else {
3744 size_t run_pageind = (((uintptr_t)run -
3745 (uintptr_t)chunk)) >> PAGE_SHIFT;
3746 arena_chunk_map_t *run_mapelm =
3747 &chunk->map[run_pageind];
3748
3749 assert(arena_run_tree_search(&bin->runs, run_mapelm) ==
3750 NULL);
3751 arena_run_tree_insert(&bin->runs, run_mapelm);
3752 }
3753 }
Jason Evansb7924f52009-06-23 19:01:18 -07003754#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003755 arena->stats.allocated_small -= size;
3756 arena->stats.ndalloc_small++;
3757#endif
3758}
3759
Jason Evansb7924f52009-06-23 19:01:18 -07003760#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003761static void
3762mag_unload(mag_t *mag)
3763{
3764 arena_chunk_t *chunk;
3765 arena_t *arena;
3766 void *round;
3767 size_t i, ndeferred, nrounds;
3768
3769 for (ndeferred = mag->nrounds; ndeferred > 0;) {
3770 nrounds = ndeferred;
3771 /* Lock the arena associated with the first round. */
3772 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mag->rounds[0]);
3773 arena = chunk->arena;
Jason Evansb7924f52009-06-23 19:01:18 -07003774#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003775 arena_lock_balance(arena);
3776#else
3777 malloc_spin_lock(&arena->lock);
3778#endif
3779 /* Deallocate every round that belongs to the locked arena. */
3780 for (i = ndeferred = 0; i < nrounds; i++) {
3781 round = mag->rounds[i];
3782 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(round);
3783 if (chunk->arena == arena) {
3784 size_t pageind = (((uintptr_t)round -
3785 (uintptr_t)chunk) >> PAGE_SHIFT);
3786 arena_chunk_map_t *mapelm =
3787 &chunk->map[pageind];
3788 arena_dalloc_small(arena, chunk, round, mapelm);
3789 } else {
3790 /*
3791 * This round was allocated via a different
3792 * arena than the one that is currently locked.
3793 * Stash the round, so that it can be handled
3794 * in a future pass.
3795 */
3796 mag->rounds[ndeferred] = round;
3797 ndeferred++;
3798 }
3799 }
3800 malloc_spin_unlock(&arena->lock);
3801 }
3802
3803 mag->nrounds = 0;
3804}
3805
3806static inline void
3807mag_rack_dalloc(mag_rack_t *rack, void *ptr)
3808{
3809 arena_t *arena;
3810 arena_chunk_t *chunk;
3811 arena_run_t *run;
3812 arena_bin_t *bin;
3813 bin_mags_t *bin_mags;
3814 mag_t *mag;
3815 size_t pageind, binind;
3816 arena_chunk_map_t *mapelm;
3817
3818 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3819 arena = chunk->arena;
3820 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3821 mapelm = &chunk->map[pageind];
3822 run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK);
3823 assert(run->magic == ARENA_RUN_MAGIC);
3824 bin = run->bin;
3825 binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
3826 sizeof(arena_bin_t);
3827 assert(binind < nbins);
3828
Jason Evansb7924f52009-06-23 19:01:18 -07003829#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07003830 if (opt_junk)
3831 memset(ptr, 0x5a, arena->bins[binind].reg_size);
Jason Evansb7924f52009-06-23 19:01:18 -07003832#endif
Jason Evans289053c2009-06-22 12:08:42 -07003833
3834 bin_mags = &rack->bin_mags[binind];
3835 mag = bin_mags->curmag;
3836 if (mag == NULL) {
3837 /* Create an initial magazine for this size class. */
3838 assert(bin_mags->sparemag == NULL);
3839 mag = mag_create(choose_arena(), binind);
3840 if (mag == NULL) {
3841 malloc_spin_lock(&arena->lock);
3842 arena_dalloc_small(arena, chunk, ptr, mapelm);
3843 malloc_spin_unlock(&arena->lock);
3844 return;
3845 }
3846 bin_mags->curmag = mag;
3847 }
3848
3849 if (mag->nrounds == max_rounds) {
3850 if (bin_mags->sparemag != NULL) {
3851 if (bin_mags->sparemag->nrounds < max_rounds) {
3852 /* Swap magazines. */
3853 bin_mags->curmag = bin_mags->sparemag;
3854 bin_mags->sparemag = mag;
3855 mag = bin_mags->curmag;
3856 } else {
3857 /* Unload the current magazine. */
3858 mag_unload(mag);
3859 }
3860 } else {
3861 /* Create a second magazine. */
3862 mag = mag_create(choose_arena(), binind);
3863 if (mag == NULL) {
3864 mag = rack->bin_mags[binind].curmag;
3865 mag_unload(mag);
3866 } else {
3867 bin_mags->sparemag = bin_mags->curmag;
3868 bin_mags->curmag = mag;
3869 }
3870 }
3871 assert(mag->nrounds < max_rounds);
3872 }
3873 mag->rounds[mag->nrounds] = ptr;
3874 mag->nrounds++;
3875}
3876#endif
3877
3878static void
3879arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr)
3880{
3881 /* Large allocation. */
3882 malloc_spin_lock(&arena->lock);
3883
Jason Evansb7924f52009-06-23 19:01:18 -07003884#ifdef JEMALLOC_FILL
3885#ifndef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003886 if (opt_junk)
3887#endif
Jason Evansb7924f52009-06-23 19:01:18 -07003888#endif
Jason Evans289053c2009-06-22 12:08:42 -07003889 {
Jason Evansb7924f52009-06-23 19:01:18 -07003890#if (defined(JEMALLOC_FILL) || defined(JEMALLOC_STATS))
Jason Evans289053c2009-06-22 12:08:42 -07003891 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >>
3892 PAGE_SHIFT;
3893 size_t size = chunk->map[pageind].bits & ~PAGE_MASK;
Jason Evansb7924f52009-06-23 19:01:18 -07003894#endif
Jason Evans289053c2009-06-22 12:08:42 -07003895
Jason Evansb7924f52009-06-23 19:01:18 -07003896#ifdef JEMALLOC_FILL
3897#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003898 if (opt_junk)
3899#endif
3900 memset(ptr, 0x5a, size);
Jason Evansb7924f52009-06-23 19:01:18 -07003901#endif
3902#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003903 arena->stats.allocated_large -= size;
3904#endif
3905 }
Jason Evansb7924f52009-06-23 19:01:18 -07003906#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003907 arena->stats.ndalloc_large++;
3908#endif
3909
3910 arena_run_dalloc(arena, (arena_run_t *)ptr, true);
3911 malloc_spin_unlock(&arena->lock);
3912}
3913
3914static inline void
3915arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
3916{
3917 size_t pageind;
3918 arena_chunk_map_t *mapelm;
3919
3920 assert(arena != NULL);
3921 assert(arena->magic == ARENA_MAGIC);
3922 assert(chunk->arena == arena);
3923 assert(ptr != NULL);
3924 assert(CHUNK_ADDR2BASE(ptr) != ptr);
3925
3926 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
3927 mapelm = &chunk->map[pageind];
3928 assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
3929 if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
3930 /* Small allocation. */
Jason Evansb7924f52009-06-23 19:01:18 -07003931#ifdef JEMALLOC_MAG
3932 if (opt_mag) {
Jason Evans289053c2009-06-22 12:08:42 -07003933 mag_rack_t *rack = mag_rack;
3934 if (rack == NULL) {
3935 rack = mag_rack_create(arena);
3936 if (rack == NULL) {
3937 malloc_spin_lock(&arena->lock);
3938 arena_dalloc_small(arena, chunk, ptr,
3939 mapelm);
3940 malloc_spin_unlock(&arena->lock);
3941 }
3942 mag_rack = rack;
Jason Evansb7924f52009-06-23 19:01:18 -07003943 pthread_setspecific(mag_rack_tsd, rack);
Jason Evans289053c2009-06-22 12:08:42 -07003944 }
3945 mag_rack_dalloc(rack, ptr);
3946 } else {
3947#endif
3948 malloc_spin_lock(&arena->lock);
3949 arena_dalloc_small(arena, chunk, ptr, mapelm);
3950 malloc_spin_unlock(&arena->lock);
Jason Evansb7924f52009-06-23 19:01:18 -07003951#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07003952 }
3953#endif
3954 } else
3955 arena_dalloc_large(arena, chunk, ptr);
3956}
3957
3958static inline void
3959idalloc(void *ptr)
3960{
3961 arena_chunk_t *chunk;
3962
3963 assert(ptr != NULL);
3964
3965 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3966 if (chunk != ptr)
3967 arena_dalloc(chunk->arena, chunk, ptr);
3968 else
3969 huge_dalloc(ptr);
3970}
3971
3972static void
3973arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3974 size_t size, size_t oldsize)
3975{
3976
3977 assert(size < oldsize);
3978
3979 /*
3980 * Shrink the run, and make trailing pages available for other
3981 * allocations.
3982 */
Jason Evansb7924f52009-06-23 19:01:18 -07003983#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07003984 arena_lock_balance(arena);
3985#else
3986 malloc_spin_lock(&arena->lock);
3987#endif
3988 arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size,
3989 true);
Jason Evansb7924f52009-06-23 19:01:18 -07003990#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07003991 arena->stats.allocated_large -= oldsize - size;
3992#endif
3993 malloc_spin_unlock(&arena->lock);
3994}
3995
3996static bool
3997arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
3998 size_t size, size_t oldsize)
3999{
4000 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
4001 size_t npages = oldsize >> PAGE_SHIFT;
4002
4003 assert(oldsize == (chunk->map[pageind].bits & ~PAGE_MASK));
4004
4005 /* Try to extend the run. */
4006 assert(size > oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004007#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004008 arena_lock_balance(arena);
4009#else
4010 malloc_spin_lock(&arena->lock);
4011#endif
4012 if (pageind + npages < chunk_npages && (chunk->map[pageind+npages].bits
4013 & CHUNK_MAP_ALLOCATED) == 0 && (chunk->map[pageind+npages].bits &
4014 ~PAGE_MASK) >= size - oldsize) {
4015 /*
4016 * The next run is available and sufficiently large. Split the
4017 * following run, then merge the first part with the existing
4018 * allocation.
4019 */
4020 arena_run_split(arena, (arena_run_t *)((uintptr_t)chunk +
4021 ((pageind+npages) << PAGE_SHIFT)), size - oldsize, true,
4022 false);
4023
4024 chunk->map[pageind].bits = size | CHUNK_MAP_LARGE |
4025 CHUNK_MAP_ALLOCATED;
4026 chunk->map[pageind+npages].bits = CHUNK_MAP_LARGE |
4027 CHUNK_MAP_ALLOCATED;
4028
Jason Evansb7924f52009-06-23 19:01:18 -07004029#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004030 arena->stats.allocated_large += size - oldsize;
4031#endif
4032 malloc_spin_unlock(&arena->lock);
4033 return (false);
4034 }
4035 malloc_spin_unlock(&arena->lock);
4036
4037 return (true);
4038}
4039
4040/*
4041 * Try to resize a large allocation, in order to avoid copying. This will
4042 * always fail if growing an object, and the following run is already in use.
4043 */
4044static bool
4045arena_ralloc_large(void *ptr, size_t size, size_t oldsize)
4046{
4047 size_t psize;
4048
4049 psize = PAGE_CEILING(size);
4050 if (psize == oldsize) {
4051 /* Same size class. */
Jason Evansb7924f52009-06-23 19:01:18 -07004052#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004053 if (opt_junk && size < oldsize) {
4054 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize -
4055 size);
4056 }
Jason Evansb7924f52009-06-23 19:01:18 -07004057#endif
Jason Evans289053c2009-06-22 12:08:42 -07004058 return (false);
4059 } else {
4060 arena_chunk_t *chunk;
4061 arena_t *arena;
4062
4063 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
4064 arena = chunk->arena;
4065 assert(arena->magic == ARENA_MAGIC);
4066
4067 if (psize < oldsize) {
Jason Evansb7924f52009-06-23 19:01:18 -07004068#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004069 /* Fill before shrinking in order avoid a race. */
4070 if (opt_junk) {
4071 memset((void *)((uintptr_t)ptr + size), 0x5a,
4072 oldsize - size);
4073 }
Jason Evansb7924f52009-06-23 19:01:18 -07004074#endif
Jason Evans289053c2009-06-22 12:08:42 -07004075 arena_ralloc_large_shrink(arena, chunk, ptr, psize,
4076 oldsize);
4077 return (false);
4078 } else {
4079 bool ret = arena_ralloc_large_grow(arena, chunk, ptr,
4080 psize, oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004081#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004082 if (ret == false && opt_zero) {
4083 memset((void *)((uintptr_t)ptr + oldsize), 0,
4084 size - oldsize);
4085 }
Jason Evansb7924f52009-06-23 19:01:18 -07004086#endif
Jason Evans289053c2009-06-22 12:08:42 -07004087 return (ret);
4088 }
4089 }
4090}
4091
4092static void *
4093arena_ralloc(void *ptr, size_t size, size_t oldsize)
4094{
4095 void *ret;
4096 size_t copysize;
4097
4098 /* Try to avoid moving the allocation. */
4099 if (size <= bin_maxclass) {
4100 if (oldsize <= bin_maxclass && size2bin[size] ==
4101 size2bin[oldsize])
4102 goto IN_PLACE;
4103 } else {
4104 if (oldsize > bin_maxclass && oldsize <= arena_maxclass) {
4105 assert(size > bin_maxclass);
4106 if (arena_ralloc_large(ptr, size, oldsize) == false)
4107 return (ptr);
4108 }
4109 }
4110
4111 /*
4112 * If we get here, then size and oldsize are different enough that we
4113 * need to move the object. In that case, fall back to allocating new
4114 * space and copying.
4115 */
4116 ret = arena_malloc(choose_arena(), size, false);
4117 if (ret == NULL)
4118 return (NULL);
4119
4120 /* Junk/zero-filling were already done by arena_malloc(). */
4121 copysize = (size < oldsize) ? size : oldsize;
4122 memcpy(ret, ptr, copysize);
4123 idalloc(ptr);
4124 return (ret);
4125IN_PLACE:
Jason Evansb7924f52009-06-23 19:01:18 -07004126#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004127 if (opt_junk && size < oldsize)
4128 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size);
4129 else if (opt_zero && size > oldsize)
4130 memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize);
Jason Evansb7924f52009-06-23 19:01:18 -07004131#endif
Jason Evans289053c2009-06-22 12:08:42 -07004132 return (ptr);
4133}
4134
4135static inline void *
4136iralloc(void *ptr, size_t size)
4137{
4138 size_t oldsize;
4139
4140 assert(ptr != NULL);
4141 assert(size != 0);
4142
4143 oldsize = isalloc(ptr);
4144
4145 if (size <= arena_maxclass)
4146 return (arena_ralloc(ptr, size, oldsize));
4147 else
4148 return (huge_ralloc(ptr, size, oldsize));
4149}
4150
4151static bool
4152arena_new(arena_t *arena)
4153{
4154 unsigned i;
4155 arena_bin_t *bin;
4156 size_t prev_run_size;
4157
4158 if (malloc_spin_init(&arena->lock))
4159 return (true);
4160
Jason Evansb7924f52009-06-23 19:01:18 -07004161#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004162 memset(&arena->stats, 0, sizeof(arena_stats_t));
4163#endif
4164
4165 /* Initialize chunks. */
4166 arena_chunk_tree_dirty_new(&arena->chunks_dirty);
4167 arena->spare = NULL;
4168
4169 arena->ndirty = 0;
4170
4171 arena_avail_tree_new(&arena->runs_avail);
4172
Jason Evansb7924f52009-06-23 19:01:18 -07004173#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004174 arena->contention = 0;
4175#endif
4176
4177 /* Initialize bins. */
4178 prev_run_size = PAGE_SIZE;
4179
4180 i = 0;
Jason Evansb7924f52009-06-23 19:01:18 -07004181#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004182 /* (2^n)-spaced tiny bins. */
4183 for (; i < ntbins; i++) {
4184 bin = &arena->bins[i];
4185 bin->runcur = NULL;
4186 arena_run_tree_new(&bin->runs);
4187
4188 bin->reg_size = (1U << (TINY_MIN_2POW + i));
4189
4190 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4191
Jason Evansb7924f52009-06-23 19:01:18 -07004192#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004193 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4194#endif
4195 }
4196#endif
4197
4198 /* Quantum-spaced bins. */
4199 for (; i < ntbins + nqbins; i++) {
4200 bin = &arena->bins[i];
4201 bin->runcur = NULL;
4202 arena_run_tree_new(&bin->runs);
4203
4204 bin->reg_size = (i - ntbins + 1) << QUANTUM_2POW;
4205
4206 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4207
Jason Evansb7924f52009-06-23 19:01:18 -07004208#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004209 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4210#endif
4211 }
4212
4213 /* Cacheline-spaced bins. */
4214 for (; i < ntbins + nqbins + ncbins; i++) {
4215 bin = &arena->bins[i];
4216 bin->runcur = NULL;
4217 arena_run_tree_new(&bin->runs);
4218
4219 bin->reg_size = cspace_min + ((i - (ntbins + nqbins)) <<
4220 CACHELINE_2POW);
4221
4222 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4223
Jason Evansb7924f52009-06-23 19:01:18 -07004224#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004225 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4226#endif
4227 }
4228
4229 /* Subpage-spaced bins. */
4230 for (; i < nbins; i++) {
4231 bin = &arena->bins[i];
4232 bin->runcur = NULL;
4233 arena_run_tree_new(&bin->runs);
4234
4235 bin->reg_size = sspace_min + ((i - (ntbins + nqbins + ncbins))
4236 << SUBPAGE_2POW);
4237
4238 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
4239
Jason Evansb7924f52009-06-23 19:01:18 -07004240#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004241 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
4242#endif
4243 }
4244
Jason Evansb7924f52009-06-23 19:01:18 -07004245#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004246 arena->magic = ARENA_MAGIC;
4247#endif
4248
4249 return (false);
4250}
4251
4252/* Create a new arena and insert it into the arenas array at index ind. */
4253static arena_t *
4254arenas_extend(unsigned ind)
4255{
4256 arena_t *ret;
4257
4258 /* Allocate enough space for trailing bins. */
4259 ret = (arena_t *)base_alloc(sizeof(arena_t)
4260 + (sizeof(arena_bin_t) * (nbins - 1)));
4261 if (ret != NULL && arena_new(ret) == false) {
4262 arenas[ind] = ret;
4263 return (ret);
4264 }
4265 /* Only reached if there is an OOM error. */
4266
4267 /*
4268 * OOM here is quite inconvenient to propagate, since dealing with it
4269 * would require a check for failure in the fast path. Instead, punt
4270 * by using arenas[0]. In practice, this is an extremely unlikely
4271 * failure.
4272 */
Jason Evans804c9ec2009-06-22 17:44:33 -07004273 jemalloc_message("<jemalloc>",
4274 ": Error initializing arena\n", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004275 if (opt_abort)
4276 abort();
4277
4278 return (arenas[0]);
4279}
4280
Jason Evansb7924f52009-06-23 19:01:18 -07004281#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07004282static mag_t *
4283mag_create(arena_t *arena, size_t binind)
4284{
4285 mag_t *ret;
4286
4287 if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <=
4288 bin_maxclass) {
4289 ret = arena_malloc_small(arena, sizeof(mag_t) + (sizeof(void *)
4290 * (max_rounds - 1)), false);
4291 } else {
4292 ret = imalloc(sizeof(mag_t) + (sizeof(void *) * (max_rounds -
4293 1)));
4294 }
4295 if (ret == NULL)
4296 return (NULL);
4297 ret->binind = binind;
4298 ret->nrounds = 0;
4299
4300 return (ret);
4301}
4302
4303static void
4304mag_destroy(mag_t *mag)
4305{
4306 arena_t *arena;
4307 arena_chunk_t *chunk;
4308 size_t pageind;
4309 arena_chunk_map_t *mapelm;
4310
4311 chunk = CHUNK_ADDR2BASE(mag);
4312 arena = chunk->arena;
4313 pageind = (((uintptr_t)mag - (uintptr_t)chunk) >> PAGE_SHIFT);
4314 mapelm = &chunk->map[pageind];
4315
4316 assert(mag->nrounds == 0);
4317 if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <=
4318 bin_maxclass) {
4319 malloc_spin_lock(&arena->lock);
4320 arena_dalloc_small(arena, chunk, mag, mapelm);
4321 malloc_spin_unlock(&arena->lock);
4322 } else
4323 idalloc(mag);
4324}
4325
4326static mag_rack_t *
4327mag_rack_create(arena_t *arena)
4328{
4329
4330 assert(sizeof(mag_rack_t) + (sizeof(bin_mags_t *) * (nbins - 1)) <=
4331 bin_maxclass);
4332 return (arena_malloc_small(arena, sizeof(mag_rack_t) +
4333 (sizeof(bin_mags_t) * (nbins - 1)), true));
4334}
4335
4336static void
4337mag_rack_destroy(mag_rack_t *rack)
4338{
4339 arena_t *arena;
4340 arena_chunk_t *chunk;
4341 bin_mags_t *bin_mags;
4342 size_t i, pageind;
4343 arena_chunk_map_t *mapelm;
4344
4345 for (i = 0; i < nbins; i++) {
4346 bin_mags = &rack->bin_mags[i];
4347 if (bin_mags->curmag != NULL) {
4348 assert(bin_mags->curmag->binind == i);
4349 mag_unload(bin_mags->curmag);
4350 mag_destroy(bin_mags->curmag);
4351 }
4352 if (bin_mags->sparemag != NULL) {
4353 assert(bin_mags->sparemag->binind == i);
4354 mag_unload(bin_mags->sparemag);
4355 mag_destroy(bin_mags->sparemag);
4356 }
4357 }
4358
4359 chunk = CHUNK_ADDR2BASE(rack);
4360 arena = chunk->arena;
4361 pageind = (((uintptr_t)rack - (uintptr_t)chunk) >> PAGE_SHIFT);
4362 mapelm = &chunk->map[pageind];
4363
4364 malloc_spin_lock(&arena->lock);
4365 arena_dalloc_small(arena, chunk, rack, mapelm);
4366 malloc_spin_unlock(&arena->lock);
4367}
4368#endif
4369
4370/*
4371 * End arena.
4372 */
4373/******************************************************************************/
4374/*
4375 * Begin general internal functions.
4376 */
4377
4378static void *
4379huge_malloc(size_t size, bool zero)
4380{
4381 void *ret;
4382 size_t csize;
4383 extent_node_t *node;
4384
4385 /* Allocate one or more contiguous chunks for this request. */
4386
4387 csize = CHUNK_CEILING(size);
4388 if (csize == 0) {
4389 /* size is large enough to cause size_t wrap-around. */
4390 return (NULL);
4391 }
4392
4393 /* Allocate an extent node with which to track the chunk. */
4394 node = base_node_alloc();
4395 if (node == NULL)
4396 return (NULL);
4397
4398 ret = chunk_alloc(csize, zero);
4399 if (ret == NULL) {
4400 base_node_dealloc(node);
4401 return (NULL);
4402 }
4403
4404 /* Insert node into huge. */
4405 node->addr = ret;
4406 node->size = csize;
4407
4408 malloc_mutex_lock(&huge_mtx);
4409 extent_tree_ad_insert(&huge, node);
Jason Evansb7924f52009-06-23 19:01:18 -07004410#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004411 huge_nmalloc++;
4412 huge_allocated += csize;
4413#endif
4414 malloc_mutex_unlock(&huge_mtx);
4415
Jason Evansb7924f52009-06-23 19:01:18 -07004416#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004417 if (zero == false) {
4418 if (opt_junk)
4419 memset(ret, 0xa5, csize);
4420 else if (opt_zero)
4421 memset(ret, 0, csize);
4422 }
Jason Evansb7924f52009-06-23 19:01:18 -07004423#endif
Jason Evans289053c2009-06-22 12:08:42 -07004424
4425 return (ret);
4426}
4427
4428/* Only handles large allocations that require more than chunk alignment. */
4429static void *
4430huge_palloc(size_t alignment, size_t size)
4431{
4432 void *ret;
4433 size_t alloc_size, chunk_size, offset;
4434 extent_node_t *node;
4435
4436 /*
4437 * This allocation requires alignment that is even larger than chunk
4438 * alignment. This means that huge_malloc() isn't good enough.
4439 *
4440 * Allocate almost twice as many chunks as are demanded by the size or
4441 * alignment, in order to assure the alignment can be achieved, then
4442 * unmap leading and trailing chunks.
4443 */
4444 assert(alignment >= chunksize);
4445
4446 chunk_size = CHUNK_CEILING(size);
4447
4448 if (size >= alignment)
4449 alloc_size = chunk_size + alignment - chunksize;
4450 else
4451 alloc_size = (alignment << 1) - chunksize;
4452
4453 /* Allocate an extent node with which to track the chunk. */
4454 node = base_node_alloc();
4455 if (node == NULL)
4456 return (NULL);
4457
4458 ret = chunk_alloc(alloc_size, false);
4459 if (ret == NULL) {
4460 base_node_dealloc(node);
4461 return (NULL);
4462 }
4463
4464 offset = (uintptr_t)ret & (alignment - 1);
4465 assert((offset & chunksize_mask) == 0);
4466 assert(offset < alloc_size);
4467 if (offset == 0) {
4468 /* Trim trailing space. */
4469 chunk_dealloc((void *)((uintptr_t)ret + chunk_size), alloc_size
4470 - chunk_size);
4471 } else {
4472 size_t trailsize;
4473
4474 /* Trim leading space. */
4475 chunk_dealloc(ret, alignment - offset);
4476
4477 ret = (void *)((uintptr_t)ret + (alignment - offset));
4478
4479 trailsize = alloc_size - (alignment - offset) - chunk_size;
4480 if (trailsize != 0) {
4481 /* Trim trailing space. */
4482 assert(trailsize < alloc_size);
4483 chunk_dealloc((void *)((uintptr_t)ret + chunk_size),
4484 trailsize);
4485 }
4486 }
4487
4488 /* Insert node into huge. */
4489 node->addr = ret;
4490 node->size = chunk_size;
4491
4492 malloc_mutex_lock(&huge_mtx);
4493 extent_tree_ad_insert(&huge, node);
Jason Evansb7924f52009-06-23 19:01:18 -07004494#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004495 huge_nmalloc++;
4496 huge_allocated += chunk_size;
4497#endif
4498 malloc_mutex_unlock(&huge_mtx);
4499
Jason Evansb7924f52009-06-23 19:01:18 -07004500#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004501 if (opt_junk)
4502 memset(ret, 0xa5, chunk_size);
4503 else if (opt_zero)
4504 memset(ret, 0, chunk_size);
Jason Evansb7924f52009-06-23 19:01:18 -07004505#endif
Jason Evans289053c2009-06-22 12:08:42 -07004506
4507 return (ret);
4508}
4509
4510static void *
4511huge_ralloc(void *ptr, size_t size, size_t oldsize)
4512{
4513 void *ret;
4514 size_t copysize;
4515
4516 /* Avoid moving the allocation if the size class would not change. */
4517 if (oldsize > arena_maxclass &&
4518 CHUNK_CEILING(size) == CHUNK_CEILING(oldsize)) {
Jason Evansb7924f52009-06-23 19:01:18 -07004519#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07004520 if (opt_junk && size < oldsize) {
4521 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize
4522 - size);
4523 } else if (opt_zero && size > oldsize) {
4524 memset((void *)((uintptr_t)ptr + oldsize), 0, size
4525 - oldsize);
4526 }
Jason Evansb7924f52009-06-23 19:01:18 -07004527#endif
Jason Evans289053c2009-06-22 12:08:42 -07004528 return (ptr);
4529 }
4530
4531 /*
4532 * If we get here, then size and oldsize are different enough that we
4533 * need to use a different size class. In that case, fall back to
4534 * allocating new space and copying.
4535 */
4536 ret = huge_malloc(size, false);
4537 if (ret == NULL)
4538 return (NULL);
4539
4540 copysize = (size < oldsize) ? size : oldsize;
4541 memcpy(ret, ptr, copysize);
4542 idalloc(ptr);
4543 return (ret);
4544}
4545
4546static void
4547huge_dalloc(void *ptr)
4548{
4549 extent_node_t *node, key;
4550
4551 malloc_mutex_lock(&huge_mtx);
4552
4553 /* Extract from tree of huge allocations. */
4554 key.addr = ptr;
4555 node = extent_tree_ad_search(&huge, &key);
4556 assert(node != NULL);
4557 assert(node->addr == ptr);
4558 extent_tree_ad_remove(&huge, node);
4559
Jason Evansb7924f52009-06-23 19:01:18 -07004560#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004561 huge_ndalloc++;
4562 huge_allocated -= node->size;
4563#endif
4564
4565 malloc_mutex_unlock(&huge_mtx);
4566
4567 /* Unmap chunk. */
Jason Evansb7924f52009-06-23 19:01:18 -07004568#ifdef JEMALLOC_FILL
4569#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07004570 if (opt_dss && opt_junk)
4571 memset(node->addr, 0x5a, node->size);
4572#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004573#endif
Jason Evans289053c2009-06-22 12:08:42 -07004574 chunk_dealloc(node->addr, node->size);
4575
4576 base_node_dealloc(node);
4577}
4578
4579static void
4580malloc_print_stats(void)
4581{
4582
4583 if (opt_print_stats) {
4584 char s[UMAX2S_BUFSIZE];
Jason Evans804c9ec2009-06-22 17:44:33 -07004585 jemalloc_message("___ Begin jemalloc statistics ___\n", "", "",
Jason Evans289053c2009-06-22 12:08:42 -07004586 "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004587 jemalloc_message("Assertions ",
Jason Evans289053c2009-06-22 12:08:42 -07004588#ifdef NDEBUG
4589 "disabled",
4590#else
4591 "enabled",
4592#endif
4593 "\n", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004594 jemalloc_message("Boolean JEMALLOC_OPTIONS: ",
Jason Evans289053c2009-06-22 12:08:42 -07004595 opt_abort ? "A" : "a", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004596#ifdef JEMALLOC_DSS
Jason Evans804c9ec2009-06-22 17:44:33 -07004597 jemalloc_message(opt_dss ? "D" : "d", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004598#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004599#ifdef JEMALLOC_MAG
Jason Evans804c9ec2009-06-22 17:44:33 -07004600 jemalloc_message(opt_mag ? "G" : "g", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004601#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004602#ifdef JEMALLOC_FILL
Jason Evans804c9ec2009-06-22 17:44:33 -07004603 jemalloc_message(opt_junk ? "J" : "j", "", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004604#endif
4605#ifdef JEMALLOC_DSS
Jason Evans804c9ec2009-06-22 17:44:33 -07004606 jemalloc_message(opt_mmap ? "M" : "m", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004607#endif
Jason Evansb7924f52009-06-23 19:01:18 -07004608 jemalloc_message("P", "", "", "");
4609#ifdef JEMALLOC_STATS
4610 jemalloc_message(opt_utrace ? "U" : "u", "", "", "");
4611#endif
4612#ifdef JEMALLOC_SYSV
4613 jemalloc_message(opt_sysv ? "V" : "v", "", "", "");
4614#endif
4615#ifdef JEMALLOC_XMALLOC
4616 jemalloc_message(opt_xmalloc ? "X" : "x", "", "", "");
4617#endif
4618#ifdef JEMALLOC_FILL
4619 jemalloc_message(opt_zero ? "Z" : "z", "", "", "");
4620#endif
4621 jemalloc_message("\n", "", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004622
Jason Evans804c9ec2009-06-22 17:44:33 -07004623 jemalloc_message("CPUs: ", umax2s(ncpus, s), "\n", "");
4624 jemalloc_message("Max arenas: ", umax2s(narenas, s), "\n", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004625#ifdef JEMALLOC_BALANCE
Jason Evans804c9ec2009-06-22 17:44:33 -07004626 jemalloc_message("Arena balance threshold: ",
Jason Evans289053c2009-06-22 12:08:42 -07004627 umax2s(opt_balance_threshold, s), "\n", "");
4628#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004629 jemalloc_message("Pointer size: ", umax2s(sizeof(void *), s),
Jason Evans289053c2009-06-22 12:08:42 -07004630 "\n", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004631 jemalloc_message("Quantum size: ", umax2s(QUANTUM, s), "\n",
4632 "");
4633 jemalloc_message("Cacheline size (assumed): ",
4634 umax2s(CACHELINE, s), "\n", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004635#ifdef JEMALLOC_TINY
Jason Evans804c9ec2009-06-22 17:44:33 -07004636 jemalloc_message("Tiny 2^n-spaced sizes: [", umax2s((1U <<
Jason Evans289053c2009-06-22 12:08:42 -07004637 TINY_MIN_2POW), s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004638 jemalloc_message(umax2s((qspace_min >> 1), s), "]\n", "", "");
Jason Evans289053c2009-06-22 12:08:42 -07004639#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004640 jemalloc_message("Quantum-spaced sizes: [", umax2s(qspace_min,
Jason Evans289053c2009-06-22 12:08:42 -07004641 s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004642 jemalloc_message(umax2s(qspace_max, s), "]\n", "", "");
4643 jemalloc_message("Cacheline-spaced sizes: [",
4644 umax2s(cspace_min, s), "..", "");
4645 jemalloc_message(umax2s(cspace_max, s), "]\n", "", "");
4646 jemalloc_message("Subpage-spaced sizes: [", umax2s(sspace_min,
Jason Evans289053c2009-06-22 12:08:42 -07004647 s), "..", "");
Jason Evans804c9ec2009-06-22 17:44:33 -07004648 jemalloc_message(umax2s(sspace_max, s), "]\n", "", "");
Jason Evansb7924f52009-06-23 19:01:18 -07004649#ifdef JEMALLOC_MAG
Jason Evans804c9ec2009-06-22 17:44:33 -07004650 jemalloc_message("Rounds per magazine: ", umax2s(max_rounds,
4651 s), "\n", "");
Jason Evans289053c2009-06-22 12:08:42 -07004652#endif
Jason Evans804c9ec2009-06-22 17:44:33 -07004653 jemalloc_message("Max dirty pages per arena: ",
Jason Evans289053c2009-06-22 12:08:42 -07004654 umax2s(opt_dirty_max, s), "\n", "");
4655
Jason Evans804c9ec2009-06-22 17:44:33 -07004656 jemalloc_message("Chunk size: ", umax2s(chunksize, s), "", "");
4657 jemalloc_message(" (2^", umax2s(opt_chunk_2pow, s), ")\n", "");
Jason Evans289053c2009-06-22 12:08:42 -07004658
Jason Evansb7924f52009-06-23 19:01:18 -07004659#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07004660 {
4661 size_t allocated, mapped;
Jason Evansb7924f52009-06-23 19:01:18 -07004662#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004663 uint64_t nbalance = 0;
4664#endif
4665 unsigned i;
4666 arena_t *arena;
4667
4668 /* Calculate and print allocated/mapped stats. */
4669
4670 /* arenas. */
4671 for (i = 0, allocated = 0; i < narenas; i++) {
4672 if (arenas[i] != NULL) {
4673 malloc_spin_lock(&arenas[i]->lock);
4674 allocated +=
4675 arenas[i]->stats.allocated_small;
4676 allocated +=
4677 arenas[i]->stats.allocated_large;
Jason Evansb7924f52009-06-23 19:01:18 -07004678#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004679 nbalance += arenas[i]->stats.nbalance;
4680#endif
4681 malloc_spin_unlock(&arenas[i]->lock);
4682 }
4683 }
4684
4685 /* huge/base. */
4686 malloc_mutex_lock(&huge_mtx);
4687 allocated += huge_allocated;
4688 mapped = stats_chunks.curchunks * chunksize;
4689 malloc_mutex_unlock(&huge_mtx);
4690
4691 malloc_mutex_lock(&base_mtx);
4692 mapped += base_mapped;
4693 malloc_mutex_unlock(&base_mtx);
4694
4695 malloc_printf("Allocated: %zu, mapped: %zu\n",
4696 allocated, mapped);
4697
Jason Evansb7924f52009-06-23 19:01:18 -07004698#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07004699 malloc_printf("Arena balance reassignments: %llu\n",
4700 nbalance);
4701#endif
4702
4703 /* Print chunk stats. */
4704 {
4705 chunk_stats_t chunks_stats;
4706
4707 malloc_mutex_lock(&huge_mtx);
4708 chunks_stats = stats_chunks;
4709 malloc_mutex_unlock(&huge_mtx);
4710
4711 malloc_printf("chunks: nchunks "
4712 "highchunks curchunks\n");
4713 malloc_printf(" %13llu%13lu%13lu\n",
4714 chunks_stats.nchunks,
4715 chunks_stats.highchunks,
4716 chunks_stats.curchunks);
4717 }
4718
4719 /* Print chunk stats. */
4720 malloc_printf(
4721 "huge: nmalloc ndalloc allocated\n");
4722 malloc_printf(" %12llu %12llu %12zu\n",
4723 huge_nmalloc, huge_ndalloc, huge_allocated);
4724
4725 /* Print stats for each arena. */
4726 for (i = 0; i < narenas; i++) {
4727 arena = arenas[i];
4728 if (arena != NULL) {
4729 malloc_printf(
4730 "\narenas[%u]:\n", i);
4731 malloc_spin_lock(&arena->lock);
4732 stats_print(arena);
4733 malloc_spin_unlock(&arena->lock);
4734 }
4735 }
4736 }
Jason Evansb7924f52009-06-23 19:01:18 -07004737#endif /* #ifdef JEMALLOC_STATS */
Jason Evans804c9ec2009-06-22 17:44:33 -07004738 jemalloc_message("--- End jemalloc statistics ---\n", "", "",
4739 "");
Jason Evans289053c2009-06-22 12:08:42 -07004740 }
4741}
4742
Jason Evansb7924f52009-06-23 19:01:18 -07004743#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004744static void
4745size2bin_validate(void)
4746{
4747 size_t i, size, binind;
4748
4749 assert(size2bin[0] == 0xffU);
4750 i = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07004751# ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004752 /* Tiny. */
4753 for (; i < (1U << TINY_MIN_2POW); i++) {
4754 size = pow2_ceil(1U << TINY_MIN_2POW);
4755 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4756 assert(size2bin[i] == binind);
4757 }
4758 for (; i < qspace_min; i++) {
4759 size = pow2_ceil(i);
4760 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4761 assert(size2bin[i] == binind);
4762 }
4763# endif
4764 /* Quantum-spaced. */
4765 for (; i <= qspace_max; i++) {
4766 size = QUANTUM_CEILING(i);
4767 binind = ntbins + (size >> QUANTUM_2POW) - 1;
4768 assert(size2bin[i] == binind);
4769 }
4770 /* Cacheline-spaced. */
4771 for (; i <= cspace_max; i++) {
4772 size = CACHELINE_CEILING(i);
4773 binind = ntbins + nqbins + ((size - cspace_min) >>
4774 CACHELINE_2POW);
4775 assert(size2bin[i] == binind);
4776 }
4777 /* Sub-page. */
4778 for (; i <= sspace_max; i++) {
4779 size = SUBPAGE_CEILING(i);
4780 binind = ntbins + nqbins + ncbins + ((size - sspace_min)
4781 >> SUBPAGE_2POW);
4782 assert(size2bin[i] == binind);
4783 }
4784}
4785#endif
4786
4787static bool
4788size2bin_init(void)
4789{
4790
4791 if (opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT
4792 || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT)
4793 return (size2bin_init_hard());
4794
4795 size2bin = const_size2bin;
Jason Evansb7924f52009-06-23 19:01:18 -07004796#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004797 assert(sizeof(const_size2bin) == bin_maxclass + 1);
4798 size2bin_validate();
4799#endif
4800 return (false);
4801}
4802
4803static bool
4804size2bin_init_hard(void)
4805{
4806 size_t i, size, binind;
4807 uint8_t *custom_size2bin;
4808
4809 assert(opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT
4810 || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT);
4811
4812 custom_size2bin = (uint8_t *)base_alloc(bin_maxclass + 1);
4813 if (custom_size2bin == NULL)
4814 return (true);
4815
4816 custom_size2bin[0] = 0xffU;
4817 i = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07004818#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07004819 /* Tiny. */
4820 for (; i < (1U << TINY_MIN_2POW); i++) {
4821 size = pow2_ceil(1U << TINY_MIN_2POW);
4822 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4823 custom_size2bin[i] = binind;
4824 }
4825 for (; i < qspace_min; i++) {
4826 size = pow2_ceil(i);
4827 binind = ffs((int)(size >> (TINY_MIN_2POW + 1)));
4828 custom_size2bin[i] = binind;
4829 }
4830#endif
4831 /* Quantum-spaced. */
4832 for (; i <= qspace_max; i++) {
4833 size = QUANTUM_CEILING(i);
4834 binind = ntbins + (size >> QUANTUM_2POW) - 1;
4835 custom_size2bin[i] = binind;
4836 }
4837 /* Cacheline-spaced. */
4838 for (; i <= cspace_max; i++) {
4839 size = CACHELINE_CEILING(i);
4840 binind = ntbins + nqbins + ((size - cspace_min) >>
4841 CACHELINE_2POW);
4842 custom_size2bin[i] = binind;
4843 }
4844 /* Sub-page. */
4845 for (; i <= sspace_max; i++) {
4846 size = SUBPAGE_CEILING(i);
4847 binind = ntbins + nqbins + ncbins + ((size - sspace_min) >>
4848 SUBPAGE_2POW);
4849 custom_size2bin[i] = binind;
4850 }
4851
4852 size2bin = custom_size2bin;
Jason Evansb7924f52009-06-23 19:01:18 -07004853#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07004854 size2bin_validate();
4855#endif
4856 return (false);
4857}
4858
Jason Evansc9658dd2009-06-22 14:44:08 -07004859static unsigned
4860malloc_ncpus(void)
4861{
4862 unsigned ret;
Jason Evansb7924f52009-06-23 19:01:18 -07004863 long result;
Jason Evansc9658dd2009-06-22 14:44:08 -07004864
Jason Evansb7924f52009-06-23 19:01:18 -07004865 result = sysconf(_SC_NPROCESSORS_ONLN);
4866 if (result == -1) {
4867 /* Error. */
4868 ret = 1;
Jason Evansc9658dd2009-06-22 14:44:08 -07004869 }
Jason Evansb7924f52009-06-23 19:01:18 -07004870 ret = (unsigned)result;
Jason Evansc9658dd2009-06-22 14:44:08 -07004871
4872 return (ret);
4873}
Jason Evansb7924f52009-06-23 19:01:18 -07004874
Jason Evans289053c2009-06-22 12:08:42 -07004875/*
4876 * FreeBSD's pthreads implementation calls malloc(3), so the malloc
4877 * implementation has to take pains to avoid infinite recursion during
4878 * initialization.
4879 */
4880static inline bool
4881malloc_init(void)
4882{
4883
4884 if (malloc_initialized == false)
4885 return (malloc_init_hard());
4886
4887 return (false);
4888}
4889
4890static bool
4891malloc_init_hard(void)
4892{
4893 unsigned i;
4894 int linklen;
4895 char buf[PATH_MAX + 1];
4896 const char *opts;
Jason Evansb7924f52009-06-23 19:01:18 -07004897 arena_t *init_arenas[1];
Jason Evans289053c2009-06-22 12:08:42 -07004898
4899 malloc_mutex_lock(&init_lock);
Jason Evansb7924f52009-06-23 19:01:18 -07004900 if (malloc_initialized || malloc_initializer == pthread_self()) {
Jason Evans289053c2009-06-22 12:08:42 -07004901 /*
4902 * Another thread initialized the allocator before this one
Jason Evansb7924f52009-06-23 19:01:18 -07004903 * acquired init_lock, or this thread is the inializing thread,
4904 * and it is recursively allocating.
Jason Evans289053c2009-06-22 12:08:42 -07004905 */
4906 malloc_mutex_unlock(&init_lock);
4907 return (false);
4908 }
Jason Evansb7924f52009-06-23 19:01:18 -07004909 if (malloc_initializer != (unsigned long)0) {
4910 /* Busy-wait until the initializing thread completes. */
4911 do {
4912 malloc_mutex_unlock(&init_lock);
4913 CPU_SPINWAIT;
4914 malloc_mutex_lock(&init_lock);
4915 } while (malloc_initialized == false);
4916 return (false);
4917 }
Jason Evans289053c2009-06-22 12:08:42 -07004918
Jason Evansb7924f52009-06-23 19:01:18 -07004919#ifdef DYNAMIC_PAGE_SHIFT
Jason Evansc9658dd2009-06-22 14:44:08 -07004920 /* Get page size. */
4921 {
4922 long result;
4923
4924 result = sysconf(_SC_PAGESIZE);
4925 assert(result != -1);
Jason Evansb7924f52009-06-23 19:01:18 -07004926 pagesize = (unsigned)result;
4927
4928 /*
4929 * We assume that pagesize is a power of 2 when calculating
4930 * pagesize_mask and pagesize_2pow.
4931 */
4932 assert(((result - 1) & result) == 0);
4933 pagesize_mask = result - 1;
4934 pagesize_2pow = ffs((int)result) - 1;
Jason Evans289053c2009-06-22 12:08:42 -07004935 }
Jason Evansc9658dd2009-06-22 14:44:08 -07004936#endif
Jason Evans289053c2009-06-22 12:08:42 -07004937
4938 for (i = 0; i < 3; i++) {
4939 unsigned j;
4940
4941 /* Get runtime configuration. */
4942 switch (i) {
4943 case 0:
Jason Evans804c9ec2009-06-22 17:44:33 -07004944 if ((linklen = readlink("/etc/jemalloc.conf", buf,
Jason Evans289053c2009-06-22 12:08:42 -07004945 sizeof(buf) - 1)) != -1) {
4946 /*
Jason Evans804c9ec2009-06-22 17:44:33 -07004947 * Use the contents of the "/etc/jemalloc.conf"
Jason Evans289053c2009-06-22 12:08:42 -07004948 * symbolic link's name.
4949 */
4950 buf[linklen] = '\0';
4951 opts = buf;
4952 } else {
4953 /* No configuration specified. */
4954 buf[0] = '\0';
4955 opts = buf;
4956 }
4957 break;
4958 case 1:
Jason Evansb7924f52009-06-23 19:01:18 -07004959 if ((opts = getenv("JEMALLOC_OPTIONS")) != NULL) {
Jason Evans289053c2009-06-22 12:08:42 -07004960 /*
4961 * Do nothing; opts is already initialized to
Jason Evans804c9ec2009-06-22 17:44:33 -07004962 * the value of the JEMALLOC_OPTIONS
4963 * environment variable.
Jason Evans289053c2009-06-22 12:08:42 -07004964 */
4965 } else {
4966 /* No configuration specified. */
4967 buf[0] = '\0';
4968 opts = buf;
4969 }
4970 break;
4971 case 2:
Jason Evans804c9ec2009-06-22 17:44:33 -07004972 if (jemalloc_options != NULL) {
Jason Evans289053c2009-06-22 12:08:42 -07004973 /*
4974 * Use options that were compiled into the
4975 * program.
4976 */
Jason Evans804c9ec2009-06-22 17:44:33 -07004977 opts = jemalloc_options;
Jason Evans289053c2009-06-22 12:08:42 -07004978 } else {
4979 /* No configuration specified. */
4980 buf[0] = '\0';
4981 opts = buf;
4982 }
4983 break;
4984 default:
4985 /* NOTREACHED */
4986 assert(false);
Jason Evansb7924f52009-06-23 19:01:18 -07004987 buf[0] = '\0';
4988 opts = buf;
Jason Evans289053c2009-06-22 12:08:42 -07004989 }
4990
4991 for (j = 0; opts[j] != '\0'; j++) {
4992 unsigned k, nreps;
4993 bool nseen;
4994
4995 /* Parse repetition count, if any. */
4996 for (nreps = 0, nseen = false;; j++, nseen = true) {
4997 switch (opts[j]) {
4998 case '0': case '1': case '2': case '3':
4999 case '4': case '5': case '6': case '7':
5000 case '8': case '9':
5001 nreps *= 10;
5002 nreps += opts[j] - '0';
5003 break;
5004 default:
5005 goto MALLOC_OUT;
5006 }
5007 }
5008MALLOC_OUT:
5009 if (nseen == false)
5010 nreps = 1;
5011
5012 for (k = 0; k < nreps; k++) {
5013 switch (opts[j]) {
5014 case 'a':
5015 opt_abort = false;
5016 break;
5017 case 'A':
5018 opt_abort = true;
5019 break;
5020 case 'b':
Jason Evansb7924f52009-06-23 19:01:18 -07005021#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005022 opt_balance_threshold >>= 1;
5023#endif
5024 break;
5025 case 'B':
Jason Evansb7924f52009-06-23 19:01:18 -07005026#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005027 if (opt_balance_threshold == 0)
5028 opt_balance_threshold = 1;
5029 else if ((opt_balance_threshold << 1)
5030 > opt_balance_threshold)
5031 opt_balance_threshold <<= 1;
5032#endif
5033 break;
5034 case 'c':
5035 if (opt_cspace_max_2pow - 1 >
5036 opt_qspace_max_2pow &&
5037 opt_cspace_max_2pow >
5038 CACHELINE_2POW)
5039 opt_cspace_max_2pow--;
5040 break;
5041 case 'C':
5042 if (opt_cspace_max_2pow < PAGE_SHIFT
5043 - 1)
5044 opt_cspace_max_2pow++;
5045 break;
5046 case 'd':
Jason Evansb7924f52009-06-23 19:01:18 -07005047#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005048 opt_dss = false;
5049#endif
5050 break;
5051 case 'D':
Jason Evansb7924f52009-06-23 19:01:18 -07005052#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005053 opt_dss = true;
5054#endif
5055 break;
5056 case 'f':
5057 opt_dirty_max >>= 1;
5058 break;
5059 case 'F':
5060 if (opt_dirty_max == 0)
5061 opt_dirty_max = 1;
5062 else if ((opt_dirty_max << 1) != 0)
5063 opt_dirty_max <<= 1;
5064 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005065#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005066 case 'g':
5067 opt_mag = false;
5068 break;
5069 case 'G':
5070 opt_mag = true;
5071 break;
5072#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005073#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07005074 case 'j':
5075 opt_junk = false;
5076 break;
5077 case 'J':
5078 opt_junk = true;
5079 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005080#endif
Jason Evans289053c2009-06-22 12:08:42 -07005081 case 'k':
5082 /*
5083 * Chunks always require at least one
5084 * header page, so chunks can never be
5085 * smaller than two pages.
5086 */
5087 if (opt_chunk_2pow > PAGE_SHIFT + 1)
5088 opt_chunk_2pow--;
5089 break;
5090 case 'K':
5091 if (opt_chunk_2pow + 1 <
5092 (sizeof(size_t) << 3))
5093 opt_chunk_2pow++;
5094 break;
5095 case 'm':
Jason Evansb7924f52009-06-23 19:01:18 -07005096#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005097 opt_mmap = false;
5098#endif
5099 break;
5100 case 'M':
Jason Evansb7924f52009-06-23 19:01:18 -07005101#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005102 opt_mmap = true;
5103#endif
5104 break;
5105 case 'n':
5106 opt_narenas_lshift--;
5107 break;
5108 case 'N':
5109 opt_narenas_lshift++;
5110 break;
5111 case 'p':
5112 opt_print_stats = false;
5113 break;
5114 case 'P':
5115 opt_print_stats = true;
5116 break;
5117 case 'q':
5118 if (opt_qspace_max_2pow > QUANTUM_2POW)
5119 opt_qspace_max_2pow--;
5120 break;
5121 case 'Q':
5122 if (opt_qspace_max_2pow + 1 <
5123 opt_cspace_max_2pow)
5124 opt_qspace_max_2pow++;
5125 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005126#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005127 case 'R':
5128 if (opt_mag_size_2pow + 1 < (8U <<
5129 SIZEOF_PTR_2POW))
5130 opt_mag_size_2pow++;
5131 break;
5132 case 'r':
5133 /*
5134 * Make sure there's always at least
5135 * one round per magazine.
5136 */
5137 if ((1U << (opt_mag_size_2pow-1)) >=
5138 sizeof(mag_t))
5139 opt_mag_size_2pow--;
5140 break;
5141#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005142#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005143 case 'u':
5144 opt_utrace = false;
5145 break;
5146 case 'U':
5147 opt_utrace = true;
5148 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005149#endif
5150#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005151 case 'v':
5152 opt_sysv = false;
5153 break;
5154 case 'V':
5155 opt_sysv = true;
5156 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005157#endif
5158#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005159 case 'x':
5160 opt_xmalloc = false;
5161 break;
5162 case 'X':
5163 opt_xmalloc = true;
5164 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005165#endif
5166#ifdef JEMALLOC_FILL
Jason Evans289053c2009-06-22 12:08:42 -07005167 case 'z':
5168 opt_zero = false;
5169 break;
5170 case 'Z':
5171 opt_zero = true;
5172 break;
Jason Evansb7924f52009-06-23 19:01:18 -07005173#endif
Jason Evans289053c2009-06-22 12:08:42 -07005174 default: {
5175 char cbuf[2];
5176
5177 cbuf[0] = opts[j];
5178 cbuf[1] = '\0';
Jason Evans804c9ec2009-06-22 17:44:33 -07005179 jemalloc_message("<jemalloc>",
5180 ": Unsupported character "
Jason Evans289053c2009-06-22 12:08:42 -07005181 "in malloc options: '", cbuf,
5182 "'\n");
5183 }
5184 }
5185 }
5186 }
5187 }
5188
Jason Evansb7924f52009-06-23 19:01:18 -07005189#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005190 /* Make sure that there is some method for acquiring memory. */
5191 if (opt_dss == false && opt_mmap == false)
5192 opt_mmap = true;
5193#endif
5194
5195 /* Take care to call atexit() only once. */
5196 if (opt_print_stats) {
5197 /* Print statistics at exit. */
5198 atexit(malloc_print_stats);
5199 }
5200
Jason Evansc9658dd2009-06-22 14:44:08 -07005201 /* Register fork handlers. */
Jason Evans804c9ec2009-06-22 17:44:33 -07005202 pthread_atfork(jemalloc_prefork, jemalloc_postfork, jemalloc_postfork);
Jason Evansc9658dd2009-06-22 14:44:08 -07005203
Jason Evansb7924f52009-06-23 19:01:18 -07005204#ifdef JEMALLOC_MAG
Jason Evans289053c2009-06-22 12:08:42 -07005205 /*
5206 * Calculate the actual number of rounds per magazine, taking into
5207 * account header overhead.
5208 */
5209 max_rounds = (1LLU << (opt_mag_size_2pow - SIZEOF_PTR_2POW)) -
5210 (sizeof(mag_t) >> SIZEOF_PTR_2POW) + 1;
5211#endif
5212
5213 /* Set variables according to the value of opt_[qc]space_max_2pow. */
5214 qspace_max = (1U << opt_qspace_max_2pow);
5215 cspace_min = CACHELINE_CEILING(qspace_max);
5216 if (cspace_min == qspace_max)
5217 cspace_min += CACHELINE;
5218 cspace_max = (1U << opt_cspace_max_2pow);
5219 sspace_min = SUBPAGE_CEILING(cspace_max);
5220 if (sspace_min == cspace_max)
5221 sspace_min += SUBPAGE;
5222 assert(sspace_min < PAGE_SIZE);
5223 sspace_max = PAGE_SIZE - SUBPAGE;
5224
Jason Evansb7924f52009-06-23 19:01:18 -07005225#ifdef JEMALLOC_TINY
Jason Evans289053c2009-06-22 12:08:42 -07005226 assert(QUANTUM_2POW >= TINY_MIN_2POW);
5227#endif
5228 assert(ntbins <= QUANTUM_2POW);
5229 nqbins = qspace_max >> QUANTUM_2POW;
5230 ncbins = ((cspace_max - cspace_min) >> CACHELINE_2POW) + 1;
5231 nsbins = ((sspace_max - sspace_min) >> SUBPAGE_2POW) + 1;
5232 nbins = ntbins + nqbins + ncbins + nsbins;
5233
5234 if (size2bin_init()) {
5235 malloc_mutex_unlock(&init_lock);
5236 return (true);
5237 }
5238
5239 /* Set variables according to the value of opt_chunk_2pow. */
5240 chunksize = (1LU << opt_chunk_2pow);
5241 chunksize_mask = chunksize - 1;
5242 chunk_npages = (chunksize >> PAGE_SHIFT);
5243 {
5244 size_t header_size;
5245
5246 /*
5247 * Compute the header size such that it is large enough to
5248 * contain the page map.
5249 */
5250 header_size = sizeof(arena_chunk_t) +
5251 (sizeof(arena_chunk_map_t) * (chunk_npages - 1));
5252 arena_chunk_header_npages = (header_size >> PAGE_SHIFT) +
5253 ((header_size & PAGE_MASK) != 0);
5254 }
5255 arena_maxclass = chunksize - (arena_chunk_header_npages <<
5256 PAGE_SHIFT);
5257
5258 UTRACE(0, 0, 0);
5259
Jason Evansb7924f52009-06-23 19:01:18 -07005260#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005261 memset(&stats_chunks, 0, sizeof(chunk_stats_t));
5262#endif
5263
5264 /* Various sanity checks that regard configuration. */
5265 assert(chunksize >= PAGE_SIZE);
5266
5267 /* Initialize chunks data. */
Jason Evansc9658dd2009-06-22 14:44:08 -07005268 if (malloc_mutex_init(&huge_mtx)) {
5269 malloc_mutex_unlock(&init_lock);
5270 return (true);
5271 }
Jason Evans289053c2009-06-22 12:08:42 -07005272 extent_tree_ad_new(&huge);
Jason Evansb7924f52009-06-23 19:01:18 -07005273#ifdef JEMALLOC_DSS
Jason Evansc9658dd2009-06-22 14:44:08 -07005274 if (malloc_mutex_init(&dss_mtx)) {
5275 malloc_mutex_unlock(&init_lock);
5276 return (true);
5277 }
Jason Evans289053c2009-06-22 12:08:42 -07005278 dss_base = sbrk(0);
5279 dss_prev = dss_base;
5280 dss_max = dss_base;
5281 extent_tree_szad_new(&dss_chunks_szad);
5282 extent_tree_ad_new(&dss_chunks_ad);
5283#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005284#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005285 huge_nmalloc = 0;
5286 huge_ndalloc = 0;
5287 huge_allocated = 0;
5288#endif
5289
5290 /* Initialize base allocation data structures. */
Jason Evansb7924f52009-06-23 19:01:18 -07005291#ifdef JEMALLOC_STATS
Jason Evans289053c2009-06-22 12:08:42 -07005292 base_mapped = 0;
5293#endif
Jason Evansb7924f52009-06-23 19:01:18 -07005294#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005295 /*
5296 * Allocate a base chunk here, since it doesn't actually have to be
5297 * chunk-aligned. Doing this before allocating any other chunks allows
5298 * the use of space that would otherwise be wasted.
5299 */
5300 if (opt_dss)
5301 base_pages_alloc(0);
5302#endif
5303 base_nodes = NULL;
Jason Evansc9658dd2009-06-22 14:44:08 -07005304 if (malloc_mutex_init(&base_mtx)) {
5305 malloc_mutex_unlock(&init_lock);
5306 return (true);
5307 }
Jason Evans289053c2009-06-22 12:08:42 -07005308
Jason Evansb7924f52009-06-23 19:01:18 -07005309 /*
5310 * Create enough scaffolding to allow recursive allocation in
5311 * malloc_ncpus().
5312 */
5313 narenas = 1;
5314 arenas = init_arenas;
5315 memset(arenas, 0, sizeof(arena_t *) * narenas);
5316
5317 /*
5318 * Initialize one arena here. The rest are lazily created in
5319 * choose_arena_hard().
5320 */
5321 arenas_extend(0);
5322 if (arenas[0] == NULL) {
5323 malloc_mutex_unlock(&init_lock);
5324 return (true);
5325 }
5326
5327#ifndef NO_TLS
5328 /*
5329 * Assign the initial arena to the initial thread, in order to avoid
5330 * spurious creation of an extra arena if the application switches to
5331 * threaded mode.
5332 */
5333 arenas_map = arenas[0];
5334#endif
5335
5336#ifdef JEMALLOC_MAG
5337 if (pthread_key_create(&mag_rack_tsd, thread_cleanup) != 0) {
5338 jemalloc_message("<jemalloc>",
5339 ": Error in pthread_key_create()\n", "", "");
5340 abort();
5341 }
5342#endif
5343 /*
5344 * Seed here for the initial thread, since choose_arena_hard() is only
5345 * called for other threads. The seed value doesn't really matter.
5346 */
5347#ifdef JEMALLOC_BALANCE
5348 SPRN(balance, 42);
5349#endif
5350
5351 malloc_spin_init(&arenas_lock);
5352
5353 /* Get number of CPUs. */
5354 malloc_initializer = pthread_self();
5355 malloc_mutex_unlock(&init_lock);
5356 ncpus = malloc_ncpus();
5357 malloc_mutex_lock(&init_lock);
5358
Jason Evans289053c2009-06-22 12:08:42 -07005359 if (ncpus > 1) {
5360 /*
5361 * For SMP systems, create twice as many arenas as there are
5362 * CPUs by default.
5363 */
5364 opt_narenas_lshift++;
5365 }
5366
5367 /* Determine how many arenas to use. */
5368 narenas = ncpus;
5369 if (opt_narenas_lshift > 0) {
5370 if ((narenas << opt_narenas_lshift) > narenas)
5371 narenas <<= opt_narenas_lshift;
5372 /*
5373 * Make sure not to exceed the limits of what base_alloc() can
5374 * handle.
5375 */
5376 if (narenas * sizeof(arena_t *) > chunksize)
5377 narenas = chunksize / sizeof(arena_t *);
5378 } else if (opt_narenas_lshift < 0) {
5379 if ((narenas >> -opt_narenas_lshift) < narenas)
5380 narenas >>= -opt_narenas_lshift;
5381 /* Make sure there is at least one arena. */
5382 if (narenas == 0)
5383 narenas = 1;
5384 }
Jason Evansb7924f52009-06-23 19:01:18 -07005385#ifdef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005386 assert(narenas != 0);
5387 for (narenas_2pow = 0;
5388 (narenas >> (narenas_2pow + 1)) != 0;
5389 narenas_2pow++);
5390#endif
5391
5392#ifdef NO_TLS
5393 if (narenas > 1) {
5394 static const unsigned primes[] = {1, 3, 5, 7, 11, 13, 17, 19,
5395 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
5396 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
5397 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
5398 223, 227, 229, 233, 239, 241, 251, 257, 263};
5399 unsigned nprimes, parenas;
5400
5401 /*
5402 * Pick a prime number of hash arenas that is more than narenas
5403 * so that direct hashing of pthread_self() pointers tends to
5404 * spread allocations evenly among the arenas.
5405 */
5406 assert((narenas & 1) == 0); /* narenas must be even. */
5407 nprimes = (sizeof(primes) >> SIZEOF_INT_2POW);
5408 parenas = primes[nprimes - 1]; /* In case not enough primes. */
5409 for (i = 1; i < nprimes; i++) {
5410 if (primes[i] > narenas) {
5411 parenas = primes[i];
5412 break;
5413 }
5414 }
5415 narenas = parenas;
5416 }
5417#endif
5418
5419#ifndef NO_TLS
Jason Evansb7924f52009-06-23 19:01:18 -07005420# ifndef JEMALLOC_BALANCE
Jason Evans289053c2009-06-22 12:08:42 -07005421 next_arena = 0;
5422# endif
5423#endif
5424
5425 /* Allocate and initialize arenas. */
5426 arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
5427 if (arenas == NULL) {
5428 malloc_mutex_unlock(&init_lock);
5429 return (true);
5430 }
5431 /*
5432 * Zero the array. In practice, this should always be pre-zeroed,
5433 * since it was just mmap()ed, but let's be sure.
5434 */
5435 memset(arenas, 0, sizeof(arena_t *) * narenas);
Jason Evansb7924f52009-06-23 19:01:18 -07005436 /* Copy the pointer to the one arena that was already initialized. */
5437 arenas[0] = init_arenas[0];
Jason Evans289053c2009-06-22 12:08:42 -07005438
5439 malloc_initialized = true;
5440 malloc_mutex_unlock(&init_lock);
5441 return (false);
5442}
5443
5444/*
5445 * End general internal functions.
5446 */
5447/******************************************************************************/
5448/*
5449 * Begin malloc(3)-compatible functions.
5450 */
5451
5452void *
5453malloc(size_t size)
5454{
5455 void *ret;
5456
5457 if (malloc_init()) {
5458 ret = NULL;
5459 goto RETURN;
5460 }
5461
5462 if (size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005463#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005464 if (opt_sysv == false)
Jason Evansb7924f52009-06-23 19:01:18 -07005465#endif
Jason Evans289053c2009-06-22 12:08:42 -07005466 size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005467#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005468 else {
5469 ret = NULL;
5470 goto RETURN;
5471 }
Jason Evansb7924f52009-06-23 19:01:18 -07005472#endif
Jason Evans289053c2009-06-22 12:08:42 -07005473 }
5474
5475 ret = imalloc(size);
5476
5477RETURN:
5478 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005479#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005480 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005481 jemalloc_message("<jemalloc>",
5482 ": Error in malloc(): out of memory\n", "",
Jason Evans289053c2009-06-22 12:08:42 -07005483 "");
5484 abort();
5485 }
Jason Evansb7924f52009-06-23 19:01:18 -07005486#endif
Jason Evans289053c2009-06-22 12:08:42 -07005487 errno = ENOMEM;
5488 }
5489
5490 UTRACE(0, size, ret);
5491 return (ret);
5492}
5493
5494int
5495posix_memalign(void **memptr, size_t alignment, size_t size)
5496{
5497 int ret;
5498 void *result;
5499
5500 if (malloc_init())
5501 result = NULL;
5502 else {
5503 /* Make sure that alignment is a large enough power of 2. */
5504 if (((alignment - 1) & alignment) != 0
5505 || alignment < sizeof(void *)) {
Jason Evansb7924f52009-06-23 19:01:18 -07005506#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005507 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005508 jemalloc_message("<jemalloc>",
5509 ": Error in posix_memalign(): "
Jason Evans289053c2009-06-22 12:08:42 -07005510 "invalid alignment\n", "", "");
5511 abort();
5512 }
Jason Evansb7924f52009-06-23 19:01:18 -07005513#endif
Jason Evans289053c2009-06-22 12:08:42 -07005514 result = NULL;
5515 ret = EINVAL;
5516 goto RETURN;
5517 }
5518
5519 result = ipalloc(alignment, size);
5520 }
5521
5522 if (result == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005523#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005524 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005525 jemalloc_message("<jemalloc>",
5526 ": Error in posix_memalign(): out of memory\n",
Jason Evans289053c2009-06-22 12:08:42 -07005527 "", "");
5528 abort();
5529 }
Jason Evansb7924f52009-06-23 19:01:18 -07005530#endif
Jason Evans289053c2009-06-22 12:08:42 -07005531 ret = ENOMEM;
5532 goto RETURN;
5533 }
5534
5535 *memptr = result;
5536 ret = 0;
5537
5538RETURN:
5539 UTRACE(0, size, result);
5540 return (ret);
5541}
5542
5543void *
5544calloc(size_t num, size_t size)
5545{
5546 void *ret;
5547 size_t num_size;
5548
5549 if (malloc_init()) {
5550 num_size = 0;
5551 ret = NULL;
5552 goto RETURN;
5553 }
5554
5555 num_size = num * size;
5556 if (num_size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005557#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005558 if ((opt_sysv == false) && ((num == 0) || (size == 0)))
Jason Evansb7924f52009-06-23 19:01:18 -07005559#endif
Jason Evans289053c2009-06-22 12:08:42 -07005560 num_size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005561#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005562 else {
5563 ret = NULL;
5564 goto RETURN;
5565 }
Jason Evansb7924f52009-06-23 19:01:18 -07005566#endif
Jason Evans289053c2009-06-22 12:08:42 -07005567 /*
5568 * Try to avoid division here. We know that it isn't possible to
5569 * overflow during multiplication if neither operand uses any of the
5570 * most significant half of the bits in a size_t.
5571 */
5572 } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2)))
5573 && (num_size / size != num)) {
5574 /* size_t overflow. */
5575 ret = NULL;
5576 goto RETURN;
5577 }
5578
5579 ret = icalloc(num_size);
5580
5581RETURN:
5582 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005583#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005584 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005585 jemalloc_message("<jemalloc>",
5586 ": Error in calloc(): out of memory\n", "",
Jason Evans289053c2009-06-22 12:08:42 -07005587 "");
5588 abort();
5589 }
Jason Evansb7924f52009-06-23 19:01:18 -07005590#endif
Jason Evans289053c2009-06-22 12:08:42 -07005591 errno = ENOMEM;
5592 }
5593
5594 UTRACE(0, num_size, ret);
5595 return (ret);
5596}
5597
5598void *
5599realloc(void *ptr, size_t size)
5600{
5601 void *ret;
5602
5603 if (size == 0) {
Jason Evansb7924f52009-06-23 19:01:18 -07005604#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005605 if (opt_sysv == false)
Jason Evansb7924f52009-06-23 19:01:18 -07005606#endif
Jason Evans289053c2009-06-22 12:08:42 -07005607 size = 1;
Jason Evansb7924f52009-06-23 19:01:18 -07005608#ifdef JEMALLOC_SYSV
Jason Evans289053c2009-06-22 12:08:42 -07005609 else {
5610 if (ptr != NULL)
5611 idalloc(ptr);
5612 ret = NULL;
5613 goto RETURN;
5614 }
Jason Evansb7924f52009-06-23 19:01:18 -07005615#endif
Jason Evans289053c2009-06-22 12:08:42 -07005616 }
5617
5618 if (ptr != NULL) {
5619 assert(malloc_initialized);
5620
5621 ret = iralloc(ptr, size);
5622
5623 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005624#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005625 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005626 jemalloc_message("<jemalloc>",
5627 ": Error in realloc(): out of "
Jason Evans289053c2009-06-22 12:08:42 -07005628 "memory\n", "", "");
5629 abort();
5630 }
Jason Evansb7924f52009-06-23 19:01:18 -07005631#endif
Jason Evans289053c2009-06-22 12:08:42 -07005632 errno = ENOMEM;
5633 }
5634 } else {
5635 if (malloc_init())
5636 ret = NULL;
5637 else
5638 ret = imalloc(size);
5639
5640 if (ret == NULL) {
Jason Evansb7924f52009-06-23 19:01:18 -07005641#ifdef JEMALLOC_XMALLOC
Jason Evans289053c2009-06-22 12:08:42 -07005642 if (opt_xmalloc) {
Jason Evans804c9ec2009-06-22 17:44:33 -07005643 jemalloc_message("<jemalloc>",
5644 ": Error in realloc(): out of "
Jason Evans289053c2009-06-22 12:08:42 -07005645 "memory\n", "", "");
5646 abort();
5647 }
Jason Evansb7924f52009-06-23 19:01:18 -07005648#endif
Jason Evans289053c2009-06-22 12:08:42 -07005649 errno = ENOMEM;
5650 }
5651 }
5652
5653RETURN:
5654 UTRACE(ptr, size, ret);
5655 return (ret);
5656}
5657
5658void
5659free(void *ptr)
5660{
5661
5662 UTRACE(ptr, 0, 0);
5663 if (ptr != NULL) {
5664 assert(malloc_initialized);
5665
5666 idalloc(ptr);
5667 }
5668}
5669
5670/*
5671 * End malloc(3)-compatible functions.
5672 */
5673/******************************************************************************/
5674/*
5675 * Begin non-standard functions.
5676 */
5677
5678size_t
5679malloc_usable_size(const void *ptr)
5680{
5681
5682 assert(ptr != NULL);
5683
5684 return (isalloc(ptr));
5685}
5686
5687/*
5688 * End non-standard functions.
5689 */
5690/******************************************************************************/
5691/*
5692 * Begin library-private functions.
5693 */
5694
5695/******************************************************************************/
5696/*
5697 * Begin thread cache.
5698 */
5699
5700/*
5701 * We provide an unpublished interface in order to receive notifications from
5702 * the pthreads library whenever a thread exits. This allows us to clean up
5703 * thread caches.
5704 */
Jason Evansb7924f52009-06-23 19:01:18 -07005705static void
5706thread_cleanup(void *arg)
Jason Evans289053c2009-06-22 12:08:42 -07005707{
5708
Jason Evansb7924f52009-06-23 19:01:18 -07005709#ifdef JEMALLOC_MAG
5710 assert((mag_rack_t *)arg == mag_rack);
Jason Evans289053c2009-06-22 12:08:42 -07005711 if (mag_rack != NULL) {
5712 assert(mag_rack != (void *)-1);
5713 mag_rack_destroy(mag_rack);
Jason Evansb7924f52009-06-23 19:01:18 -07005714#ifdef JEMALLOC_DEBUG
Jason Evans289053c2009-06-22 12:08:42 -07005715 mag_rack = (void *)-1;
5716#endif
5717 }
5718#endif
5719}
5720
5721/*
5722 * The following functions are used by threading libraries for protection of
5723 * malloc during fork(). These functions are only called if the program is
5724 * running in threaded mode, so there is no need to check whether the program
5725 * is threaded here.
5726 */
5727
5728void
Jason Evans804c9ec2009-06-22 17:44:33 -07005729jemalloc_prefork(void)
Jason Evans289053c2009-06-22 12:08:42 -07005730{
5731 bool again;
5732 unsigned i, j;
5733 arena_t *larenas[narenas], *tarenas[narenas];
5734
5735 /* Acquire all mutexes in a safe order. */
5736
5737 /*
5738 * arenas_lock must be acquired after all of the arena mutexes, in
5739 * order to avoid potential deadlock with arena_lock_balance[_hard]().
5740 * Since arenas_lock protects the arenas array, the following code has
5741 * to race with arenas_extend() callers until it succeeds in locking
5742 * all arenas before locking arenas_lock.
5743 */
5744 memset(larenas, 0, sizeof(arena_t *) * narenas);
5745 do {
5746 again = false;
5747
5748 malloc_spin_lock(&arenas_lock);
5749 for (i = 0; i < narenas; i++) {
5750 if (arenas[i] != larenas[i]) {
5751 memcpy(tarenas, arenas, sizeof(arena_t *) *
5752 narenas);
5753 malloc_spin_unlock(&arenas_lock);
5754 for (j = 0; j < narenas; j++) {
5755 if (larenas[j] != tarenas[j]) {
5756 larenas[j] = tarenas[j];
5757 malloc_spin_lock(
5758 &larenas[j]->lock);
5759 }
5760 }
5761 again = true;
5762 break;
5763 }
5764 }
5765 } while (again);
5766
5767 malloc_mutex_lock(&base_mtx);
5768
5769 malloc_mutex_lock(&huge_mtx);
5770
Jason Evansb7924f52009-06-23 19:01:18 -07005771#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005772 malloc_mutex_lock(&dss_mtx);
5773#endif
5774}
5775
5776void
Jason Evans804c9ec2009-06-22 17:44:33 -07005777jemalloc_postfork(void)
Jason Evans289053c2009-06-22 12:08:42 -07005778{
5779 unsigned i;
5780 arena_t *larenas[narenas];
5781
5782 /* Release all mutexes, now that fork() has completed. */
5783
Jason Evansb7924f52009-06-23 19:01:18 -07005784#ifdef JEMALLOC_DSS
Jason Evans289053c2009-06-22 12:08:42 -07005785 malloc_mutex_unlock(&dss_mtx);
5786#endif
5787
5788 malloc_mutex_unlock(&huge_mtx);
5789
5790 malloc_mutex_unlock(&base_mtx);
5791
5792 memcpy(larenas, arenas, sizeof(arena_t *) * narenas);
5793 malloc_spin_unlock(&arenas_lock);
5794 for (i = 0; i < narenas; i++) {
5795 if (larenas[i] != NULL)
5796 malloc_spin_unlock(&larenas[i]->lock);
5797 }
5798}
5799
5800/*
5801 * End library-private functions.
5802 */
5803/******************************************************************************/