Fix fork()-related lock rank ordering reversals.

This commit is contained in:
Jason Evans 2016-04-25 23:14:40 -07:00
parent de35328a10
commit 2687a72087
8 changed files with 139 additions and 39 deletions

View File

@ -138,6 +138,7 @@ TESTS_UNIT := $(srcroot)test/unit/atomic.c \
$(srcroot)test/unit/bitmap.c \
$(srcroot)test/unit/ckh.c \
$(srcroot)test/unit/decay.c \
$(srcroot)test/unit/fork.c \
$(srcroot)test/unit/hash.c \
$(srcroot)test/unit/junk.c \
$(srcroot)test/unit/junk_alloc.c \

View File

@ -584,7 +584,10 @@ void arena_nthreads_inc(arena_t *arena);
void arena_nthreads_dec(arena_t *arena);
arena_t *arena_new(unsigned ind);
bool arena_boot(void);
void arena_prefork(arena_t *arena);
void arena_prefork0(arena_t *arena);
void arena_prefork1(arena_t *arena);
void arena_prefork2(arena_t *arena);
void arena_prefork3(arena_t *arena);
void arena_postfork_parent(arena_t *arena);
void arena_postfork_child(arena_t *arena);

View File

@ -81,7 +81,10 @@ arena_nthreads_inc
arena_palloc
arena_postfork_child
arena_postfork_parent
arena_prefork
arena_prefork0
arena_prefork1
arena_prefork2
arena_prefork3
arena_prof_accum
arena_prof_accum_impl
arena_prof_accum_locked
@ -408,7 +411,8 @@ prof_malloc_sample_object
prof_mdump
prof_postfork_child
prof_postfork_parent
prof_prefork
prof_prefork0
prof_prefork1
prof_realloc
prof_reset
prof_sample_accum_update

View File

@ -316,7 +316,8 @@ bool prof_gdump_set(bool active);
void prof_boot0(void);
void prof_boot1(void);
bool prof_boot2(void);
void prof_prefork(void);
void prof_prefork0(void);
void prof_prefork1(void);
void prof_postfork_parent(void);
void prof_postfork_child(void);
void prof_sample_threshold_update(prof_tdata_t *tdata);

View File

@ -3646,16 +3646,34 @@ arena_boot(void)
}
void
arena_prefork(arena_t *arena)
arena_prefork0(arena_t *arena)
{
malloc_mutex_prefork(&arena->lock);
}
void
arena_prefork1(arena_t *arena)
{
malloc_mutex_prefork(&arena->chunks_mtx);
}
void
arena_prefork2(arena_t *arena)
{
malloc_mutex_prefork(&arena->node_cache_mtx);
}
void
arena_prefork3(arena_t *arena)
{
unsigned i;
malloc_mutex_prefork(&arena->lock);
malloc_mutex_prefork(&arena->huge_mtx);
malloc_mutex_prefork(&arena->chunks_mtx);
malloc_mutex_prefork(&arena->node_cache_mtx);
for (i = 0; i < NBINS; i++)
malloc_mutex_prefork(&arena->bins[i].lock);
malloc_mutex_prefork(&arena->huge_mtx);
}
void
@ -3663,11 +3681,11 @@ arena_postfork_parent(arena_t *arena)
{
unsigned i;
malloc_mutex_postfork_parent(&arena->huge_mtx);
for (i = 0; i < NBINS; i++)
malloc_mutex_postfork_parent(&arena->bins[i].lock);
malloc_mutex_postfork_parent(&arena->node_cache_mtx);
malloc_mutex_postfork_parent(&arena->chunks_mtx);
malloc_mutex_postfork_parent(&arena->huge_mtx);
malloc_mutex_postfork_parent(&arena->lock);
}
@ -3676,10 +3694,10 @@ arena_postfork_child(arena_t *arena)
{
unsigned i;
malloc_mutex_postfork_child(&arena->huge_mtx);
for (i = 0; i < NBINS; i++)
malloc_mutex_postfork_child(&arena->bins[i].lock);
malloc_mutex_postfork_child(&arena->node_cache_mtx);
malloc_mutex_postfork_child(&arena->chunks_mtx);
malloc_mutex_postfork_child(&arena->huge_mtx);
malloc_mutex_postfork_child(&arena->lock);
}

View File

@ -2644,7 +2644,8 @@ JEMALLOC_EXPORT void
_malloc_prefork(void)
#endif
{
unsigned i, narenas;
unsigned i, j, narenas;
arena_t *arena;
#ifdef JEMALLOC_MUTEX_INIT_CB
if (!malloc_initialized())
@ -2652,18 +2653,31 @@ _malloc_prefork(void)
#endif
assert(malloc_initialized());
narenas = narenas_total_get();
/* Acquire all mutexes in a safe order. */
ctl_prefork();
prof_prefork();
malloc_mutex_prefork(&arenas_lock);
for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
arena_t *arena;
if ((arena = arena_get(i, false)) != NULL)
arena_prefork(arena);
prof_prefork0();
for (i = 0; i < 3; i++) {
for (j = 0; j < narenas; j++) {
if ((arena = arena_get(j, false)) != NULL) {
switch (i) {
case 0: arena_prefork0(arena); break;
case 1: arena_prefork1(arena); break;
case 2: arena_prefork2(arena); break;
default: not_reached();
}
}
}
}
chunk_prefork();
base_prefork();
chunk_prefork();
for (i = 0; i < narenas; i++) {
if ((arena = arena_get(i, false)) != NULL)
arena_prefork3(arena);
}
prof_prefork1();
}
#ifndef JEMALLOC_MUTEX_INIT_CB
@ -2683,16 +2697,16 @@ _malloc_postfork(void)
assert(malloc_initialized());
/* Release all mutexes, now that fork() has completed. */
base_postfork_parent();
chunk_postfork_parent();
base_postfork_parent();
for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
arena_t *arena;
if ((arena = arena_get(i, false)) != NULL)
arena_postfork_parent(arena);
}
malloc_mutex_postfork_parent(&arenas_lock);
prof_postfork_parent();
malloc_mutex_postfork_parent(&arenas_lock);
ctl_postfork_parent();
}
@ -2704,16 +2718,16 @@ jemalloc_postfork_child(void)
assert(malloc_initialized());
/* Release all mutexes, now that fork() has completed. */
base_postfork_child();
chunk_postfork_child();
base_postfork_child();
for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
arena_t *arena;
if ((arena = arena_get(i, false)) != NULL)
arena_postfork_child(arena);
}
malloc_mutex_postfork_child(&arenas_lock);
prof_postfork_child();
malloc_mutex_postfork_child(&arenas_lock);
ctl_postfork_child();
}

