1a4bd5210SJason Evans #define JEMALLOC_C_ 2a4bd5210SJason Evans #include "jemalloc/internal/jemalloc_internal.h" 3a4bd5210SJason Evans 4a4bd5210SJason Evans /******************************************************************************/ 5a4bd5210SJason Evans /* Data. */ 6a4bd5210SJason Evans 7a4bd5210SJason Evans malloc_tsd_data(, arenas, arena_t *, NULL) 8a4bd5210SJason Evans malloc_tsd_data(, thread_allocated, thread_allocated_t, 9a4bd5210SJason Evans THREAD_ALLOCATED_INITIALIZER) 10a4bd5210SJason Evans 11*4fdb8d2aSDimitry Andric /* Work around <http://llvm.org/bugs/show_bug.cgi?id=12623>: */ 12*4fdb8d2aSDimitry Andric const char *__malloc_options_1_0 = NULL; 13a4bd5210SJason Evans __sym_compat(_malloc_options, __malloc_options_1_0, FBSD_1.0); 14a4bd5210SJason Evans 15a4bd5210SJason Evans /* Runtime configuration options. */ 16a4bd5210SJason Evans const char *je_malloc_conf JEMALLOC_ATTR(visibility("default")); 17a4bd5210SJason Evans #ifdef JEMALLOC_DEBUG 18a4bd5210SJason Evans bool opt_abort = true; 19a4bd5210SJason Evans # ifdef JEMALLOC_FILL 20a4bd5210SJason Evans bool opt_junk = true; 21a4bd5210SJason Evans # else 22a4bd5210SJason Evans bool opt_junk = false; 23a4bd5210SJason Evans # endif 24a4bd5210SJason Evans #else 25a4bd5210SJason Evans bool opt_abort = false; 26a4bd5210SJason Evans bool opt_junk = false; 27a4bd5210SJason Evans #endif 28a4bd5210SJason Evans size_t opt_quarantine = ZU(0); 29a4bd5210SJason Evans bool opt_redzone = false; 30a4bd5210SJason Evans bool opt_utrace = false; 31a4bd5210SJason Evans bool opt_valgrind = false; 32a4bd5210SJason Evans bool opt_xmalloc = false; 33a4bd5210SJason Evans bool opt_zero = false; 34a4bd5210SJason Evans size_t opt_narenas = 0; 35a4bd5210SJason Evans 36a4bd5210SJason Evans unsigned ncpus; 37a4bd5210SJason Evans 38a4bd5210SJason Evans malloc_mutex_t arenas_lock; 39a4bd5210SJason Evans arena_t **arenas; 40a4bd5210SJason Evans unsigned narenas; 41a4bd5210SJason Evans 42a4bd5210SJason Evans /* Set to true once the allocator has been initialized. */ 43a4bd5210SJason Evans static bool malloc_initialized = false; 44a4bd5210SJason Evans 45a4bd5210SJason Evans #ifdef JEMALLOC_THREADED_INIT 46a4bd5210SJason Evans /* Used to let the initializing thread recursively allocate. */ 47a4bd5210SJason Evans # define NO_INITIALIZER ((unsigned long)0) 48a4bd5210SJason Evans # define INITIALIZER pthread_self() 49a4bd5210SJason Evans # define IS_INITIALIZER (malloc_initializer == pthread_self()) 50a4bd5210SJason Evans static pthread_t malloc_initializer = NO_INITIALIZER; 51a4bd5210SJason Evans #else 52a4bd5210SJason Evans # define NO_INITIALIZER false 53a4bd5210SJason Evans # define INITIALIZER true 54a4bd5210SJason Evans # define IS_INITIALIZER malloc_initializer 55a4bd5210SJason Evans static bool malloc_initializer = NO_INITIALIZER; 56a4bd5210SJason Evans #endif 57a4bd5210SJason Evans 58a4bd5210SJason Evans /* Used to avoid initialization races. */ 59a4bd5210SJason Evans static malloc_mutex_t init_lock = MALLOC_MUTEX_INITIALIZER; 60a4bd5210SJason Evans 61a4bd5210SJason Evans typedef struct { 62a4bd5210SJason Evans void *p; /* Input pointer (as in realloc(p, s)). */ 63a4bd5210SJason Evans size_t s; /* Request size. */ 64a4bd5210SJason Evans void *r; /* Result pointer. */ 65a4bd5210SJason Evans } malloc_utrace_t; 66a4bd5210SJason Evans 67a4bd5210SJason Evans #ifdef JEMALLOC_UTRACE 68a4bd5210SJason Evans # define UTRACE(a, b, c) do { \ 69a4bd5210SJason Evans if (opt_utrace) { \ 70a4bd5210SJason Evans malloc_utrace_t ut; \ 71a4bd5210SJason Evans ut.p = (a); \ 72a4bd5210SJason Evans ut.s = (b); \ 73a4bd5210SJason Evans ut.r = (c); \ 74a4bd5210SJason Evans utrace(&ut, sizeof(ut)); \ 75a4bd5210SJason Evans } \ 76a4bd5210SJason Evans } while (0) 77a4bd5210SJason Evans #else 78a4bd5210SJason Evans # define UTRACE(a, b, c) 79a4bd5210SJason Evans #endif 80a4bd5210SJason Evans 81a4bd5210SJason Evans /******************************************************************************/ 82a4bd5210SJason Evans /* Function prototypes for non-inline static functions. */ 83a4bd5210SJason Evans 84a4bd5210SJason Evans static void stats_print_atexit(void); 85a4bd5210SJason Evans static unsigned malloc_ncpus(void); 86a4bd5210SJason Evans static bool malloc_conf_next(char const **opts_p, char const **k_p, 87a4bd5210SJason Evans size_t *klen_p, char const **v_p, size_t *vlen_p); 88a4bd5210SJason Evans static void malloc_conf_error(const char *msg, const char *k, size_t klen, 89a4bd5210SJason Evans const char *v, size_t vlen); 90a4bd5210SJason Evans static void malloc_conf_init(void); 91a4bd5210SJason Evans static bool malloc_init_hard(void); 92a4bd5210SJason Evans static int imemalign(void **memptr, size_t alignment, size_t size, 93a4bd5210SJason Evans size_t min_alignment); 94a4bd5210SJason Evans 95a4bd5210SJason Evans /******************************************************************************/ 96a4bd5210SJason Evans /* 97a4bd5210SJason Evans * Begin miscellaneous support functions. 98a4bd5210SJason Evans */ 99a4bd5210SJason Evans 100a4bd5210SJason Evans /* Create a new arena and insert it into the arenas array at index ind. */ 101a4bd5210SJason Evans arena_t * 102a4bd5210SJason Evans arenas_extend(unsigned ind) 103a4bd5210SJason Evans { 104a4bd5210SJason Evans arena_t *ret; 105a4bd5210SJason Evans 106a4bd5210SJason Evans ret = (arena_t *)base_alloc(sizeof(arena_t)); 107a4bd5210SJason Evans if (ret != NULL && arena_new(ret, ind) == false) { 108a4bd5210SJason Evans arenas[ind] = ret; 109a4bd5210SJason Evans return (ret); 110a4bd5210SJason Evans } 111a4bd5210SJason Evans /* Only reached if there is an OOM error. */ 112a4bd5210SJason Evans 113a4bd5210SJason Evans /* 114a4bd5210SJason Evans * OOM here is quite inconvenient to propagate, since dealing with it 115a4bd5210SJason Evans * would require a check for failure in the fast path. Instead, punt 116a4bd5210SJason Evans * by using arenas[0]. In practice, this is an extremely unlikely 117a4bd5210SJason Evans * failure. 118a4bd5210SJason Evans */ 119a4bd5210SJason Evans malloc_write("<jemalloc>: Error initializing arena\n"); 120a4bd5210SJason Evans if (opt_abort) 121a4bd5210SJason Evans abort(); 122a4bd5210SJason Evans 123a4bd5210SJason Evans return (arenas[0]); 124a4bd5210SJason Evans } 125a4bd5210SJason Evans 126a4bd5210SJason Evans /* Slow path, called only by choose_arena(). */ 127a4bd5210SJason Evans arena_t * 128a4bd5210SJason Evans choose_arena_hard(void) 129a4bd5210SJason Evans { 130a4bd5210SJason Evans arena_t *ret; 131a4bd5210SJason Evans 132a4bd5210SJason Evans if (narenas > 1) { 133a4bd5210SJason Evans unsigned i, choose, first_null; 134a4bd5210SJason Evans 135a4bd5210SJason Evans choose = 0; 136a4bd5210SJason Evans first_null = narenas; 137a4bd5210SJason Evans malloc_mutex_lock(&arenas_lock); 138a4bd5210SJason Evans assert(arenas[0] != NULL); 139a4bd5210SJason Evans for (i = 1; i < narenas; i++) { 140a4bd5210SJason Evans if (arenas[i] != NULL) { 141a4bd5210SJason Evans /* 142a4bd5210SJason Evans * Choose the first arena that has the lowest 143a4bd5210SJason Evans * number of threads assigned to it. 144a4bd5210SJason Evans */ 145a4bd5210SJason Evans if (arenas[i]->nthreads < 146a4bd5210SJason Evans arenas[choose]->nthreads) 147a4bd5210SJason Evans choose = i; 148a4bd5210SJason Evans } else if (first_null == narenas) { 149a4bd5210SJason Evans /* 150a4bd5210SJason Evans * Record the index of the first uninitialized 151a4bd5210SJason Evans * arena, in case all extant arenas are in use. 152a4bd5210SJason Evans * 153a4bd5210SJason Evans * NB: It is possible for there to be 154a4bd5210SJason Evans * discontinuities in terms of initialized 155a4bd5210SJason Evans * versus uninitialized arenas, due to the 156a4bd5210SJason Evans * "thread.arena" mallctl. 157a4bd5210SJason Evans */ 158a4bd5210SJason Evans first_null = i; 159a4bd5210SJason Evans } 160a4bd5210SJason Evans } 161a4bd5210SJason Evans 162a4bd5210SJason Evans if (arenas[choose]->nthreads == 0 || first_null == narenas) { 163a4bd5210SJason Evans /* 164a4bd5210SJason Evans * Use an unloaded arena, or the least loaded arena if 165a4bd5210SJason Evans * all arenas are already initialized. 166a4bd5210SJason Evans */ 167a4bd5210SJason Evans ret = arenas[choose]; 168a4bd5210SJason Evans } else { 169a4bd5210SJason Evans /* Initialize a new arena. */ 170a4bd5210SJason Evans ret = arenas_extend(first_null); 171a4bd5210SJason Evans } 172a4bd5210SJason Evans ret->nthreads++; 173a4bd5210SJason Evans malloc_mutex_unlock(&arenas_lock); 174a4bd5210SJason Evans } else { 175a4bd5210SJason Evans ret = arenas[0]; 176a4bd5210SJason Evans malloc_mutex_lock(&arenas_lock); 177a4bd5210SJason Evans ret->nthreads++; 178a4bd5210SJason Evans malloc_mutex_unlock(&arenas_lock); 179a4bd5210SJason Evans } 180a4bd5210SJason Evans 181a4bd5210SJason Evans arenas_tsd_set(&ret); 182a4bd5210SJason Evans 183a4bd5210SJason Evans return (ret); 184a4bd5210SJason Evans } 185a4bd5210SJason Evans 186a4bd5210SJason Evans static void 187a4bd5210SJason Evans stats_print_atexit(void) 188a4bd5210SJason Evans { 189a4bd5210SJason Evans 190a4bd5210SJason Evans if (config_tcache && config_stats) { 191a4bd5210SJason Evans unsigned i; 192a4bd5210SJason Evans 193a4bd5210SJason Evans /* 194a4bd5210SJason Evans * Merge stats from extant threads. This is racy, since 195a4bd5210SJason Evans * individual threads do not lock when recording tcache stats 196a4bd5210SJason Evans * events. As a consequence, the final stats may be slightly 197a4bd5210SJason Evans * out of date by the time they are reported, if other threads 198a4bd5210SJason Evans * continue to allocate. 199a4bd5210SJason Evans */ 200a4bd5210SJason Evans for (i = 0; i < narenas; i++) { 201a4bd5210SJason Evans arena_t *arena = arenas[i]; 202a4bd5210SJason Evans if (arena != NULL) { 203a4bd5210SJason Evans tcache_t *tcache; 204a4bd5210SJason Evans 205a4bd5210SJason Evans /* 206a4bd5210SJason Evans * tcache_stats_merge() locks bins, so if any 207a4bd5210SJason Evans * code is introduced that acquires both arena 208a4bd5210SJason Evans * and bin locks in the opposite order, 209a4bd5210SJason Evans * deadlocks may result. 210a4bd5210SJason Evans */ 211a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 212a4bd5210SJason Evans ql_foreach(tcache, &arena->tcache_ql, link) { 213a4bd5210SJason Evans tcache_stats_merge(tcache, arena); 214a4bd5210SJason Evans } 215a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 216a4bd5210SJason Evans } 217a4bd5210SJason Evans } 218a4bd5210SJason Evans } 219a4bd5210SJason Evans je_malloc_stats_print(NULL, NULL, NULL); 220a4bd5210SJason Evans } 221a4bd5210SJason Evans 222a4bd5210SJason Evans /* 223a4bd5210SJason Evans * End miscellaneous support functions. 224a4bd5210SJason Evans */ 225a4bd5210SJason Evans /******************************************************************************/ 226a4bd5210SJason Evans /* 227a4bd5210SJason Evans * Begin initialization functions. 228a4bd5210SJason Evans */ 229a4bd5210SJason Evans 230a4bd5210SJason Evans static unsigned 231a4bd5210SJason Evans malloc_ncpus(void) 232a4bd5210SJason Evans { 233a4bd5210SJason Evans unsigned ret; 234a4bd5210SJason Evans long result; 235a4bd5210SJason Evans 236a4bd5210SJason Evans result = sysconf(_SC_NPROCESSORS_ONLN); 237a4bd5210SJason Evans if (result == -1) { 238a4bd5210SJason Evans /* Error. */ 239a4bd5210SJason Evans ret = 1; 240a4bd5210SJason Evans } 241a4bd5210SJason Evans ret = (unsigned)result; 242a4bd5210SJason Evans 243a4bd5210SJason Evans return (ret); 244a4bd5210SJason Evans } 245a4bd5210SJason Evans 246a4bd5210SJason Evans void 247a4bd5210SJason Evans arenas_cleanup(void *arg) 248a4bd5210SJason Evans { 249a4bd5210SJason Evans arena_t *arena = *(arena_t **)arg; 250a4bd5210SJason Evans 251a4bd5210SJason Evans malloc_mutex_lock(&arenas_lock); 252a4bd5210SJason Evans arena->nthreads--; 253a4bd5210SJason Evans malloc_mutex_unlock(&arenas_lock); 254a4bd5210SJason Evans } 255a4bd5210SJason Evans 256a4bd5210SJason Evans static inline bool 257a4bd5210SJason Evans malloc_init(void) 258a4bd5210SJason Evans { 259a4bd5210SJason Evans 260a4bd5210SJason Evans if (malloc_initialized == false) 261a4bd5210SJason Evans return (malloc_init_hard()); 262a4bd5210SJason Evans 263a4bd5210SJason Evans return (false); 264a4bd5210SJason Evans } 265a4bd5210SJason Evans 266a4bd5210SJason Evans static bool 267a4bd5210SJason Evans malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, 268a4bd5210SJason Evans char const **v_p, size_t *vlen_p) 269a4bd5210SJason Evans { 270a4bd5210SJason Evans bool accept; 271a4bd5210SJason Evans const char *opts = *opts_p; 272a4bd5210SJason Evans 273a4bd5210SJason Evans *k_p = opts; 274a4bd5210SJason Evans 275a4bd5210SJason Evans for (accept = false; accept == false;) { 276a4bd5210SJason Evans switch (*opts) { 277a4bd5210SJason Evans case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 278a4bd5210SJason Evans case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': 279a4bd5210SJason Evans case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': 280a4bd5210SJason Evans case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': 281a4bd5210SJason Evans case 'Y': case 'Z': 282a4bd5210SJason Evans case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 283a4bd5210SJason Evans case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 284a4bd5210SJason Evans case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': 285a4bd5210SJason Evans case 's': case 't': case 'u': case 'v': case 'w': case 'x': 286a4bd5210SJason Evans case 'y': case 'z': 287a4bd5210SJason Evans case '0': case '1': case '2': case '3': case '4': case '5': 288a4bd5210SJason Evans case '6': case '7': case '8': case '9': 289a4bd5210SJason Evans case '_': 290a4bd5210SJason Evans opts++; 291a4bd5210SJason Evans break; 292a4bd5210SJason Evans case ':': 293a4bd5210SJason Evans opts++; 294a4bd5210SJason Evans *klen_p = (uintptr_t)opts - 1 - (uintptr_t)*k_p; 295a4bd5210SJason Evans *v_p = opts; 296a4bd5210SJason Evans accept = true; 297a4bd5210SJason Evans break; 298a4bd5210SJason Evans case '\0': 299a4bd5210SJason Evans if (opts != *opts_p) { 300a4bd5210SJason Evans malloc_write("<jemalloc>: Conf string ends " 301a4bd5210SJason Evans "with key\n"); 302a4bd5210SJason Evans } 303a4bd5210SJason Evans return (true); 304a4bd5210SJason Evans default: 305a4bd5210SJason Evans malloc_write("<jemalloc>: Malformed conf string\n"); 306a4bd5210SJason Evans return (true); 307a4bd5210SJason Evans } 308a4bd5210SJason Evans } 309a4bd5210SJason Evans 310a4bd5210SJason Evans for (accept = false; accept == false;) { 311a4bd5210SJason Evans switch (*opts) { 312a4bd5210SJason Evans case ',': 313a4bd5210SJason Evans opts++; 314a4bd5210SJason Evans /* 315a4bd5210SJason Evans * Look ahead one character here, because the next time 316a4bd5210SJason Evans * this function is called, it will assume that end of 317a4bd5210SJason Evans * input has been cleanly reached if no input remains, 318a4bd5210SJason Evans * but we have optimistically already consumed the 319a4bd5210SJason Evans * comma if one exists. 320a4bd5210SJason Evans */ 321a4bd5210SJason Evans if (*opts == '\0') { 322a4bd5210SJason Evans malloc_write("<jemalloc>: Conf string ends " 323a4bd5210SJason Evans "with comma\n"); 324a4bd5210SJason Evans } 325a4bd5210SJason Evans *vlen_p = (uintptr_t)opts - 1 - (uintptr_t)*v_p; 326a4bd5210SJason Evans accept = true; 327a4bd5210SJason Evans break; 328a4bd5210SJason Evans case '\0': 329a4bd5210SJason Evans *vlen_p = (uintptr_t)opts - (uintptr_t)*v_p; 330a4bd5210SJason Evans accept = true; 331a4bd5210SJason Evans break; 332a4bd5210SJason Evans default: 333a4bd5210SJason Evans opts++; 334a4bd5210SJason Evans break; 335a4bd5210SJason Evans } 336a4bd5210SJason Evans } 337a4bd5210SJason Evans 338a4bd5210SJason Evans *opts_p = opts; 339a4bd5210SJason Evans return (false); 340a4bd5210SJason Evans } 341a4bd5210SJason Evans 342a4bd5210SJason Evans static void 343a4bd5210SJason Evans malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v, 344a4bd5210SJason Evans size_t vlen) 345a4bd5210SJason Evans { 346a4bd5210SJason Evans 347a4bd5210SJason Evans malloc_printf("<jemalloc>: %s: %.*s:%.*s\n", msg, (int)klen, k, 348a4bd5210SJason Evans (int)vlen, v); 349a4bd5210SJason Evans } 350a4bd5210SJason Evans 351a4bd5210SJason Evans static void 352a4bd5210SJason Evans malloc_conf_init(void) 353a4bd5210SJason Evans { 354a4bd5210SJason Evans unsigned i; 355a4bd5210SJason Evans char buf[PATH_MAX + 1]; 356a4bd5210SJason Evans const char *opts, *k, *v; 357a4bd5210SJason Evans size_t klen, vlen; 358a4bd5210SJason Evans 359a4bd5210SJason Evans for (i = 0; i < 3; i++) { 360a4bd5210SJason Evans /* Get runtime configuration. */ 361a4bd5210SJason Evans switch (i) { 362a4bd5210SJason Evans case 0: 363a4bd5210SJason Evans if (je_malloc_conf != NULL) { 364a4bd5210SJason Evans /* 365a4bd5210SJason Evans * Use options that were compiled into the 366a4bd5210SJason Evans * program. 367a4bd5210SJason Evans */ 368a4bd5210SJason Evans opts = je_malloc_conf; 369a4bd5210SJason Evans } else { 370a4bd5210SJason Evans /* No configuration specified. */ 371a4bd5210SJason Evans buf[0] = '\0'; 372a4bd5210SJason Evans opts = buf; 373a4bd5210SJason Evans } 374a4bd5210SJason Evans break; 375a4bd5210SJason Evans case 1: { 376a4bd5210SJason Evans int linklen; 377a4bd5210SJason Evans const char *linkname = 378a4bd5210SJason Evans #ifdef JEMALLOC_PREFIX 379a4bd5210SJason Evans "/etc/"JEMALLOC_PREFIX"malloc.conf" 380a4bd5210SJason Evans #else 381a4bd5210SJason Evans "/etc/malloc.conf" 382a4bd5210SJason Evans #endif 383a4bd5210SJason Evans ; 384a4bd5210SJason Evans 385a4bd5210SJason Evans if ((linklen = readlink(linkname, buf, 386a4bd5210SJason Evans sizeof(buf) - 1)) != -1) { 387a4bd5210SJason Evans /* 388a4bd5210SJason Evans * Use the contents of the "/etc/malloc.conf" 389a4bd5210SJason Evans * symbolic link's name. 390a4bd5210SJason Evans */ 391a4bd5210SJason Evans buf[linklen] = '\0'; 392a4bd5210SJason Evans opts = buf; 393a4bd5210SJason Evans } else { 394a4bd5210SJason Evans /* No configuration specified. */ 395a4bd5210SJason Evans buf[0] = '\0'; 396a4bd5210SJason Evans opts = buf; 397a4bd5210SJason Evans } 398a4bd5210SJason Evans break; 399a4bd5210SJason Evans } case 2: { 400a4bd5210SJason Evans const char *envname = 401a4bd5210SJason Evans #ifdef JEMALLOC_PREFIX 402a4bd5210SJason Evans JEMALLOC_CPREFIX"MALLOC_CONF" 403a4bd5210SJason Evans #else 404a4bd5210SJason Evans "MALLOC_CONF" 405a4bd5210SJason Evans #endif 406a4bd5210SJason Evans ; 407a4bd5210SJason Evans 408a4bd5210SJason Evans if (issetugid() == 0 && (opts = getenv(envname)) != 409a4bd5210SJason Evans NULL) { 410a4bd5210SJason Evans /* 411a4bd5210SJason Evans * Do nothing; opts is already initialized to 412a4bd5210SJason Evans * the value of the MALLOC_CONF environment 413a4bd5210SJason Evans * variable. 414a4bd5210SJason Evans */ 415a4bd5210SJason Evans } else { 416a4bd5210SJason Evans /* No configuration specified. */ 417a4bd5210SJason Evans buf[0] = '\0'; 418a4bd5210SJason Evans opts = buf; 419a4bd5210SJason Evans } 420a4bd5210SJason Evans break; 421a4bd5210SJason Evans } default: 422a4bd5210SJason Evans /* NOTREACHED */ 423a4bd5210SJason Evans assert(false); 424a4bd5210SJason Evans buf[0] = '\0'; 425a4bd5210SJason Evans opts = buf; 426a4bd5210SJason Evans } 427a4bd5210SJason Evans 428a4bd5210SJason Evans while (*opts != '\0' && malloc_conf_next(&opts, &k, &klen, &v, 429a4bd5210SJason Evans &vlen) == false) { 430a4bd5210SJason Evans #define CONF_HANDLE_BOOL_HIT(o, n, hit) \ 4318ed34ab0SJason Evans if (sizeof(n)-1 == klen && strncmp(n, k, \ 432a4bd5210SJason Evans klen) == 0) { \ 433a4bd5210SJason Evans if (strncmp("true", v, vlen) == 0 && \ 434a4bd5210SJason Evans vlen == sizeof("true")-1) \ 435a4bd5210SJason Evans o = true; \ 436a4bd5210SJason Evans else if (strncmp("false", v, vlen) == \ 437a4bd5210SJason Evans 0 && vlen == sizeof("false")-1) \ 438a4bd5210SJason Evans o = false; \ 439a4bd5210SJason Evans else { \ 440a4bd5210SJason Evans malloc_conf_error( \ 441a4bd5210SJason Evans "Invalid conf value", \ 442a4bd5210SJason Evans k, klen, v, vlen); \ 443a4bd5210SJason Evans } \ 444a4bd5210SJason Evans hit = true; \ 445a4bd5210SJason Evans } else \ 446a4bd5210SJason Evans hit = false; 447a4bd5210SJason Evans #define CONF_HANDLE_BOOL(o, n) { \ 448a4bd5210SJason Evans bool hit; \ 449a4bd5210SJason Evans CONF_HANDLE_BOOL_HIT(o, n, hit); \ 450a4bd5210SJason Evans if (hit) \ 451a4bd5210SJason Evans continue; \ 452a4bd5210SJason Evans } 453a4bd5210SJason Evans #define CONF_HANDLE_SIZE_T(o, n, min, max) \ 4548ed34ab0SJason Evans if (sizeof(n)-1 == klen && strncmp(n, k, \ 455a4bd5210SJason Evans klen) == 0) { \ 456a4bd5210SJason Evans uintmax_t um; \ 457a4bd5210SJason Evans char *end; \ 458a4bd5210SJason Evans \ 459a4bd5210SJason Evans errno = 0; \ 460a4bd5210SJason Evans um = malloc_strtoumax(v, &end, 0); \ 461a4bd5210SJason Evans if (errno != 0 || (uintptr_t)end - \ 462a4bd5210SJason Evans (uintptr_t)v != vlen) { \ 463a4bd5210SJason Evans malloc_conf_error( \ 464a4bd5210SJason Evans "Invalid conf value", \ 465a4bd5210SJason Evans k, klen, v, vlen); \ 466a4bd5210SJason Evans } else if (um < min || um > max) { \ 467a4bd5210SJason Evans malloc_conf_error( \ 468a4bd5210SJason Evans "Out-of-range conf value", \ 469a4bd5210SJason Evans k, klen, v, vlen); \ 470a4bd5210SJason Evans } else \ 471a4bd5210SJason Evans o = um; \ 472a4bd5210SJason Evans continue; \ 473a4bd5210SJason Evans } 474a4bd5210SJason Evans #define CONF_HANDLE_SSIZE_T(o, n, min, max) \ 4758ed34ab0SJason Evans if (sizeof(n)-1 == klen && strncmp(n, k, \ 476a4bd5210SJason Evans klen) == 0) { \ 477a4bd5210SJason Evans long l; \ 478a4bd5210SJason Evans char *end; \ 479a4bd5210SJason Evans \ 480a4bd5210SJason Evans errno = 0; \ 481a4bd5210SJason Evans l = strtol(v, &end, 0); \ 482a4bd5210SJason Evans if (errno != 0 || (uintptr_t)end - \ 483a4bd5210SJason Evans (uintptr_t)v != vlen) { \ 484a4bd5210SJason Evans malloc_conf_error( \ 485a4bd5210SJason Evans "Invalid conf value", \ 486a4bd5210SJason Evans k, klen, v, vlen); \ 487a4bd5210SJason Evans } else if (l < (ssize_t)min || l > \ 488a4bd5210SJason Evans (ssize_t)max) { \ 489a4bd5210SJason Evans malloc_conf_error( \ 490a4bd5210SJason Evans "Out-of-range conf value", \ 491a4bd5210SJason Evans k, klen, v, vlen); \ 492a4bd5210SJason Evans } else \ 493a4bd5210SJason Evans o = l; \ 494a4bd5210SJason Evans continue; \ 495a4bd5210SJason Evans } 496a4bd5210SJason Evans #define CONF_HANDLE_CHAR_P(o, n, d) \ 4978ed34ab0SJason Evans if (sizeof(n)-1 == klen && strncmp(n, k, \ 498a4bd5210SJason Evans klen) == 0) { \ 499a4bd5210SJason Evans size_t cpylen = (vlen <= \ 500a4bd5210SJason Evans sizeof(o)-1) ? vlen : \ 501a4bd5210SJason Evans sizeof(o)-1; \ 502a4bd5210SJason Evans strncpy(o, v, cpylen); \ 503a4bd5210SJason Evans o[cpylen] = '\0'; \ 504a4bd5210SJason Evans continue; \ 505a4bd5210SJason Evans } 506a4bd5210SJason Evans 5078ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_abort, "abort") 508a4bd5210SJason Evans /* 509a4bd5210SJason Evans * Chunks always require at least one header page, plus 510a4bd5210SJason Evans * one data page in the absence of redzones, or three 511a4bd5210SJason Evans * pages in the presence of redzones. In order to 512a4bd5210SJason Evans * simplify options processing, fix the limit based on 513a4bd5210SJason Evans * config_fill. 514a4bd5210SJason Evans */ 5158ed34ab0SJason Evans CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE + 516a4bd5210SJason Evans (config_fill ? 2 : 1), (sizeof(size_t) << 3) - 1) 5178ed34ab0SJason Evans CONF_HANDLE_SIZE_T(opt_narenas, "narenas", 1, 5188ed34ab0SJason Evans SIZE_T_MAX) 5198ed34ab0SJason Evans CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult", 520a4bd5210SJason Evans -1, (sizeof(size_t) << 3) - 1) 5218ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_stats_print, "stats_print") 522a4bd5210SJason Evans if (config_fill) { 5238ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_junk, "junk") 5248ed34ab0SJason Evans CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine", 525a4bd5210SJason Evans 0, SIZE_T_MAX) 5268ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_redzone, "redzone") 5278ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_zero, "zero") 528a4bd5210SJason Evans } 529a4bd5210SJason Evans if (config_utrace) { 5308ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_utrace, "utrace") 531a4bd5210SJason Evans } 532a4bd5210SJason Evans if (config_valgrind) { 533a4bd5210SJason Evans bool hit; 534a4bd5210SJason Evans CONF_HANDLE_BOOL_HIT(opt_valgrind, 5358ed34ab0SJason Evans "valgrind", hit) 536a4bd5210SJason Evans if (config_fill && opt_valgrind && hit) { 537a4bd5210SJason Evans opt_junk = false; 538a4bd5210SJason Evans opt_zero = false; 539a4bd5210SJason Evans if (opt_quarantine == 0) { 540a4bd5210SJason Evans opt_quarantine = 541a4bd5210SJason Evans JEMALLOC_VALGRIND_QUARANTINE_DEFAULT; 542a4bd5210SJason Evans } 543a4bd5210SJason Evans opt_redzone = true; 544a4bd5210SJason Evans } 545a4bd5210SJason Evans if (hit) 546a4bd5210SJason Evans continue; 547a4bd5210SJason Evans } 548a4bd5210SJason Evans if (config_xmalloc) { 5498ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc") 550a4bd5210SJason Evans } 551a4bd5210SJason Evans if (config_tcache) { 5528ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_tcache, "tcache") 553a4bd5210SJason Evans CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, 5548ed34ab0SJason Evans "lg_tcache_max", -1, 555a4bd5210SJason Evans (sizeof(size_t) << 3) - 1) 556a4bd5210SJason Evans } 557a4bd5210SJason Evans if (config_prof) { 5588ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_prof, "prof") 5598ed34ab0SJason Evans CONF_HANDLE_CHAR_P(opt_prof_prefix, 5608ed34ab0SJason Evans "prof_prefix", "jeprof") 5618ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_prof_active, "prof_active") 562a4bd5210SJason Evans CONF_HANDLE_SSIZE_T(opt_lg_prof_sample, 5638ed34ab0SJason Evans "lg_prof_sample", 0, 564a4bd5210SJason Evans (sizeof(uint64_t) << 3) - 1) 5658ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum") 566a4bd5210SJason Evans CONF_HANDLE_SSIZE_T(opt_lg_prof_interval, 5678ed34ab0SJason Evans "lg_prof_interval", -1, 568a4bd5210SJason Evans (sizeof(uint64_t) << 3) - 1) 5698ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump") 5708ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_prof_final, "prof_final") 5718ed34ab0SJason Evans CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak") 572a4bd5210SJason Evans } 573a4bd5210SJason Evans malloc_conf_error("Invalid conf pair", k, klen, v, 574a4bd5210SJason Evans vlen); 575a4bd5210SJason Evans #undef CONF_HANDLE_BOOL 576a4bd5210SJason Evans #undef CONF_HANDLE_SIZE_T 577a4bd5210SJason Evans #undef CONF_HANDLE_SSIZE_T 578a4bd5210SJason Evans #undef CONF_HANDLE_CHAR_P 579a4bd5210SJason Evans } 580a4bd5210SJason Evans } 581a4bd5210SJason Evans } 582a4bd5210SJason Evans 583a4bd5210SJason Evans static bool 584a4bd5210SJason Evans malloc_init_hard(void) 585a4bd5210SJason Evans { 586a4bd5210SJason Evans arena_t *init_arenas[1]; 587a4bd5210SJason Evans 588a4bd5210SJason Evans malloc_mutex_lock(&init_lock); 589a4bd5210SJason Evans if (malloc_initialized || IS_INITIALIZER) { 590a4bd5210SJason Evans /* 591a4bd5210SJason Evans * Another thread initialized the allocator before this one 592a4bd5210SJason Evans * acquired init_lock, or this thread is the initializing 593a4bd5210SJason Evans * thread, and it is recursively allocating. 594a4bd5210SJason Evans */ 595a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 596a4bd5210SJason Evans return (false); 597a4bd5210SJason Evans } 598a4bd5210SJason Evans #ifdef JEMALLOC_THREADED_INIT 599a4bd5210SJason Evans if (malloc_initializer != NO_INITIALIZER && IS_INITIALIZER == false) { 600a4bd5210SJason Evans /* Busy-wait until the initializing thread completes. */ 601a4bd5210SJason Evans do { 602a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 603a4bd5210SJason Evans CPU_SPINWAIT; 604a4bd5210SJason Evans malloc_mutex_lock(&init_lock); 605a4bd5210SJason Evans } while (malloc_initialized == false); 606a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 607a4bd5210SJason Evans return (false); 608a4bd5210SJason Evans } 609a4bd5210SJason Evans #endif 610a4bd5210SJason Evans malloc_initializer = INITIALIZER; 611a4bd5210SJason Evans 612a4bd5210SJason Evans malloc_tsd_boot(); 613a4bd5210SJason Evans if (config_prof) 614a4bd5210SJason Evans prof_boot0(); 615a4bd5210SJason Evans 616a4bd5210SJason Evans malloc_conf_init(); 617a4bd5210SJason Evans 618a4bd5210SJason Evans #if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE)) 619a4bd5210SJason Evans /* Register fork handlers. */ 620a4bd5210SJason Evans if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, 621a4bd5210SJason Evans jemalloc_postfork_child) != 0) { 622a4bd5210SJason Evans malloc_write("<jemalloc>: Error in pthread_atfork()\n"); 623a4bd5210SJason Evans if (opt_abort) 624a4bd5210SJason Evans abort(); 625a4bd5210SJason Evans } 626a4bd5210SJason Evans #endif 627a4bd5210SJason Evans 628a4bd5210SJason Evans if (opt_stats_print) { 629a4bd5210SJason Evans /* Print statistics at exit. */ 630a4bd5210SJason Evans if (atexit(stats_print_atexit) != 0) { 631a4bd5210SJason Evans malloc_write("<jemalloc>: Error in atexit()\n"); 632a4bd5210SJason Evans if (opt_abort) 633a4bd5210SJason Evans abort(); 634a4bd5210SJason Evans } 635a4bd5210SJason Evans } 636a4bd5210SJason Evans 637a4bd5210SJason Evans if (base_boot()) { 638a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 639a4bd5210SJason Evans return (true); 640a4bd5210SJason Evans } 641a4bd5210SJason Evans 6424bcb1430SJason Evans if (chunk_boot()) { 643a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 644a4bd5210SJason Evans return (true); 645a4bd5210SJason Evans } 646a4bd5210SJason Evans 647a4bd5210SJason Evans if (ctl_boot()) { 648a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 649a4bd5210SJason Evans return (true); 650a4bd5210SJason Evans } 651a4bd5210SJason Evans 652a4bd5210SJason Evans if (config_prof) 653a4bd5210SJason Evans prof_boot1(); 654a4bd5210SJason Evans 655a4bd5210SJason Evans arena_boot(); 656a4bd5210SJason Evans 657a4bd5210SJason Evans if (config_tcache && tcache_boot0()) { 658a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 659a4bd5210SJason Evans return (true); 660a4bd5210SJason Evans } 661a4bd5210SJason Evans 662a4bd5210SJason Evans if (huge_boot()) { 663a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 664a4bd5210SJason Evans return (true); 665a4bd5210SJason Evans } 666a4bd5210SJason Evans 667a4bd5210SJason Evans if (malloc_mutex_init(&arenas_lock)) 668a4bd5210SJason Evans return (true); 669a4bd5210SJason Evans 670a4bd5210SJason Evans /* 671a4bd5210SJason Evans * Create enough scaffolding to allow recursive allocation in 672a4bd5210SJason Evans * malloc_ncpus(). 673a4bd5210SJason Evans */ 674a4bd5210SJason Evans narenas = 1; 675a4bd5210SJason Evans arenas = init_arenas; 676a4bd5210SJason Evans memset(arenas, 0, sizeof(arena_t *) * narenas); 677a4bd5210SJason Evans 678a4bd5210SJason Evans /* 679a4bd5210SJason Evans * Initialize one arena here. The rest are lazily created in 680a4bd5210SJason Evans * choose_arena_hard(). 681a4bd5210SJason Evans */ 682a4bd5210SJason Evans arenas_extend(0); 683a4bd5210SJason Evans if (arenas[0] == NULL) { 684a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 685a4bd5210SJason Evans return (true); 686a4bd5210SJason Evans } 687a4bd5210SJason Evans 688a4bd5210SJason Evans /* Initialize allocation counters before any allocations can occur. */ 689a4bd5210SJason Evans if (config_stats && thread_allocated_tsd_boot()) { 690a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 691a4bd5210SJason Evans return (true); 692a4bd5210SJason Evans } 693a4bd5210SJason Evans 694a4bd5210SJason Evans if (arenas_tsd_boot()) { 695a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 696a4bd5210SJason Evans return (true); 697a4bd5210SJason Evans } 698a4bd5210SJason Evans 699a4bd5210SJason Evans if (config_tcache && tcache_boot1()) { 700a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 701a4bd5210SJason Evans return (true); 702a4bd5210SJason Evans } 703a4bd5210SJason Evans 704a4bd5210SJason Evans if (config_fill && quarantine_boot()) { 705a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 706a4bd5210SJason Evans return (true); 707a4bd5210SJason Evans } 708a4bd5210SJason Evans 709a4bd5210SJason Evans if (config_prof && prof_boot2()) { 710a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 711a4bd5210SJason Evans return (true); 712a4bd5210SJason Evans } 713a4bd5210SJason Evans 714a4bd5210SJason Evans /* Get number of CPUs. */ 715a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 716a4bd5210SJason Evans ncpus = malloc_ncpus(); 717a4bd5210SJason Evans malloc_mutex_lock(&init_lock); 718a4bd5210SJason Evans 719a4bd5210SJason Evans if (mutex_boot()) { 720a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 721a4bd5210SJason Evans return (true); 722a4bd5210SJason Evans } 723a4bd5210SJason Evans 724a4bd5210SJason Evans if (opt_narenas == 0) { 725a4bd5210SJason Evans /* 726a4bd5210SJason Evans * For SMP systems, create more than one arena per CPU by 727a4bd5210SJason Evans * default. 728a4bd5210SJason Evans */ 729a4bd5210SJason Evans if (ncpus > 1) 730a4bd5210SJason Evans opt_narenas = ncpus << 2; 731a4bd5210SJason Evans else 732a4bd5210SJason Evans opt_narenas = 1; 733a4bd5210SJason Evans } 734a4bd5210SJason Evans narenas = opt_narenas; 735a4bd5210SJason Evans /* 736a4bd5210SJason Evans * Make sure that the arenas array can be allocated. In practice, this 737a4bd5210SJason Evans * limit is enough to allow the allocator to function, but the ctl 738a4bd5210SJason Evans * machinery will fail to allocate memory at far lower limits. 739a4bd5210SJason Evans */ 740a4bd5210SJason Evans if (narenas > chunksize / sizeof(arena_t *)) { 741a4bd5210SJason Evans narenas = chunksize / sizeof(arena_t *); 742a4bd5210SJason Evans malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n", 743a4bd5210SJason Evans narenas); 744a4bd5210SJason Evans } 745a4bd5210SJason Evans 746a4bd5210SJason Evans /* Allocate and initialize arenas. */ 747a4bd5210SJason Evans arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas); 748a4bd5210SJason Evans if (arenas == NULL) { 749a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 750a4bd5210SJason Evans return (true); 751a4bd5210SJason Evans } 752a4bd5210SJason Evans /* 753a4bd5210SJason Evans * Zero the array. In practice, this should always be pre-zeroed, 754a4bd5210SJason Evans * since it was just mmap()ed, but let's be sure. 755a4bd5210SJason Evans */ 756a4bd5210SJason Evans memset(arenas, 0, sizeof(arena_t *) * narenas); 757a4bd5210SJason Evans /* Copy the pointer to the one arena that was already initialized. */ 758a4bd5210SJason Evans arenas[0] = init_arenas[0]; 759a4bd5210SJason Evans 760a4bd5210SJason Evans malloc_initialized = true; 761a4bd5210SJason Evans malloc_mutex_unlock(&init_lock); 762a4bd5210SJason Evans return (false); 763a4bd5210SJason Evans } 764a4bd5210SJason Evans 765a4bd5210SJason Evans /* 766a4bd5210SJason Evans * End initialization functions. 767a4bd5210SJason Evans */ 768a4bd5210SJason Evans /******************************************************************************/ 769a4bd5210SJason Evans /* 770a4bd5210SJason Evans * Begin malloc(3)-compatible functions. 771a4bd5210SJason Evans */ 772a4bd5210SJason Evans 773a4bd5210SJason Evans JEMALLOC_ATTR(malloc) 774a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 775a4bd5210SJason Evans void * 776a4bd5210SJason Evans je_malloc(size_t size) 777a4bd5210SJason Evans { 778a4bd5210SJason Evans void *ret; 779a4bd5210SJason Evans size_t usize; 780a4bd5210SJason Evans prof_thr_cnt_t *cnt JEMALLOC_CC_SILENCE_INIT(NULL); 781a4bd5210SJason Evans 782a4bd5210SJason Evans if (malloc_init()) { 783a4bd5210SJason Evans ret = NULL; 784a4bd5210SJason Evans goto label_oom; 785a4bd5210SJason Evans } 786a4bd5210SJason Evans 787a4bd5210SJason Evans if (size == 0) 788a4bd5210SJason Evans size = 1; 789a4bd5210SJason Evans 790a4bd5210SJason Evans if (config_prof && opt_prof) { 791a4bd5210SJason Evans usize = s2u(size); 792a4bd5210SJason Evans PROF_ALLOC_PREP(1, usize, cnt); 793a4bd5210SJason Evans if (cnt == NULL) { 794a4bd5210SJason Evans ret = NULL; 795a4bd5210SJason Evans goto label_oom; 796a4bd5210SJason Evans } 797a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && usize <= 798a4bd5210SJason Evans SMALL_MAXCLASS) { 799a4bd5210SJason Evans ret = imalloc(SMALL_MAXCLASS+1); 800a4bd5210SJason Evans if (ret != NULL) 801a4bd5210SJason Evans arena_prof_promoted(ret, usize); 802a4bd5210SJason Evans } else 803a4bd5210SJason Evans ret = imalloc(size); 804a4bd5210SJason Evans } else { 805a4bd5210SJason Evans if (config_stats || (config_valgrind && opt_valgrind)) 806a4bd5210SJason Evans usize = s2u(size); 807a4bd5210SJason Evans ret = imalloc(size); 808a4bd5210SJason Evans } 809a4bd5210SJason Evans 810a4bd5210SJason Evans label_oom: 811a4bd5210SJason Evans if (ret == NULL) { 812a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 813a4bd5210SJason Evans malloc_write("<jemalloc>: Error in malloc(): " 814a4bd5210SJason Evans "out of memory\n"); 815a4bd5210SJason Evans abort(); 816a4bd5210SJason Evans } 817a4bd5210SJason Evans errno = ENOMEM; 818a4bd5210SJason Evans } 819a4bd5210SJason Evans if (config_prof && opt_prof && ret != NULL) 820a4bd5210SJason Evans prof_malloc(ret, usize, cnt); 821a4bd5210SJason Evans if (config_stats && ret != NULL) { 822a4bd5210SJason Evans assert(usize == isalloc(ret, config_prof)); 823a4bd5210SJason Evans thread_allocated_tsd_get()->allocated += usize; 824a4bd5210SJason Evans } 825a4bd5210SJason Evans UTRACE(0, size, ret); 826a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, false); 827a4bd5210SJason Evans return (ret); 828a4bd5210SJason Evans } 829a4bd5210SJason Evans 830a4bd5210SJason Evans JEMALLOC_ATTR(nonnull(1)) 831a4bd5210SJason Evans #ifdef JEMALLOC_PROF 832a4bd5210SJason Evans /* 833a4bd5210SJason Evans * Avoid any uncertainty as to how many backtrace frames to ignore in 834a4bd5210SJason Evans * PROF_ALLOC_PREP(). 835a4bd5210SJason Evans */ 836a4bd5210SJason Evans JEMALLOC_ATTR(noinline) 837a4bd5210SJason Evans #endif 838a4bd5210SJason Evans static int 839a4bd5210SJason Evans imemalign(void **memptr, size_t alignment, size_t size, 840a4bd5210SJason Evans size_t min_alignment) 841a4bd5210SJason Evans { 842a4bd5210SJason Evans int ret; 843a4bd5210SJason Evans size_t usize; 844a4bd5210SJason Evans void *result; 845a4bd5210SJason Evans prof_thr_cnt_t *cnt JEMALLOC_CC_SILENCE_INIT(NULL); 846a4bd5210SJason Evans 847a4bd5210SJason Evans assert(min_alignment != 0); 848a4bd5210SJason Evans 849a4bd5210SJason Evans if (malloc_init()) 850a4bd5210SJason Evans result = NULL; 851a4bd5210SJason Evans else { 852a4bd5210SJason Evans if (size == 0) 853a4bd5210SJason Evans size = 1; 854a4bd5210SJason Evans 855a4bd5210SJason Evans /* Make sure that alignment is a large enough power of 2. */ 856a4bd5210SJason Evans if (((alignment - 1) & alignment) != 0 857a4bd5210SJason Evans || (alignment < min_alignment)) { 858a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 859a4bd5210SJason Evans malloc_write("<jemalloc>: Error allocating " 860a4bd5210SJason Evans "aligned memory: invalid alignment\n"); 861a4bd5210SJason Evans abort(); 862a4bd5210SJason Evans } 863a4bd5210SJason Evans result = NULL; 864a4bd5210SJason Evans ret = EINVAL; 865a4bd5210SJason Evans goto label_return; 866a4bd5210SJason Evans } 867a4bd5210SJason Evans 868a4bd5210SJason Evans usize = sa2u(size, alignment); 869a4bd5210SJason Evans if (usize == 0) { 870a4bd5210SJason Evans result = NULL; 871a4bd5210SJason Evans ret = ENOMEM; 872a4bd5210SJason Evans goto label_return; 873a4bd5210SJason Evans } 874a4bd5210SJason Evans 875a4bd5210SJason Evans if (config_prof && opt_prof) { 876a4bd5210SJason Evans PROF_ALLOC_PREP(2, usize, cnt); 877a4bd5210SJason Evans if (cnt == NULL) { 878a4bd5210SJason Evans result = NULL; 879a4bd5210SJason Evans ret = EINVAL; 880a4bd5210SJason Evans } else { 881a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != 882a4bd5210SJason Evans (uintptr_t)1U && usize <= SMALL_MAXCLASS) { 883a4bd5210SJason Evans assert(sa2u(SMALL_MAXCLASS+1, 884a4bd5210SJason Evans alignment) != 0); 885a4bd5210SJason Evans result = ipalloc(sa2u(SMALL_MAXCLASS+1, 886a4bd5210SJason Evans alignment), alignment, false); 887a4bd5210SJason Evans if (result != NULL) { 888a4bd5210SJason Evans arena_prof_promoted(result, 889a4bd5210SJason Evans usize); 890a4bd5210SJason Evans } 891a4bd5210SJason Evans } else { 892a4bd5210SJason Evans result = ipalloc(usize, alignment, 893a4bd5210SJason Evans false); 894a4bd5210SJason Evans } 895a4bd5210SJason Evans } 896a4bd5210SJason Evans } else 897a4bd5210SJason Evans result = ipalloc(usize, alignment, false); 898a4bd5210SJason Evans } 899a4bd5210SJason Evans 900a4bd5210SJason Evans if (result == NULL) { 901a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 902a4bd5210SJason Evans malloc_write("<jemalloc>: Error allocating aligned " 903a4bd5210SJason Evans "memory: out of memory\n"); 904a4bd5210SJason Evans abort(); 905a4bd5210SJason Evans } 906a4bd5210SJason Evans ret = ENOMEM; 907a4bd5210SJason Evans goto label_return; 908a4bd5210SJason Evans } 909a4bd5210SJason Evans 910a4bd5210SJason Evans *memptr = result; 911a4bd5210SJason Evans ret = 0; 912a4bd5210SJason Evans 913a4bd5210SJason Evans label_return: 914a4bd5210SJason Evans if (config_stats && result != NULL) { 915a4bd5210SJason Evans assert(usize == isalloc(result, config_prof)); 916a4bd5210SJason Evans thread_allocated_tsd_get()->allocated += usize; 917a4bd5210SJason Evans } 918a4bd5210SJason Evans if (config_prof && opt_prof && result != NULL) 919a4bd5210SJason Evans prof_malloc(result, usize, cnt); 920a4bd5210SJason Evans UTRACE(0, size, result); 921a4bd5210SJason Evans return (ret); 922a4bd5210SJason Evans } 923a4bd5210SJason Evans 924a4bd5210SJason Evans JEMALLOC_ATTR(nonnull(1)) 925a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 926a4bd5210SJason Evans int 927a4bd5210SJason Evans je_posix_memalign(void **memptr, size_t alignment, size_t size) 928a4bd5210SJason Evans { 929a4bd5210SJason Evans int ret = imemalign(memptr, alignment, size, sizeof(void *)); 930a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(ret == 0, *memptr, isalloc(*memptr, 931a4bd5210SJason Evans config_prof), false); 932a4bd5210SJason Evans return (ret); 933a4bd5210SJason Evans } 934a4bd5210SJason Evans 935a4bd5210SJason Evans JEMALLOC_ATTR(malloc) 936a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 937a4bd5210SJason Evans void * 938a4bd5210SJason Evans je_aligned_alloc(size_t alignment, size_t size) 939a4bd5210SJason Evans { 940a4bd5210SJason Evans void *ret; 941a4bd5210SJason Evans int err; 942a4bd5210SJason Evans 943a4bd5210SJason Evans if ((err = imemalign(&ret, alignment, size, 1)) != 0) { 944a4bd5210SJason Evans ret = NULL; 945a4bd5210SJason Evans errno = err; 946a4bd5210SJason Evans } 947a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(err == 0, ret, isalloc(ret, config_prof), 948a4bd5210SJason Evans false); 949a4bd5210SJason Evans return (ret); 950a4bd5210SJason Evans } 951a4bd5210SJason Evans 952a4bd5210SJason Evans JEMALLOC_ATTR(malloc) 953a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 954a4bd5210SJason Evans void * 955a4bd5210SJason Evans je_calloc(size_t num, size_t size) 956a4bd5210SJason Evans { 957a4bd5210SJason Evans void *ret; 958a4bd5210SJason Evans size_t num_size; 959a4bd5210SJason Evans size_t usize; 960a4bd5210SJason Evans prof_thr_cnt_t *cnt JEMALLOC_CC_SILENCE_INIT(NULL); 961a4bd5210SJason Evans 962a4bd5210SJason Evans if (malloc_init()) { 963a4bd5210SJason Evans num_size = 0; 964a4bd5210SJason Evans ret = NULL; 965a4bd5210SJason Evans goto label_return; 966a4bd5210SJason Evans } 967a4bd5210SJason Evans 968a4bd5210SJason Evans num_size = num * size; 969a4bd5210SJason Evans if (num_size == 0) { 970a4bd5210SJason Evans if (num == 0 || size == 0) 971a4bd5210SJason Evans num_size = 1; 972a4bd5210SJason Evans else { 973a4bd5210SJason Evans ret = NULL; 974a4bd5210SJason Evans goto label_return; 975a4bd5210SJason Evans } 976a4bd5210SJason Evans /* 977a4bd5210SJason Evans * Try to avoid division here. We know that it isn't possible to 978a4bd5210SJason Evans * overflow during multiplication if neither operand uses any of the 979a4bd5210SJason Evans * most significant half of the bits in a size_t. 980a4bd5210SJason Evans */ 981a4bd5210SJason Evans } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2))) 982a4bd5210SJason Evans && (num_size / size != num)) { 983a4bd5210SJason Evans /* size_t overflow. */ 984a4bd5210SJason Evans ret = NULL; 985a4bd5210SJason Evans goto label_return; 986a4bd5210SJason Evans } 987a4bd5210SJason Evans 988a4bd5210SJason Evans if (config_prof && opt_prof) { 989a4bd5210SJason Evans usize = s2u(num_size); 990a4bd5210SJason Evans PROF_ALLOC_PREP(1, usize, cnt); 991a4bd5210SJason Evans if (cnt == NULL) { 992a4bd5210SJason Evans ret = NULL; 993a4bd5210SJason Evans goto label_return; 994a4bd5210SJason Evans } 995a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && usize 996a4bd5210SJason Evans <= SMALL_MAXCLASS) { 997a4bd5210SJason Evans ret = icalloc(SMALL_MAXCLASS+1); 998a4bd5210SJason Evans if (ret != NULL) 999a4bd5210SJason Evans arena_prof_promoted(ret, usize); 1000a4bd5210SJason Evans } else 1001a4bd5210SJason Evans ret = icalloc(num_size); 1002a4bd5210SJason Evans } else { 1003a4bd5210SJason Evans if (config_stats || (config_valgrind && opt_valgrind)) 1004a4bd5210SJason Evans usize = s2u(num_size); 1005a4bd5210SJason Evans ret = icalloc(num_size); 1006a4bd5210SJason Evans } 1007a4bd5210SJason Evans 1008a4bd5210SJason Evans label_return: 1009a4bd5210SJason Evans if (ret == NULL) { 1010a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 1011a4bd5210SJason Evans malloc_write("<jemalloc>: Error in calloc(): out of " 1012a4bd5210SJason Evans "memory\n"); 1013a4bd5210SJason Evans abort(); 1014a4bd5210SJason Evans } 1015a4bd5210SJason Evans errno = ENOMEM; 1016a4bd5210SJason Evans } 1017a4bd5210SJason Evans 1018a4bd5210SJason Evans if (config_prof && opt_prof && ret != NULL) 1019a4bd5210SJason Evans prof_malloc(ret, usize, cnt); 1020a4bd5210SJason Evans if (config_stats && ret != NULL) { 1021a4bd5210SJason Evans assert(usize == isalloc(ret, config_prof)); 1022a4bd5210SJason Evans thread_allocated_tsd_get()->allocated += usize; 1023a4bd5210SJason Evans } 1024a4bd5210SJason Evans UTRACE(0, num_size, ret); 1025a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, true); 1026a4bd5210SJason Evans return (ret); 1027a4bd5210SJason Evans } 1028a4bd5210SJason Evans 1029a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1030a4bd5210SJason Evans void * 1031a4bd5210SJason Evans je_realloc(void *ptr, size_t size) 1032a4bd5210SJason Evans { 1033a4bd5210SJason Evans void *ret; 1034a4bd5210SJason Evans size_t usize; 1035a4bd5210SJason Evans size_t old_size = 0; 1036a4bd5210SJason Evans size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); 1037a4bd5210SJason Evans prof_thr_cnt_t *cnt JEMALLOC_CC_SILENCE_INIT(NULL); 1038a4bd5210SJason Evans prof_ctx_t *old_ctx JEMALLOC_CC_SILENCE_INIT(NULL); 1039a4bd5210SJason Evans 1040a4bd5210SJason Evans if (size == 0) { 1041a4bd5210SJason Evans if (ptr != NULL) { 1042a4bd5210SJason Evans /* realloc(ptr, 0) is equivalent to free(p). */ 1043a4bd5210SJason Evans if (config_prof) { 1044a4bd5210SJason Evans old_size = isalloc(ptr, true); 1045a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1046a4bd5210SJason Evans old_rzsize = p2rz(ptr); 1047a4bd5210SJason Evans } else if (config_stats) { 1048a4bd5210SJason Evans old_size = isalloc(ptr, false); 1049a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1050a4bd5210SJason Evans old_rzsize = u2rz(old_size); 1051a4bd5210SJason Evans } else if (config_valgrind && opt_valgrind) { 1052a4bd5210SJason Evans old_size = isalloc(ptr, false); 1053a4bd5210SJason Evans old_rzsize = u2rz(old_size); 1054a4bd5210SJason Evans } 1055a4bd5210SJason Evans if (config_prof && opt_prof) { 1056a4bd5210SJason Evans old_ctx = prof_ctx_get(ptr); 1057a4bd5210SJason Evans cnt = NULL; 1058a4bd5210SJason Evans } 1059a4bd5210SJason Evans iqalloc(ptr); 1060a4bd5210SJason Evans ret = NULL; 1061a4bd5210SJason Evans goto label_return; 1062a4bd5210SJason Evans } else 1063a4bd5210SJason Evans size = 1; 1064a4bd5210SJason Evans } 1065a4bd5210SJason Evans 1066a4bd5210SJason Evans if (ptr != NULL) { 1067a4bd5210SJason Evans assert(malloc_initialized || IS_INITIALIZER); 1068a4bd5210SJason Evans 1069a4bd5210SJason Evans if (config_prof) { 1070a4bd5210SJason Evans old_size = isalloc(ptr, true); 1071a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1072a4bd5210SJason Evans old_rzsize = p2rz(ptr); 1073a4bd5210SJason Evans } else if (config_stats) { 1074a4bd5210SJason Evans old_size = isalloc(ptr, false); 1075a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1076a4bd5210SJason Evans old_rzsize = u2rz(old_size); 1077a4bd5210SJason Evans } else if (config_valgrind && opt_valgrind) { 1078a4bd5210SJason Evans old_size = isalloc(ptr, false); 1079a4bd5210SJason Evans old_rzsize = u2rz(old_size); 1080a4bd5210SJason Evans } 1081a4bd5210SJason Evans if (config_prof && opt_prof) { 1082a4bd5210SJason Evans usize = s2u(size); 1083a4bd5210SJason Evans old_ctx = prof_ctx_get(ptr); 1084a4bd5210SJason Evans PROF_ALLOC_PREP(1, usize, cnt); 1085a4bd5210SJason Evans if (cnt == NULL) { 1086a4bd5210SJason Evans old_ctx = NULL; 1087a4bd5210SJason Evans ret = NULL; 1088a4bd5210SJason Evans goto label_oom; 1089a4bd5210SJason Evans } 1090a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && 1091a4bd5210SJason Evans usize <= SMALL_MAXCLASS) { 1092a4bd5210SJason Evans ret = iralloc(ptr, SMALL_MAXCLASS+1, 0, 0, 1093a4bd5210SJason Evans false, false); 1094a4bd5210SJason Evans if (ret != NULL) 1095a4bd5210SJason Evans arena_prof_promoted(ret, usize); 1096a4bd5210SJason Evans else 1097a4bd5210SJason Evans old_ctx = NULL; 1098a4bd5210SJason Evans } else { 1099a4bd5210SJason Evans ret = iralloc(ptr, size, 0, 0, false, false); 1100a4bd5210SJason Evans if (ret == NULL) 1101a4bd5210SJason Evans old_ctx = NULL; 1102a4bd5210SJason Evans } 1103a4bd5210SJason Evans } else { 1104a4bd5210SJason Evans if (config_stats || (config_valgrind && opt_valgrind)) 1105a4bd5210SJason Evans usize = s2u(size); 1106a4bd5210SJason Evans ret = iralloc(ptr, size, 0, 0, false, false); 1107a4bd5210SJason Evans } 1108a4bd5210SJason Evans 1109a4bd5210SJason Evans label_oom: 1110a4bd5210SJason Evans if (ret == NULL) { 1111a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 1112a4bd5210SJason Evans malloc_write("<jemalloc>: Error in realloc(): " 1113a4bd5210SJason Evans "out of memory\n"); 1114a4bd5210SJason Evans abort(); 1115a4bd5210SJason Evans } 1116a4bd5210SJason Evans errno = ENOMEM; 1117a4bd5210SJason Evans } 1118a4bd5210SJason Evans } else { 1119a4bd5210SJason Evans /* realloc(NULL, size) is equivalent to malloc(size). */ 1120a4bd5210SJason Evans if (config_prof && opt_prof) 1121a4bd5210SJason Evans old_ctx = NULL; 1122a4bd5210SJason Evans if (malloc_init()) { 1123a4bd5210SJason Evans if (config_prof && opt_prof) 1124a4bd5210SJason Evans cnt = NULL; 1125a4bd5210SJason Evans ret = NULL; 1126a4bd5210SJason Evans } else { 1127a4bd5210SJason Evans if (config_prof && opt_prof) { 1128a4bd5210SJason Evans usize = s2u(size); 1129a4bd5210SJason Evans PROF_ALLOC_PREP(1, usize, cnt); 1130a4bd5210SJason Evans if (cnt == NULL) 1131a4bd5210SJason Evans ret = NULL; 1132a4bd5210SJason Evans else { 1133a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != 1134a4bd5210SJason Evans (uintptr_t)1U && usize <= 1135a4bd5210SJason Evans SMALL_MAXCLASS) { 1136a4bd5210SJason Evans ret = imalloc(SMALL_MAXCLASS+1); 1137a4bd5210SJason Evans if (ret != NULL) { 1138a4bd5210SJason Evans arena_prof_promoted(ret, 1139a4bd5210SJason Evans usize); 1140a4bd5210SJason Evans } 1141a4bd5210SJason Evans } else 1142a4bd5210SJason Evans ret = imalloc(size); 1143a4bd5210SJason Evans } 1144a4bd5210SJason Evans } else { 1145a4bd5210SJason Evans if (config_stats || (config_valgrind && 1146a4bd5210SJason Evans opt_valgrind)) 1147a4bd5210SJason Evans usize = s2u(size); 1148a4bd5210SJason Evans ret = imalloc(size); 1149a4bd5210SJason Evans } 1150a4bd5210SJason Evans } 1151a4bd5210SJason Evans 1152a4bd5210SJason Evans if (ret == NULL) { 1153a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 1154a4bd5210SJason Evans malloc_write("<jemalloc>: Error in realloc(): " 1155a4bd5210SJason Evans "out of memory\n"); 1156a4bd5210SJason Evans abort(); 1157a4bd5210SJason Evans } 1158a4bd5210SJason Evans errno = ENOMEM; 1159a4bd5210SJason Evans } 1160a4bd5210SJason Evans } 1161a4bd5210SJason Evans 1162a4bd5210SJason Evans label_return: 1163a4bd5210SJason Evans if (config_prof && opt_prof) 1164a4bd5210SJason Evans prof_realloc(ret, usize, cnt, old_size, old_ctx); 1165a4bd5210SJason Evans if (config_stats && ret != NULL) { 1166a4bd5210SJason Evans thread_allocated_t *ta; 1167a4bd5210SJason Evans assert(usize == isalloc(ret, config_prof)); 1168a4bd5210SJason Evans ta = thread_allocated_tsd_get(); 1169a4bd5210SJason Evans ta->allocated += usize; 1170a4bd5210SJason Evans ta->deallocated += old_size; 1171a4bd5210SJason Evans } 1172a4bd5210SJason Evans UTRACE(ptr, size, ret); 1173a4bd5210SJason Evans JEMALLOC_VALGRIND_REALLOC(ret, usize, ptr, old_size, old_rzsize, false); 1174a4bd5210SJason Evans return (ret); 1175a4bd5210SJason Evans } 1176a4bd5210SJason Evans 1177a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1178a4bd5210SJason Evans void 1179a4bd5210SJason Evans je_free(void *ptr) 1180a4bd5210SJason Evans { 1181a4bd5210SJason Evans 1182a4bd5210SJason Evans UTRACE(ptr, 0, 0); 1183a4bd5210SJason Evans if (ptr != NULL) { 1184a4bd5210SJason Evans size_t usize; 1185a4bd5210SJason Evans size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); 1186a4bd5210SJason Evans 1187a4bd5210SJason Evans assert(malloc_initialized || IS_INITIALIZER); 1188a4bd5210SJason Evans 1189a4bd5210SJason Evans if (config_prof && opt_prof) { 1190a4bd5210SJason Evans usize = isalloc(ptr, config_prof); 1191a4bd5210SJason Evans prof_free(ptr, usize); 1192a4bd5210SJason Evans } else if (config_stats || config_valgrind) 1193a4bd5210SJason Evans usize = isalloc(ptr, config_prof); 1194a4bd5210SJason Evans if (config_stats) 1195a4bd5210SJason Evans thread_allocated_tsd_get()->deallocated += usize; 1196a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1197a4bd5210SJason Evans rzsize = p2rz(ptr); 1198a4bd5210SJason Evans iqalloc(ptr); 1199a4bd5210SJason Evans JEMALLOC_VALGRIND_FREE(ptr, rzsize); 1200a4bd5210SJason Evans } 1201a4bd5210SJason Evans } 1202a4bd5210SJason Evans 1203a4bd5210SJason Evans /* 1204a4bd5210SJason Evans * End malloc(3)-compatible functions. 1205a4bd5210SJason Evans */ 1206a4bd5210SJason Evans /******************************************************************************/ 1207a4bd5210SJason Evans /* 1208a4bd5210SJason Evans * Begin non-standard override functions. 1209a4bd5210SJason Evans */ 1210a4bd5210SJason Evans 1211a4bd5210SJason Evans #ifdef JEMALLOC_OVERRIDE_MEMALIGN 1212a4bd5210SJason Evans JEMALLOC_ATTR(malloc) 1213a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1214a4bd5210SJason Evans void * 1215a4bd5210SJason Evans je_memalign(size_t alignment, size_t size) 1216a4bd5210SJason Evans { 1217a4bd5210SJason Evans void *ret JEMALLOC_CC_SILENCE_INIT(NULL); 1218a4bd5210SJason Evans imemalign(&ret, alignment, size, 1); 1219a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, size, false); 1220a4bd5210SJason Evans return (ret); 1221a4bd5210SJason Evans } 1222a4bd5210SJason Evans #endif 1223a4bd5210SJason Evans 1224a4bd5210SJason Evans #ifdef JEMALLOC_OVERRIDE_VALLOC 1225a4bd5210SJason Evans JEMALLOC_ATTR(malloc) 1226a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1227a4bd5210SJason Evans void * 1228a4bd5210SJason Evans je_valloc(size_t size) 1229a4bd5210SJason Evans { 1230a4bd5210SJason Evans void *ret JEMALLOC_CC_SILENCE_INIT(NULL); 1231a4bd5210SJason Evans imemalign(&ret, PAGE, size, 1); 1232a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, size, false); 1233a4bd5210SJason Evans return (ret); 1234a4bd5210SJason Evans } 1235a4bd5210SJason Evans #endif 1236a4bd5210SJason Evans 1237a4bd5210SJason Evans /* 1238a4bd5210SJason Evans * is_malloc(je_malloc) is some macro magic to detect if jemalloc_defs.h has 1239a4bd5210SJason Evans * #define je_malloc malloc 1240a4bd5210SJason Evans */ 1241a4bd5210SJason Evans #define malloc_is_malloc 1 1242a4bd5210SJason Evans #define is_malloc_(a) malloc_is_ ## a 1243a4bd5210SJason Evans #define is_malloc(a) is_malloc_(a) 1244a4bd5210SJason Evans 1245a4bd5210SJason Evans #if ((is_malloc(je_malloc) == 1) && defined(__GLIBC__) && !defined(__UCLIBC__)) 1246a4bd5210SJason Evans /* 1247a4bd5210SJason Evans * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible 1248a4bd5210SJason Evans * to inconsistently reference libc's malloc(3)-compatible functions 1249a4bd5210SJason Evans * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541). 1250a4bd5210SJason Evans * 1251a4bd5210SJason Evans * These definitions interpose hooks in glibc. The functions are actually 1252a4bd5210SJason Evans * passed an extra argument for the caller return address, which will be 1253a4bd5210SJason Evans * ignored. 1254a4bd5210SJason Evans */ 1255a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1256a4bd5210SJason Evans void (* const __free_hook)(void *ptr) = je_free; 1257a4bd5210SJason Evans 1258a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1259a4bd5210SJason Evans void *(* const __malloc_hook)(size_t size) = je_malloc; 1260a4bd5210SJason Evans 1261a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1262a4bd5210SJason Evans void *(* const __realloc_hook)(void *ptr, size_t size) = je_realloc; 1263a4bd5210SJason Evans 1264a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1265a4bd5210SJason Evans void *(* const __memalign_hook)(size_t alignment, size_t size) = je_memalign; 1266a4bd5210SJason Evans #endif 1267a4bd5210SJason Evans 1268a4bd5210SJason Evans /* 1269a4bd5210SJason Evans * End non-standard override functions. 1270a4bd5210SJason Evans */ 1271a4bd5210SJason Evans /******************************************************************************/ 1272a4bd5210SJason Evans /* 1273a4bd5210SJason Evans * Begin non-standard functions. 1274a4bd5210SJason Evans */ 1275a4bd5210SJason Evans 1276a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1277a4bd5210SJason Evans size_t 1278a4bd5210SJason Evans je_malloc_usable_size(const void *ptr) 1279a4bd5210SJason Evans { 1280a4bd5210SJason Evans size_t ret; 1281a4bd5210SJason Evans 1282a4bd5210SJason Evans assert(malloc_initialized || IS_INITIALIZER); 1283a4bd5210SJason Evans 1284a4bd5210SJason Evans if (config_ivsalloc) 1285a4bd5210SJason Evans ret = ivsalloc(ptr, config_prof); 1286a4bd5210SJason Evans else 1287a4bd5210SJason Evans ret = (ptr != NULL) ? isalloc(ptr, config_prof) : 0; 1288a4bd5210SJason Evans 1289a4bd5210SJason Evans return (ret); 1290a4bd5210SJason Evans } 1291a4bd5210SJason Evans 1292a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1293a4bd5210SJason Evans void 1294a4bd5210SJason Evans je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque, 1295a4bd5210SJason Evans const char *opts) 1296a4bd5210SJason Evans { 1297a4bd5210SJason Evans 1298a4bd5210SJason Evans stats_print(write_cb, cbopaque, opts); 1299a4bd5210SJason Evans } 1300a4bd5210SJason Evans 1301a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1302a4bd5210SJason Evans int 1303a4bd5210SJason Evans je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, 1304a4bd5210SJason Evans size_t newlen) 1305a4bd5210SJason Evans { 1306a4bd5210SJason Evans 1307a4bd5210SJason Evans if (malloc_init()) 1308a4bd5210SJason Evans return (EAGAIN); 1309a4bd5210SJason Evans 1310a4bd5210SJason Evans return (ctl_byname(name, oldp, oldlenp, newp, newlen)); 1311a4bd5210SJason Evans } 1312a4bd5210SJason Evans 1313a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1314a4bd5210SJason Evans int 1315a4bd5210SJason Evans je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) 1316a4bd5210SJason Evans { 1317a4bd5210SJason Evans 1318a4bd5210SJason Evans if (malloc_init()) 1319a4bd5210SJason Evans return (EAGAIN); 1320a4bd5210SJason Evans 1321a4bd5210SJason Evans return (ctl_nametomib(name, mibp, miblenp)); 1322a4bd5210SJason Evans } 1323a4bd5210SJason Evans 1324a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1325a4bd5210SJason Evans int 1326a4bd5210SJason Evans je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1327a4bd5210SJason Evans void *newp, size_t newlen) 1328a4bd5210SJason Evans { 1329a4bd5210SJason Evans 1330a4bd5210SJason Evans if (malloc_init()) 1331a4bd5210SJason Evans return (EAGAIN); 1332a4bd5210SJason Evans 1333a4bd5210SJason Evans return (ctl_bymib(mib, miblen, oldp, oldlenp, newp, newlen)); 1334a4bd5210SJason Evans } 1335a4bd5210SJason Evans 1336a4bd5210SJason Evans /* 1337a4bd5210SJason Evans * End non-standard functions. 1338a4bd5210SJason Evans */ 1339a4bd5210SJason Evans /******************************************************************************/ 1340a4bd5210SJason Evans /* 1341a4bd5210SJason Evans * Begin experimental functions. 1342a4bd5210SJason Evans */ 1343a4bd5210SJason Evans #ifdef JEMALLOC_EXPERIMENTAL 1344a4bd5210SJason Evans 1345a4bd5210SJason Evans JEMALLOC_INLINE void * 1346a4bd5210SJason Evans iallocm(size_t usize, size_t alignment, bool zero) 1347a4bd5210SJason Evans { 1348a4bd5210SJason Evans 1349a4bd5210SJason Evans assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize, 1350a4bd5210SJason Evans alignment))); 1351a4bd5210SJason Evans 1352a4bd5210SJason Evans if (alignment != 0) 1353a4bd5210SJason Evans return (ipalloc(usize, alignment, zero)); 1354a4bd5210SJason Evans else if (zero) 1355a4bd5210SJason Evans return (icalloc(usize)); 1356a4bd5210SJason Evans else 1357a4bd5210SJason Evans return (imalloc(usize)); 1358a4bd5210SJason Evans } 1359a4bd5210SJason Evans 1360a4bd5210SJason Evans JEMALLOC_ATTR(nonnull(1)) 1361a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1362a4bd5210SJason Evans int 1363a4bd5210SJason Evans je_allocm(void **ptr, size_t *rsize, size_t size, int flags) 1364a4bd5210SJason Evans { 1365a4bd5210SJason Evans void *p; 1366a4bd5210SJason Evans size_t usize; 1367a4bd5210SJason Evans size_t alignment = (ZU(1) << (flags & ALLOCM_LG_ALIGN_MASK) 1368a4bd5210SJason Evans & (SIZE_T_MAX-1)); 1369a4bd5210SJason Evans bool zero = flags & ALLOCM_ZERO; 1370a4bd5210SJason Evans prof_thr_cnt_t *cnt; 1371a4bd5210SJason Evans 1372a4bd5210SJason Evans assert(ptr != NULL); 1373a4bd5210SJason Evans assert(size != 0); 1374a4bd5210SJason Evans 1375a4bd5210SJason Evans if (malloc_init()) 1376a4bd5210SJason Evans goto label_oom; 1377a4bd5210SJason Evans 1378a4bd5210SJason Evans usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); 1379a4bd5210SJason Evans if (usize == 0) 1380a4bd5210SJason Evans goto label_oom; 1381a4bd5210SJason Evans 1382a4bd5210SJason Evans if (config_prof && opt_prof) { 1383a4bd5210SJason Evans PROF_ALLOC_PREP(1, usize, cnt); 1384a4bd5210SJason Evans if (cnt == NULL) 1385a4bd5210SJason Evans goto label_oom; 1386a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && usize <= 1387a4bd5210SJason Evans SMALL_MAXCLASS) { 1388a4bd5210SJason Evans size_t usize_promoted = (alignment == 0) ? 1389a4bd5210SJason Evans s2u(SMALL_MAXCLASS+1) : sa2u(SMALL_MAXCLASS+1, 1390a4bd5210SJason Evans alignment); 1391a4bd5210SJason Evans assert(usize_promoted != 0); 1392a4bd5210SJason Evans p = iallocm(usize_promoted, alignment, zero); 1393a4bd5210SJason Evans if (p == NULL) 1394a4bd5210SJason Evans goto label_oom; 1395a4bd5210SJason Evans arena_prof_promoted(p, usize); 1396a4bd5210SJason Evans } else { 1397a4bd5210SJason Evans p = iallocm(usize, alignment, zero); 1398a4bd5210SJason Evans if (p == NULL) 1399a4bd5210SJason Evans goto label_oom; 1400a4bd5210SJason Evans } 1401a4bd5210SJason Evans prof_malloc(p, usize, cnt); 1402a4bd5210SJason Evans } else { 1403a4bd5210SJason Evans p = iallocm(usize, alignment, zero); 1404a4bd5210SJason Evans if (p == NULL) 1405a4bd5210SJason Evans goto label_oom; 1406a4bd5210SJason Evans } 1407a4bd5210SJason Evans if (rsize != NULL) 1408a4bd5210SJason Evans *rsize = usize; 1409a4bd5210SJason Evans 1410a4bd5210SJason Evans *ptr = p; 1411a4bd5210SJason Evans if (config_stats) { 1412a4bd5210SJason Evans assert(usize == isalloc(p, config_prof)); 1413a4bd5210SJason Evans thread_allocated_tsd_get()->allocated += usize; 1414a4bd5210SJason Evans } 1415a4bd5210SJason Evans UTRACE(0, size, p); 1416a4bd5210SJason Evans JEMALLOC_VALGRIND_MALLOC(true, p, usize, zero); 1417a4bd5210SJason Evans return (ALLOCM_SUCCESS); 1418a4bd5210SJason Evans label_oom: 1419a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 1420a4bd5210SJason Evans malloc_write("<jemalloc>: Error in allocm(): " 1421a4bd5210SJason Evans "out of memory\n"); 1422a4bd5210SJason Evans abort(); 1423a4bd5210SJason Evans } 1424a4bd5210SJason Evans *ptr = NULL; 1425a4bd5210SJason Evans UTRACE(0, size, 0); 1426a4bd5210SJason Evans return (ALLOCM_ERR_OOM); 1427a4bd5210SJason Evans } 1428a4bd5210SJason Evans 1429a4bd5210SJason Evans JEMALLOC_ATTR(nonnull(1)) 1430a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1431a4bd5210SJason Evans int 1432a4bd5210SJason Evans je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags) 1433a4bd5210SJason Evans { 1434a4bd5210SJason Evans void *p, *q; 1435a4bd5210SJason Evans size_t usize; 1436a4bd5210SJason Evans size_t old_size; 1437a4bd5210SJason Evans size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); 1438a4bd5210SJason Evans size_t alignment = (ZU(1) << (flags & ALLOCM_LG_ALIGN_MASK) 1439a4bd5210SJason Evans & (SIZE_T_MAX-1)); 1440a4bd5210SJason Evans bool zero = flags & ALLOCM_ZERO; 1441a4bd5210SJason Evans bool no_move = flags & ALLOCM_NO_MOVE; 1442a4bd5210SJason Evans prof_thr_cnt_t *cnt; 1443a4bd5210SJason Evans 1444a4bd5210SJason Evans assert(ptr != NULL); 1445a4bd5210SJason Evans assert(*ptr != NULL); 1446a4bd5210SJason Evans assert(size != 0); 1447a4bd5210SJason Evans assert(SIZE_T_MAX - size >= extra); 1448a4bd5210SJason Evans assert(malloc_initialized || IS_INITIALIZER); 1449a4bd5210SJason Evans 1450a4bd5210SJason Evans p = *ptr; 1451a4bd5210SJason Evans if (config_prof && opt_prof) { 1452a4bd5210SJason Evans /* 1453a4bd5210SJason Evans * usize isn't knowable before iralloc() returns when extra is 1454a4bd5210SJason Evans * non-zero. Therefore, compute its maximum possible value and 1455a4bd5210SJason Evans * use that in PROF_ALLOC_PREP() to decide whether to capture a 1456a4bd5210SJason Evans * backtrace. prof_realloc() will use the actual usize to 1457a4bd5210SJason Evans * decide whether to sample. 1458a4bd5210SJason Evans */ 1459a4bd5210SJason Evans size_t max_usize = (alignment == 0) ? s2u(size+extra) : 1460a4bd5210SJason Evans sa2u(size+extra, alignment); 1461a4bd5210SJason Evans prof_ctx_t *old_ctx = prof_ctx_get(p); 1462a4bd5210SJason Evans old_size = isalloc(p, true); 1463a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1464a4bd5210SJason Evans old_rzsize = p2rz(p); 1465a4bd5210SJason Evans PROF_ALLOC_PREP(1, max_usize, cnt); 1466a4bd5210SJason Evans if (cnt == NULL) 1467a4bd5210SJason Evans goto label_oom; 1468a4bd5210SJason Evans /* 1469a4bd5210SJason Evans * Use minimum usize to determine whether promotion may happen. 1470a4bd5210SJason Evans */ 1471a4bd5210SJason Evans if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U 1472a4bd5210SJason Evans && ((alignment == 0) ? s2u(size) : sa2u(size, alignment)) 1473a4bd5210SJason Evans <= SMALL_MAXCLASS) { 1474a4bd5210SJason Evans q = iralloc(p, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >= 1475a4bd5210SJason Evans size+extra) ? 0 : size+extra - (SMALL_MAXCLASS+1), 1476a4bd5210SJason Evans alignment, zero, no_move); 1477a4bd5210SJason Evans if (q == NULL) 1478a4bd5210SJason Evans goto label_err; 1479a4bd5210SJason Evans if (max_usize < PAGE) { 1480a4bd5210SJason Evans usize = max_usize; 1481a4bd5210SJason Evans arena_prof_promoted(q, usize); 1482a4bd5210SJason Evans } else 1483a4bd5210SJason Evans usize = isalloc(q, config_prof); 1484a4bd5210SJason Evans } else { 1485a4bd5210SJason Evans q = iralloc(p, size, extra, alignment, zero, no_move); 1486a4bd5210SJason Evans if (q == NULL) 1487a4bd5210SJason Evans goto label_err; 1488a4bd5210SJason Evans usize = isalloc(q, config_prof); 1489a4bd5210SJason Evans } 1490a4bd5210SJason Evans prof_realloc(q, usize, cnt, old_size, old_ctx); 1491a4bd5210SJason Evans if (rsize != NULL) 1492a4bd5210SJason Evans *rsize = usize; 1493a4bd5210SJason Evans } else { 1494a4bd5210SJason Evans if (config_stats) { 1495a4bd5210SJason Evans old_size = isalloc(p, false); 1496a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1497a4bd5210SJason Evans old_rzsize = u2rz(old_size); 1498a4bd5210SJason Evans } else if (config_valgrind && opt_valgrind) { 1499a4bd5210SJason Evans old_size = isalloc(p, false); 1500a4bd5210SJason Evans old_rzsize = u2rz(old_size); 1501a4bd5210SJason Evans } 1502a4bd5210SJason Evans q = iralloc(p, size, extra, alignment, zero, no_move); 1503a4bd5210SJason Evans if (q == NULL) 1504a4bd5210SJason Evans goto label_err; 1505a4bd5210SJason Evans if (config_stats) 1506a4bd5210SJason Evans usize = isalloc(q, config_prof); 1507a4bd5210SJason Evans if (rsize != NULL) { 1508a4bd5210SJason Evans if (config_stats == false) 1509a4bd5210SJason Evans usize = isalloc(q, config_prof); 1510a4bd5210SJason Evans *rsize = usize; 1511a4bd5210SJason Evans } 1512a4bd5210SJason Evans } 1513a4bd5210SJason Evans 1514a4bd5210SJason Evans *ptr = q; 1515a4bd5210SJason Evans if (config_stats) { 1516a4bd5210SJason Evans thread_allocated_t *ta; 1517a4bd5210SJason Evans ta = thread_allocated_tsd_get(); 1518a4bd5210SJason Evans ta->allocated += usize; 1519a4bd5210SJason Evans ta->deallocated += old_size; 1520a4bd5210SJason Evans } 1521a4bd5210SJason Evans UTRACE(p, size, q); 1522a4bd5210SJason Evans JEMALLOC_VALGRIND_REALLOC(q, usize, p, old_size, old_rzsize, zero); 1523a4bd5210SJason Evans return (ALLOCM_SUCCESS); 1524a4bd5210SJason Evans label_err: 1525a4bd5210SJason Evans if (no_move) { 1526a4bd5210SJason Evans UTRACE(p, size, q); 1527a4bd5210SJason Evans return (ALLOCM_ERR_NOT_MOVED); 1528a4bd5210SJason Evans } 1529a4bd5210SJason Evans label_oom: 1530a4bd5210SJason Evans if (config_xmalloc && opt_xmalloc) { 1531a4bd5210SJason Evans malloc_write("<jemalloc>: Error in rallocm(): " 1532a4bd5210SJason Evans "out of memory\n"); 1533a4bd5210SJason Evans abort(); 1534a4bd5210SJason Evans } 1535a4bd5210SJason Evans UTRACE(p, size, 0); 1536a4bd5210SJason Evans return (ALLOCM_ERR_OOM); 1537a4bd5210SJason Evans } 1538a4bd5210SJason Evans 1539a4bd5210SJason Evans JEMALLOC_ATTR(nonnull(1)) 1540a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1541a4bd5210SJason Evans int 1542a4bd5210SJason Evans je_sallocm(const void *ptr, size_t *rsize, int flags) 1543a4bd5210SJason Evans { 1544a4bd5210SJason Evans size_t sz; 1545a4bd5210SJason Evans 1546a4bd5210SJason Evans assert(malloc_initialized || IS_INITIALIZER); 1547a4bd5210SJason Evans 1548a4bd5210SJason Evans if (config_ivsalloc) 1549a4bd5210SJason Evans sz = ivsalloc(ptr, config_prof); 1550a4bd5210SJason Evans else { 1551a4bd5210SJason Evans assert(ptr != NULL); 1552a4bd5210SJason Evans sz = isalloc(ptr, config_prof); 1553a4bd5210SJason Evans } 1554a4bd5210SJason Evans assert(rsize != NULL); 1555a4bd5210SJason Evans *rsize = sz; 1556a4bd5210SJason Evans 1557a4bd5210SJason Evans return (ALLOCM_SUCCESS); 1558a4bd5210SJason Evans } 1559a4bd5210SJason Evans 1560a4bd5210SJason Evans JEMALLOC_ATTR(nonnull(1)) 1561a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1562a4bd5210SJason Evans int 1563a4bd5210SJason Evans je_dallocm(void *ptr, int flags) 1564a4bd5210SJason Evans { 1565a4bd5210SJason Evans size_t usize; 1566a4bd5210SJason Evans size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); 1567a4bd5210SJason Evans 1568a4bd5210SJason Evans assert(ptr != NULL); 1569a4bd5210SJason Evans assert(malloc_initialized || IS_INITIALIZER); 1570a4bd5210SJason Evans 1571a4bd5210SJason Evans UTRACE(ptr, 0, 0); 1572a4bd5210SJason Evans if (config_stats || config_valgrind) 1573a4bd5210SJason Evans usize = isalloc(ptr, config_prof); 1574a4bd5210SJason Evans if (config_prof && opt_prof) { 1575a4bd5210SJason Evans if (config_stats == false && config_valgrind == false) 1576a4bd5210SJason Evans usize = isalloc(ptr, config_prof); 1577a4bd5210SJason Evans prof_free(ptr, usize); 1578a4bd5210SJason Evans } 1579a4bd5210SJason Evans if (config_stats) 1580a4bd5210SJason Evans thread_allocated_tsd_get()->deallocated += usize; 1581a4bd5210SJason Evans if (config_valgrind && opt_valgrind) 1582a4bd5210SJason Evans rzsize = p2rz(ptr); 1583a4bd5210SJason Evans iqalloc(ptr); 1584a4bd5210SJason Evans JEMALLOC_VALGRIND_FREE(ptr, rzsize); 1585a4bd5210SJason Evans 1586a4bd5210SJason Evans return (ALLOCM_SUCCESS); 1587a4bd5210SJason Evans } 1588a4bd5210SJason Evans 1589a4bd5210SJason Evans JEMALLOC_ATTR(visibility("default")) 1590a4bd5210SJason Evans int 1591a4bd5210SJason Evans je_nallocm(size_t *rsize, size_t size, int flags) 1592a4bd5210SJason Evans { 1593a4bd5210SJason Evans size_t usize; 1594a4bd5210SJason Evans size_t alignment = (ZU(1) << (flags & ALLOCM_LG_ALIGN_MASK) 1595a4bd5210SJason Evans & (SIZE_T_MAX-1)); 1596a4bd5210SJason Evans 1597a4bd5210SJason Evans assert(size != 0); 1598a4bd5210SJason Evans 1599a4bd5210SJason Evans if (malloc_init()) 1600a4bd5210SJason Evans return (ALLOCM_ERR_OOM); 1601a4bd5210SJason Evans 1602a4bd5210SJason Evans usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); 1603a4bd5210SJason Evans if (usize == 0) 1604a4bd5210SJason Evans return (ALLOCM_ERR_OOM); 1605a4bd5210SJason Evans 1606a4bd5210SJason Evans if (rsize != NULL) 1607a4bd5210SJason Evans *rsize = usize; 1608a4bd5210SJason Evans return (ALLOCM_SUCCESS); 1609a4bd5210SJason Evans } 1610a4bd5210SJason Evans 1611a4bd5210SJason Evans #endif 1612a4bd5210SJason Evans /* 1613a4bd5210SJason Evans * End experimental functions. 1614a4bd5210SJason Evans */ 1615a4bd5210SJason Evans /******************************************************************************/ 1616a4bd5210SJason Evans /* 1617a4bd5210SJason Evans * The following functions are used by threading libraries for protection of 1618a4bd5210SJason Evans * malloc during fork(). 1619a4bd5210SJason Evans */ 1620a4bd5210SJason Evans 1621a4bd5210SJason Evans #ifndef JEMALLOC_MUTEX_INIT_CB 1622a4bd5210SJason Evans void 1623a4bd5210SJason Evans jemalloc_prefork(void) 1624a4bd5210SJason Evans #else 16258ed34ab0SJason Evans JEMALLOC_ATTR(visibility("default")) 1626a4bd5210SJason Evans void 1627a4bd5210SJason Evans _malloc_prefork(void) 1628a4bd5210SJason Evans #endif 1629a4bd5210SJason Evans { 1630a4bd5210SJason Evans unsigned i; 1631a4bd5210SJason Evans 1632a4bd5210SJason Evans /* Acquire all mutexes in a safe order. */ 1633a4bd5210SJason Evans malloc_mutex_prefork(&arenas_lock); 1634a4bd5210SJason Evans for (i = 0; i < narenas; i++) { 1635a4bd5210SJason Evans if (arenas[i] != NULL) 1636a4bd5210SJason Evans arena_prefork(arenas[i]); 1637a4bd5210SJason Evans } 1638a4bd5210SJason Evans base_prefork(); 1639a4bd5210SJason Evans huge_prefork(); 1640a4bd5210SJason Evans chunk_dss_prefork(); 1641a4bd5210SJason Evans } 1642a4bd5210SJason Evans 1643a4bd5210SJason Evans #ifndef JEMALLOC_MUTEX_INIT_CB 1644a4bd5210SJason Evans void 1645a4bd5210SJason Evans jemalloc_postfork_parent(void) 1646a4bd5210SJason Evans #else 16478ed34ab0SJason Evans JEMALLOC_ATTR(visibility("default")) 1648a4bd5210SJason Evans void 1649a4bd5210SJason Evans _malloc_postfork(void) 1650a4bd5210SJason Evans #endif 1651a4bd5210SJason Evans { 1652a4bd5210SJason Evans unsigned i; 1653a4bd5210SJason Evans 1654a4bd5210SJason Evans /* Release all mutexes, now that fork() has completed. */ 1655a4bd5210SJason Evans chunk_dss_postfork_parent(); 1656a4bd5210SJason Evans huge_postfork_parent(); 1657a4bd5210SJason Evans base_postfork_parent(); 1658a4bd5210SJason Evans for (i = 0; i < narenas; i++) { 1659a4bd5210SJason Evans if (arenas[i] != NULL) 1660a4bd5210SJason Evans arena_postfork_parent(arenas[i]); 1661a4bd5210SJason Evans } 1662a4bd5210SJason Evans malloc_mutex_postfork_parent(&arenas_lock); 1663a4bd5210SJason Evans } 1664a4bd5210SJason Evans 1665a4bd5210SJason Evans void 1666a4bd5210SJason Evans jemalloc_postfork_child(void) 1667a4bd5210SJason Evans { 1668a4bd5210SJason Evans unsigned i; 1669a4bd5210SJason Evans 1670a4bd5210SJason Evans /* Release all mutexes, now that fork() has completed. */ 1671a4bd5210SJason Evans chunk_dss_postfork_child(); 1672a4bd5210SJason Evans huge_postfork_child(); 1673a4bd5210SJason Evans base_postfork_child(); 1674a4bd5210SJason Evans for (i = 0; i < narenas; i++) { 1675a4bd5210SJason Evans if (arenas[i] != NULL) 1676a4bd5210SJason Evans arena_postfork_child(arenas[i]); 1677a4bd5210SJason Evans } 1678a4bd5210SJason Evans malloc_mutex_postfork_child(&arenas_lock); 1679a4bd5210SJason Evans } 1680a4bd5210SJason Evans 1681a4bd5210SJason Evans /******************************************************************************/ 1682a4bd5210SJason Evans /* 1683a4bd5210SJason Evans * The following functions are used for TLS allocation/deallocation in static 1684a4bd5210SJason Evans * binaries on FreeBSD. The primary difference between these and i[mcd]alloc() 1685a4bd5210SJason Evans * is that these avoid accessing TLS variables. 1686a4bd5210SJason Evans */ 1687a4bd5210SJason Evans 1688a4bd5210SJason Evans static void * 1689a4bd5210SJason Evans a0alloc(size_t size, bool zero) 1690a4bd5210SJason Evans { 1691a4bd5210SJason Evans 1692a4bd5210SJason Evans if (malloc_init()) 1693a4bd5210SJason Evans return (NULL); 1694a4bd5210SJason Evans 1695a4bd5210SJason Evans if (size == 0) 1696a4bd5210SJason Evans size = 1; 1697a4bd5210SJason Evans 1698a4bd5210SJason Evans if (size <= arena_maxclass) 1699a4bd5210SJason Evans return (arena_malloc(arenas[0], size, zero, false)); 1700a4bd5210SJason Evans else 1701a4bd5210SJason Evans return (huge_malloc(size, zero)); 1702a4bd5210SJason Evans } 1703a4bd5210SJason Evans 1704a4bd5210SJason Evans void * 1705a4bd5210SJason Evans a0malloc(size_t size) 1706a4bd5210SJason Evans { 1707a4bd5210SJason Evans 1708a4bd5210SJason Evans return (a0alloc(size, false)); 1709a4bd5210SJason Evans } 1710a4bd5210SJason Evans 1711a4bd5210SJason Evans void * 1712a4bd5210SJason Evans a0calloc(size_t num, size_t size) 1713a4bd5210SJason Evans { 1714a4bd5210SJason Evans 1715a4bd5210SJason Evans return (a0alloc(num * size, true)); 1716a4bd5210SJason Evans } 1717a4bd5210SJason Evans 1718a4bd5210SJason Evans void 1719a4bd5210SJason Evans a0free(void *ptr) 1720a4bd5210SJason Evans { 1721a4bd5210SJason Evans arena_chunk_t *chunk; 1722a4bd5210SJason Evans 1723a4bd5210SJason Evans if (ptr == NULL) 1724a4bd5210SJason Evans return; 1725a4bd5210SJason Evans 1726a4bd5210SJason Evans chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); 1727a4bd5210SJason Evans if (chunk != ptr) 1728a4bd5210SJason Evans arena_dalloc(chunk->arena, chunk, ptr, false); 1729a4bd5210SJason Evans else 1730a4bd5210SJason Evans huge_dalloc(ptr, true); 1731a4bd5210SJason Evans } 1732a4bd5210SJason Evans 1733a4bd5210SJason Evans /******************************************************************************/ 1734