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