diff options
author | Jason Evans <je@facebook.com> | 2010-04-14 18:27:13 (GMT) |
---|---|---|
committer | Jason Evans <je@facebook.com> | 2010-04-14 18:27:13 (GMT) |
commit | 5055f4516c8852e67668b0e746863a7d6a1c148e (patch) | |
tree | 0199eb3067af365c1c5268a49cf4b76d7efd2e15 /jemalloc | |
parent | 38cda690ddd6c9db0321b06abaa4d19f884326b6 (diff) | |
download | jemalloc-5055f4516c8852e67668b0e746863a7d6a1c148e.zip jemalloc-5055f4516c8852e67668b0e746863a7d6a1c148e.tar.gz jemalloc-5055f4516c8852e67668b0e746863a7d6a1c148e.tar.bz2 |
Fix tcache crash during thread cleanup.
Properly maintain tcache_bin_t's avail pointer such that it is NULL if
no objects are cached. This only caused problems during thread cache
destruction, since cache flushing otherwise never occurs on an empty
bin.
Diffstat (limited to 'jemalloc')
-rw-r--r-- | jemalloc/src/tcache.c | 26 |
1 files changed, 12 insertions, 14 deletions
diff --git a/jemalloc/src/tcache.c b/jemalloc/src/tcache.c index ce6ec99..ace24ce 100644 --- a/jemalloc/src/tcache.c +++ b/jemalloc/src/tcache.c @@ -55,12 +55,14 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem { void *flush, *deferred, *ptr; unsigned i, nflush, ndeferred; + bool first_pass; assert(binind < nbins); assert(rem <= tbin->ncached); + assert(tbin->ncached > 0 || tbin->avail == NULL); - for (flush = tbin->avail, nflush = tbin->ncached - rem; flush != NULL; - flush = deferred, nflush = ndeferred) { + for (flush = tbin->avail, nflush = tbin->ncached - rem, first_pass = + true; flush != NULL; flush = deferred, nflush = ndeferred) { /* Lock the arena bin associated with the first object. */ arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(flush); arena_t *arena = chunk->arena; @@ -110,12 +112,9 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem } malloc_mutex_unlock(&bin->lock); - if (flush != NULL) { - /* - * This was the first pass, and rem cached objects - * remain. - */ + if (first_pass) { tbin->avail = flush; + first_pass = false; } } @@ -133,12 +132,14 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem { void *flush, *deferred, *ptr; unsigned i, nflush, ndeferred; + bool first_pass; assert(binind < nhbins); assert(rem <= tbin->ncached); + assert(tbin->ncached > 0 || tbin->avail == NULL); - for (flush = tbin->avail, nflush = tbin->ncached - rem; flush != NULL; - flush = deferred, nflush = ndeferred) { + for (flush = tbin->avail, nflush = tbin->ncached - rem, first_pass = + true; flush != NULL; flush = deferred, nflush = ndeferred) { /* Lock the arena associated with the first object. */ arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(flush); arena_t *arena = chunk->arena; @@ -183,12 +184,9 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem } malloc_mutex_unlock(&arena->lock); - if (flush != NULL) { - /* - * This was the first pass, and rem cached objects - * remain. - */ + if (first_pass) { tbin->avail = flush; + first_pass = false; } } |