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