summaryrefslogtreecommitdiffstats
path: root/contrib/jemalloc/src/jemalloc.c
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2015-09-22 09:50:11 +0000
committerdim <dim@FreeBSD.org>2015-09-22 09:50:11 +0000
commit3715394e84505ef5709d6a973b555868e512038e (patch)
tree2fe2a49c48673e7324d1d5c28491a1684a358180 /contrib/jemalloc/src/jemalloc.c
parentfb090a675ae78b4b2524b69e42790a8308637cde (diff)
parent87b707ed34009ce34c69145b17a47c384047cf46 (diff)
downloadFreeBSD-src-3715394e84505ef5709d6a973b555868e512038e.zip
FreeBSD-src-3715394e84505ef5709d6a973b555868e512038e.tar.gz
Merge ^/head r288035 through r288099.
Diffstat (limited to 'contrib/jemalloc/src/jemalloc.c')
-rw-r--r--contrib/jemalloc/src/jemalloc.c175
1 files changed, 95 insertions, 80 deletions
diff --git a/contrib/jemalloc/src/jemalloc.c b/contrib/jemalloc/src/jemalloc.c
index d078a1f..b6cbb79 100644
--- a/contrib/jemalloc/src/jemalloc.c
+++ b/contrib/jemalloc/src/jemalloc.c
@@ -183,13 +183,24 @@ static bool malloc_initializer = NO_INITIALIZER;
static malloc_mutex_t init_lock = SRWLOCK_INIT;
#else
static malloc_mutex_t init_lock;
+static bool init_lock_initialized = false;
JEMALLOC_ATTR(constructor)
static void WINAPI
_init_init_lock(void)
{
- malloc_mutex_init(&init_lock);
+ /* If another constructor in the same binary is using mallctl to
+ * e.g. setup chunk hooks, it may end up running before this one,
+ * and malloc_init_hard will crash trying to lock the uninitialized
+ * lock. So we force an initialization of the lock in
+ * malloc_init_hard as well. We don't try to care about atomicity
+ * of the accessed to the init_lock_initialized boolean, since it
+ * really only matters early in the process creation, before any
+ * separate thread normally starts doing anything. */
+ if (!init_lock_initialized)
+ malloc_mutex_init(&init_lock);
+ init_lock_initialized = true;
}
#ifdef _MSC_VER
@@ -514,17 +525,17 @@ arena_get_hard(tsd_t *tsd, unsigned ind, bool init_if_missing)
assert(ind < narenas_actual || !init_if_missing);
narenas_cache = (ind < narenas_actual) ? narenas_actual : ind+1;
- if (!*arenas_cache_bypassp) {
+ if (tsd_nominal(tsd) && !*arenas_cache_bypassp) {
*arenas_cache_bypassp = true;
arenas_cache = (arena_t **)a0malloc(sizeof(arena_t *) *
narenas_cache);
*arenas_cache_bypassp = false;
- } else
- arenas_cache = NULL;
+ }
if (arenas_cache == NULL) {
/*
* This function must always tell the truth, even if
- * it's slow, so don't let OOM or recursive allocation
+ * it's slow, so don't let OOM, thread cleanup (note
+ * tsd_nominal check), nor recursive allocation
* avoidance (note arenas_cache_bypass check) get in the
* way.
*/
@@ -535,6 +546,7 @@ arena_get_hard(tsd_t *tsd, unsigned ind, bool init_if_missing)
malloc_mutex_unlock(&arenas_lock);
return (arena);
}
+ assert(tsd_nominal(tsd) && !*arenas_cache_bypassp);
tsd_arenas_cache_set(tsd, arenas_cache);
tsd_narenas_cache_set(tsd, narenas_cache);
}
@@ -653,8 +665,10 @@ arenas_cache_cleanup(tsd_t *tsd)
arena_t **arenas_cache;
arenas_cache = tsd_arenas_cache_get(tsd);
- if (arenas_cache != NULL)
+ if (arenas_cache != NULL) {
+ tsd_arenas_cache_set(tsd, NULL);
a0dalloc(arenas_cache);
+ }
}
void
@@ -1301,6 +1315,9 @@ static bool
malloc_init_hard(void)
{
+#if defined(_WIN32) && _WIN32_WINNT < 0x0600
+ _init_init_lock();
+#endif
malloc_mutex_lock(&init_lock);
if (!malloc_init_hard_needed()) {
malloc_mutex_unlock(&init_lock);
@@ -1365,7 +1382,7 @@ imalloc_prof(tsd_t *tsd, size_t usize)
void *p;
prof_tctx_t *tctx;
- tctx = prof_alloc_prep(tsd, usize, true);
+ tctx = prof_alloc_prep(tsd, usize, prof_active_get_unlocked(), true);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
p = imalloc_prof_sample(tsd, usize, tctx);
else
@@ -1455,7 +1472,7 @@ imemalign_prof(tsd_t *tsd, size_t alignment, size_t usize)
void *p;
prof_tctx_t *tctx;
- tctx = prof_alloc_prep(tsd, usize, true);
+ tctx = prof_alloc_prep(tsd, usize, prof_active_get_unlocked(), true);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
p = imemalign_prof_sample(tsd, alignment, usize, tctx);
else
@@ -1586,7 +1603,7 @@ icalloc_prof(tsd_t *tsd, size_t usize)
void *p;
prof_tctx_t *tctx;
- tctx = prof_alloc_prep(tsd, usize, true);
+ tctx = prof_alloc_prep(tsd, usize, prof_active_get_unlocked(), true);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
p = icalloc_prof_sample(tsd, usize, tctx);
else
@@ -1669,7 +1686,7 @@ label_return:
}
static void *
-irealloc_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize,
+irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
prof_tctx_t *tctx)
{
void *p;
@@ -1677,31 +1694,36 @@ irealloc_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize,
if (tctx == NULL)
return (NULL);
if (usize <= SMALL_MAXCLASS) {
- p = iralloc(tsd, oldptr, old_usize, LARGE_MINCLASS, 0, false);
+ p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false);
if (p == NULL)
return (NULL);
arena_prof_promoted(p, usize);
} else
- p = iralloc(tsd, oldptr, old_usize, usize, 0, false);
+ p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
return (p);
}
JEMALLOC_ALWAYS_INLINE_C void *
-irealloc_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize)
+irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize)
{
void *p;
+ bool prof_active;
prof_tctx_t *old_tctx, *tctx;
- old_tctx = prof_tctx_get(oldptr);
- tctx = prof_alloc_prep(tsd, usize, true);
+ prof_active = prof_active_get_unlocked();
+ old_tctx = prof_tctx_get(old_ptr);
+ tctx = prof_alloc_prep(tsd, usize, prof_active, true);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
- p = irealloc_prof_sample(tsd, oldptr, old_usize, usize, tctx);
+ p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx);
else
- p = iralloc(tsd, oldptr, old_usize, usize, 0, false);
- if (p == NULL)
+ p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
+ if (unlikely(p == NULL)) {
+ prof_alloc_rollback(tsd, tctx, true);
return (NULL);
- prof_realloc(tsd, p, usize, tctx, true, old_usize, old_tctx);
+ }
+ prof_realloc(tsd, p, usize, tctx, prof_active, true, old_ptr, old_usize,
+ old_tctx);
return (p);
}
@@ -1905,6 +1927,7 @@ imallocx_flags_decode_hard(tsd_t *tsd, size_t size, int flags, size_t *usize,
*alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags);
*usize = sa2u(size, *alignment);
}
+ assert(*usize != 0);
*zero = MALLOCX_ZERO_GET(flags);
if ((flags & MALLOCX_TCACHE_MASK) != 0) {
if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE)
@@ -1947,41 +1970,29 @@ imallocx_flags(tsd_t *tsd, size_t usize, size_t alignment, bool zero,
tcache_t *tcache, arena_t *arena)
{
- if (alignment != 0)
+ if (unlikely(alignment != 0))
return (ipalloct(tsd, usize, alignment, zero, tcache, arena));
- if (zero)
+ if (unlikely(zero))
return (icalloct(tsd, usize, tcache, arena));
return (imalloct(tsd, usize, tcache, arena));
}
-JEMALLOC_ALWAYS_INLINE_C void *
-imallocx_maybe_flags(tsd_t *tsd, size_t size, int flags, size_t usize,
- size_t alignment, bool zero, tcache_t *tcache, arena_t *arena)
-{
-
- if (likely(flags == 0))
- return (imalloc(tsd, size));
- return (imallocx_flags(tsd, usize, alignment, zero, tcache, arena));
-}
-
static void *
-imallocx_prof_sample(tsd_t *tsd, size_t size, int flags, size_t usize,
- size_t alignment, bool zero, tcache_t *tcache, arena_t *arena)
+imallocx_prof_sample(tsd_t *tsd, size_t usize, size_t alignment, bool zero,
+ tcache_t *tcache, arena_t *arena)
{
void *p;
if (usize <= SMALL_MAXCLASS) {
assert(((alignment == 0) ? s2u(LARGE_MINCLASS) :
sa2u(LARGE_MINCLASS, alignment)) == LARGE_MINCLASS);
- p = imallocx_maybe_flags(tsd, LARGE_MINCLASS, flags,
- LARGE_MINCLASS, alignment, zero, tcache, arena);
+ p = imallocx_flags(tsd, LARGE_MINCLASS, alignment, zero, tcache,
+ arena);
if (p == NULL)
return (NULL);
arena_prof_promoted(p, usize);
- } else {
- p = imallocx_maybe_flags(tsd, size, flags, usize, alignment,
- zero, tcache, arena);
- }
+ } else
+ p = imallocx_flags(tsd, usize, alignment, zero, tcache, arena);
return (p);
}
@@ -1999,13 +2010,12 @@ imallocx_prof(tsd_t *tsd, size_t size, int flags, size_t *usize)
if (unlikely(imallocx_flags_decode(tsd, size, flags, usize, &alignment,
&zero, &tcache, &arena)))
return (NULL);
- tctx = prof_alloc_prep(tsd, *usize, true);
- if (likely((uintptr_t)tctx == (uintptr_t)1U)) {
- p = imallocx_maybe_flags(tsd, size, flags, *usize, alignment,
- zero, tcache, arena);
- } else if ((uintptr_t)tctx > (uintptr_t)1U) {
- p = imallocx_prof_sample(tsd, size, flags, *usize, alignment,
- zero, tcache, arena);
+ tctx = prof_alloc_prep(tsd, *usize, prof_active_get_unlocked(), true);
+ if (likely((uintptr_t)tctx == (uintptr_t)1U))
+ p = imallocx_flags(tsd, *usize, alignment, zero, tcache, arena);
+ else if ((uintptr_t)tctx > (uintptr_t)1U) {
+ p = imallocx_prof_sample(tsd, *usize, alignment, zero, tcache,
+ arena);
} else
p = NULL;
if (unlikely(p == NULL)) {
@@ -2080,8 +2090,8 @@ label_oom:
}
static void *
-irallocx_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
- size_t alignment, size_t usize, bool zero, tcache_t *tcache, arena_t *arena,
+irallocx_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize,
+ size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
prof_tctx_t *tctx)
{
void *p;
@@ -2089,13 +2099,13 @@ irallocx_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
if (tctx == NULL)
return (NULL);
if (usize <= SMALL_MAXCLASS) {
- p = iralloct(tsd, oldptr, old_usize, LARGE_MINCLASS, alignment,
+ p = iralloct(tsd, old_ptr, old_usize, LARGE_MINCLASS, alignment,
zero, tcache, arena);
if (p == NULL)
return (NULL);
arena_prof_promoted(p, usize);
} else {
- p = iralloct(tsd, oldptr, old_usize, size, alignment, zero,
+ p = iralloct(tsd, old_ptr, old_usize, usize, alignment, zero,
tcache, arena);
}
@@ -2103,28 +2113,30 @@ irallocx_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
}
JEMALLOC_ALWAYS_INLINE_C void *
-irallocx_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
+irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
size_t alignment, size_t *usize, bool zero, tcache_t *tcache,
arena_t *arena)
{
void *p;
+ bool prof_active;
prof_tctx_t *old_tctx, *tctx;
- old_tctx = prof_tctx_get(oldptr);
- tctx = prof_alloc_prep(tsd, *usize, false);
+ prof_active = prof_active_get_unlocked();
+ old_tctx = prof_tctx_get(old_ptr);
+ tctx = prof_alloc_prep(tsd, *usize, prof_active, true);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
- p = irallocx_prof_sample(tsd, oldptr, old_usize, size,
- alignment, *usize, zero, tcache, arena, tctx);
+ p = irallocx_prof_sample(tsd, old_ptr, old_usize, *usize,
+ alignment, zero, tcache, arena, tctx);
} else {
- p = iralloct(tsd, oldptr, old_usize, size, alignment, zero,
+ p = iralloct(tsd, old_ptr, old_usize, size, alignment, zero,
tcache, arena);
}
if (unlikely(p == NULL)) {
- prof_alloc_rollback(tsd, tctx, false);
+ prof_alloc_rollback(tsd, tctx, true);
return (NULL);
}
- if (p == oldptr && alignment != 0) {
+ if (p == old_ptr && alignment != 0) {
/*
* The allocation did not move, so it is possible that the size
* class is smaller than would guarantee the requested
@@ -2135,7 +2147,8 @@ irallocx_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
*/
*usize = isalloc(p, config_prof);
}
- prof_realloc(tsd, p, *usize, tctx, false, old_usize, old_tctx);
+ prof_realloc(tsd, p, *usize, tctx, prof_active, true, old_ptr,
+ old_usize, old_tctx);
return (p);
}
@@ -2230,26 +2243,13 @@ ixallocx_helper(void *ptr, size_t old_usize, size_t size, size_t extra,
static size_t
ixallocx_prof_sample(void *ptr, size_t old_usize, size_t size, size_t extra,
- size_t alignment, size_t max_usize, bool zero, prof_tctx_t *tctx)
+ size_t alignment, bool zero, prof_tctx_t *tctx)
{
size_t usize;
if (tctx == NULL)
return (old_usize);
- /* Use minimum usize to determine whether promotion may happen. */
- if (((alignment == 0) ? s2u(size) : sa2u(size, alignment)) <=
- SMALL_MAXCLASS) {
- if (ixalloc(ptr, old_usize, SMALL_MAXCLASS+1,
- (SMALL_MAXCLASS+1 >= size+extra) ? 0 : size+extra -
- (SMALL_MAXCLASS+1), alignment, zero))
- return (old_usize);
- usize = isalloc(ptr, config_prof);
- if (max_usize < LARGE_MINCLASS)
- arena_prof_promoted(ptr, usize);
- } else {
- usize = ixallocx_helper(ptr, old_usize, size, extra, alignment,
- zero);
- }
+ usize = ixallocx_helper(ptr, old_usize, size, extra, alignment, zero);
return (usize);
}
@@ -2258,9 +2258,11 @@ JEMALLOC_ALWAYS_INLINE_C size_t
ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
size_t extra, size_t alignment, bool zero)
{
- size_t max_usize, usize;
+ size_t usize_max, usize;
+ bool prof_active;
prof_tctx_t *old_tctx, *tctx;
+ prof_active = prof_active_get_unlocked();
old_tctx = prof_tctx_get(ptr);
/*
* usize isn't knowable before ixalloc() returns when extra is non-zero.
@@ -2268,21 +2270,23 @@ ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
* prof_alloc_prep() to decide whether to capture a backtrace.
* prof_realloc() will use the actual usize to decide whether to sample.
*/
- max_usize = (alignment == 0) ? s2u(size+extra) : sa2u(size+extra,
+ usize_max = (alignment == 0) ? s2u(size+extra) : sa2u(size+extra,
alignment);
- tctx = prof_alloc_prep(tsd, max_usize, false);
+ assert(usize_max != 0);
+ tctx = prof_alloc_prep(tsd, usize_max, prof_active, false);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
usize = ixallocx_prof_sample(ptr, old_usize, size, extra,
- alignment, zero, max_usize, tctx);
+ alignment, zero, tctx);
} else {
usize = ixallocx_helper(ptr, old_usize, size, extra, alignment,
zero);
}
- if (unlikely(usize == old_usize)) {
+ if (usize == old_usize) {
prof_alloc_rollback(tsd, tctx, false);
return (usize);
}
- prof_realloc(tsd, ptr, usize, tctx, false, old_usize, old_tctx);
+ prof_realloc(tsd, ptr, usize, tctx, prof_active, false, ptr, old_usize,
+ old_tctx);
return (usize);
}
@@ -2304,6 +2308,17 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags)
tsd = tsd_fetch();
old_usize = isalloc(ptr, config_prof);
+
+ /* Clamp extra if necessary to avoid (size + extra) overflow. */
+ if (unlikely(size + extra > HUGE_MAXCLASS)) {
+ /* Check for size overflow. */
+ if (unlikely(size > HUGE_MAXCLASS)) {
+ usize = old_usize;
+ goto label_not_resized;
+ }
+ extra = HUGE_MAXCLASS - size;
+ }
+
if (config_valgrind && unlikely(in_valgrind))
old_rzsize = u2rz(old_usize);
OpenPOWER on IntegriCloud