summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Evans <jasone@canonware.com>2016-04-26 06:14:40 (GMT)
committerJason Evans <jasone@canonware.com>2016-05-03 17:28:25 (GMT)
commit2687a720870edeae4c8dae71a82c98a7509fcc8e (patch)
treed5bbbabc037571a8f8a53d5b68cd4b7336ee05ec
parentde35328a101f18adc474a7c2d476f963fa02764b (diff)
downloadjemalloc-2687a720870edeae4c8dae71a82c98a7509fcc8e.zip
jemalloc-2687a720870edeae4c8dae71a82c98a7509fcc8e.tar.gz
jemalloc-2687a720870edeae4c8dae71a82c98a7509fcc8e.tar.bz2
Fix fork()-related lock rank ordering reversals.
-rw-r--r--Makefile.in1
-rw-r--r--include/jemalloc/internal/arena.h5
-rw-r--r--include/jemalloc/internal/private_symbols.txt8
-rw-r--r--include/jemalloc/internal/prof.h3
-rw-r--r--src/arena.c28
-rw-r--r--src/jemalloc.c38
-rw-r--r--src/prof.c52
-rw-r--r--test/unit/fork.c39
8 files changed, 137 insertions, 37 deletions
diff --git a/Makefile.in b/Makefile.in
index f60823f..4b0e184 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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 \
diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h
index 3519873..42a7896 100644
--- a/include/jemalloc/internal/arena.h
+++ b/include/jemalloc/internal/arena.h
@@ -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);
diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt
index 5fcc669..fafee81 100644
--- a/include/jemalloc/internal/private_symbols.txt
+++ b/include/jemalloc/internal/private_symbols.txt
@@ -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
diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h
index a25502a..48dd6cc 100644
--- a/include/jemalloc/internal/prof.h
+++ b/include/jemalloc/internal/prof.h
@@ -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);
diff --git a/src/arena.c b/src/arena.c
index b7645d8..48e9b20 100644
--- a/src/arena.c
+++ b/src/arena.c
@@ -3646,16 +3646,34 @@ arena_boot(void)
}
void
-arena_prefork(arena_t *arena)
+arena_prefork0(arena_t *arena)
{
- unsigned i;
malloc_mutex_prefork(&arena->lock);
- malloc_mutex_prefork(&arena->huge_mtx);
+}
+
+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;
+
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);
}
diff --git a/src/jemalloc.c b/src/jemalloc.c
index 0735376..7120791 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -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();
}
diff --git a/src/prof.c b/src/prof.c
index b387227..a92320d 100644
--- a/src/prof.c
+++ b/src/prof.c
@@ -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);
}
}
diff --git a/test/unit/fork.c b/test/unit/fork.c
new file mode 100644
index 0000000..890bc86
--- /dev/null
+++ b/test/unit/fork.c
@@ -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));
+}