View File

@ -2198,20 +2198,32 @@ prof_boot2(void)
}
void
prof_prefork(void)
prof_prefork0(void)
{
if (opt_prof) {
unsigned i;
malloc_mutex_prefork(&tdatas_mtx);
malloc_mutex_prefork(&prof_dump_mtx);
malloc_mutex_prefork(&bt2gctx_mtx);
malloc_mutex_prefork(&next_thr_uid_mtx);
malloc_mutex_prefork(&prof_dump_seq_mtx);
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_prefork(&gctx_locks[i]);
malloc_mutex_prefork(&tdatas_mtx);
for (i = 0; i < PROF_NTDATA_LOCKS; i++)
malloc_mutex_prefork(&tdata_locks[i]);
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_prefork(&gctx_locks[i]);
}
}
void
prof_prefork1(void)
{
if (opt_prof) {
malloc_mutex_prefork(&prof_active_mtx);
malloc_mutex_prefork(&prof_dump_seq_mtx);
malloc_mutex_prefork(&prof_gdump_mtx);
malloc_mutex_prefork(&next_thr_uid_mtx);
malloc_mutex_prefork(&prof_thread_active_init_mtx);
}
}
@ -2222,14 +2234,18 @@ prof_postfork_parent(void)
if (opt_prof) {
unsigned i;
for (i = 0; i < PROF_NTDATA_LOCKS; i++)
malloc_mutex_postfork_parent(&tdata_locks[i]);
malloc_mutex_postfork_parent(&prof_thread_active_init_mtx);
malloc_mutex_postfork_parent(&next_thr_uid_mtx);
malloc_mutex_postfork_parent(&prof_gdump_mtx);
malloc_mutex_postfork_parent(&prof_dump_seq_mtx);
malloc_mutex_postfork_parent(&prof_active_mtx);
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_postfork_parent(&gctx_locks[i]);
malloc_mutex_postfork_parent(&prof_dump_seq_mtx);
malloc_mutex_postfork_parent(&next_thr_uid_mtx);
malloc_mutex_postfork_parent(&bt2gctx_mtx);
for (i = 0; i < PROF_NTDATA_LOCKS; i++)
malloc_mutex_postfork_parent(&tdata_locks[i]);
malloc_mutex_postfork_parent(&tdatas_mtx);
malloc_mutex_postfork_parent(&bt2gctx_mtx);
malloc_mutex_postfork_parent(&prof_dump_mtx);
}
}
@ -2240,14 +2256,18 @@ prof_postfork_child(void)
if (opt_prof) {
unsigned i;
for (i = 0; i < PROF_NTDATA_LOCKS; i++)
malloc_mutex_postfork_child(&tdata_locks[i]);
malloc_mutex_postfork_child(&prof_thread_active_init_mtx);
malloc_mutex_postfork_child(&next_thr_uid_mtx);
malloc_mutex_postfork_child(&prof_gdump_mtx);
malloc_mutex_postfork_child(&prof_dump_seq_mtx);
malloc_mutex_postfork_child(&prof_active_mtx);
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_postfork_child(&gctx_locks[i]);
malloc_mutex_postfork_child(&prof_dump_seq_mtx);
malloc_mutex_postfork_child(&next_thr_uid_mtx);
malloc_mutex_postfork_child(&bt2gctx_mtx);
for (i = 0; i < PROF_NTDATA_LOCKS; i++)
malloc_mutex_postfork_child(&tdata_locks[i]);
malloc_mutex_postfork_child(&tdatas_mtx);
malloc_mutex_postfork_child(&bt2gctx_mtx);
malloc_mutex_postfork_child(&prof_dump_mtx);
}
}

39
test/unit/fork.c Normal file
View File

@ -0,0 +1,39 @@
#include "test/jemalloc_test.h"
#include <sys/wait.h>
TEST_BEGIN(test_fork)
{
void *p;
pid_t pid;
p = malloc(1);
assert_ptr_not_null(p, "Unexpected malloc() failure");
pid = fork();
if (pid == -1) {
/* Error. */
test_fail("Unexpected fork() failure");
} else if (pid == 0) {
/* Child. */
exit(0);
} else {
int status;
/* Parent. */
free(p);
do {
if (waitpid(pid, &status, 0) == -1)
test_fail("Unexpected waitpid() failure");
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}
TEST_END
int
main(void)
{
return (test(
test_fork));
}