Fix witness/fork() interactions.

Fix witness to clear its list of owned mutexes in the child if
platform-specific malloc_mutex code re-initializes mutexes rather than
unlocking them.
This commit is contained in:
Jason Evans 2016-04-26 10:47:22 -07:00
parent 174c0c3a9c
commit 108c4a11e9
5 changed files with 42 additions and 9 deletions

View File

@ -594,7 +594,8 @@ witness_lock_error
witness_lockless_error witness_lockless_error
witness_not_owner_error witness_not_owner_error
witness_owner_error witness_owner_error
witness_postfork witness_postfork_child
witness_postfork_parent
witness_prefork witness_prefork
witness_unlock witness_unlock
witnesses_cleanup witnesses_cleanup

View File

@ -96,7 +96,8 @@ void witness_assert_lockless(tsd_t *tsd);
void witnesses_cleanup(tsd_t *tsd); void witnesses_cleanup(tsd_t *tsd);
void witness_fork_cleanup(tsd_t *tsd); void witness_fork_cleanup(tsd_t *tsd);
void witness_prefork(tsd_t *tsd); void witness_prefork(tsd_t *tsd);
void witness_postfork(tsd_t *tsd); void witness_postfork_parent(tsd_t *tsd);
void witness_postfork_child(tsd_t *tsd);
#endif /* JEMALLOC_H_EXTERNS */ #endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/ /******************************************************************************/

View File

@ -2770,8 +2770,8 @@ _malloc_prefork(void)
narenas = narenas_total_get(); narenas = narenas_total_get();
/* Acquire all mutexes in a safe order. */
witness_prefork(tsd); witness_prefork(tsd);
/* Acquire all mutexes in a safe order. */
ctl_prefork(tsd); ctl_prefork(tsd);
malloc_mutex_prefork(tsd, &arenas_lock); malloc_mutex_prefork(tsd, &arenas_lock);
prof_prefork0(tsd); prof_prefork0(tsd);
@ -2815,6 +2815,7 @@ _malloc_postfork(void)
tsd = tsd_fetch(); tsd = tsd_fetch();
witness_postfork_parent(tsd);
/* Release all mutexes, now that fork() has completed. */ /* Release all mutexes, now that fork() has completed. */
chunk_postfork_parent(tsd); chunk_postfork_parent(tsd);
base_postfork_parent(tsd); base_postfork_parent(tsd);
@ -2827,7 +2828,6 @@ _malloc_postfork(void)
prof_postfork_parent(tsd); prof_postfork_parent(tsd);
malloc_mutex_postfork_parent(tsd, &arenas_lock); malloc_mutex_postfork_parent(tsd, &arenas_lock);
ctl_postfork_parent(tsd); ctl_postfork_parent(tsd);
witness_postfork(tsd);
} }
void void
@ -2840,6 +2840,7 @@ jemalloc_postfork_child(void)
tsd = tsd_fetch(); tsd = tsd_fetch();
witness_postfork_child(tsd);
/* Release all mutexes, now that fork() has completed. */ /* Release all mutexes, now that fork() has completed. */
chunk_postfork_child(tsd); chunk_postfork_child(tsd);
base_postfork_child(tsd); base_postfork_child(tsd);
@ -2852,7 +2853,6 @@ jemalloc_postfork_child(void)
prof_postfork_child(tsd); prof_postfork_child(tsd);
malloc_mutex_postfork_child(tsd, &arenas_lock); malloc_mutex_postfork_child(tsd, &arenas_lock);
ctl_postfork_child(tsd); ctl_postfork_child(tsd);
witness_postfork(tsd);
} }
/******************************************************************************/ /******************************************************************************/

View File

@ -222,8 +222,20 @@ witness_prefork(tsd_t *tsd)
} }
void void
witness_postfork(tsd_t *tsd) witness_postfork_parent(tsd_t *tsd)
{ {
tsd_witness_fork_set(tsd, false); tsd_witness_fork_set(tsd, false);
} }
void
witness_postfork_child(tsd_t *tsd)
{
#ifndef JEMALLOC_MUTEX_INIT_CB
witness_list_t *witnesses;
witnesses = tsd_witnessesp_get(tsd);
ql_new(witnesses);
#endif
tsd_witness_fork_set(tsd, false);
}

View File

@ -11,6 +11,13 @@ TEST_BEGIN(test_fork)
assert_ptr_not_null(p, "Unexpected malloc() failure"); assert_ptr_not_null(p, "Unexpected malloc() failure");
pid = fork(); pid = fork();
free(p);
p = malloc(64);
assert_ptr_not_null(p, "Unexpected malloc() failure");
free(p);
if (pid == -1) { if (pid == -1) {
/* Error. */ /* Error. */
test_fail("Unexpected fork() failure"); test_fail("Unexpected fork() failure");
@ -21,11 +28,23 @@ TEST_BEGIN(test_fork)
int status; int status;
/* Parent. */ /* Parent. */
free(p); while (true) {
do {
if (waitpid(pid, &status, 0) == -1) if (waitpid(pid, &status, 0) == -1)
test_fail("Unexpected waitpid() failure"); test_fail("Unexpected waitpid() failure");
} while (!WIFEXITED(status) && !WIFSIGNALED(status)); if (WIFSIGNALED(status)) {
test_fail("Unexpected child termination due to "
"signal %d", WTERMSIG(status));
break;
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
test_fail(
"Unexpected child exit value %d",
WEXITSTATUS(status));
}
break;
}
}
} }
} }
TEST_END TEST_END