Drop high rank locks when creating threads.

Avoid holding arenas_lock and background_thread_lock when creating background
threads, because pthread_create may take internal locks, and potentially cause
deadlock with jemalloc internal locks.
This commit is contained in:
Qi Wang 2017-06-07 15:49:09 -07:00 committed by Qi Wang
parent 00869e39a3
commit 73713fbb27
5 changed files with 43 additions and 13 deletions

View File

@ -15,6 +15,7 @@ extern percpu_arena_mode_t opt_percpu_arena;
extern const char *percpu_arena_mode_names[]; extern const char *percpu_arena_mode_names[];
extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS]; extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS];
extern malloc_mutex_t arenas_lock;
void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
szind_t szind, uint64_t nrequests); szind_t szind, uint64_t nrequests);

View File

@ -2050,17 +2050,6 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
hooks_arena_new_hook(); hooks_arena_new_hook();
} }
post_reentrancy(tsdn_tsd(tsdn)); post_reentrancy(tsdn_tsd(tsdn));
/* background_thread_create() handles reentrancy internally. */
if (have_background_thread) {
bool err;
malloc_mutex_lock(tsdn, &background_thread_lock);
err = background_thread_create(tsdn_tsd(tsdn), ind);
malloc_mutex_unlock(tsdn, &background_thread_lock);
if (err) {
goto label_error;
}
}
} }
return arena; return arena;

View File

@ -352,12 +352,15 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) {
} }
pre_reentrancy(tsd); pre_reentrancy(tsd);
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
/* /*
* To avoid complications (besides reentrancy), create internal * To avoid complications (besides reentrancy), create internal
* background threads with the underlying pthread_create. * background threads with the underlying pthread_create, and drop
* background_thread_lock (pthread_create may take internal locks).
*/ */
int err = pthread_create_wrapper(&info->thread, NULL, int err = pthread_create_wrapper(&info->thread, NULL,
background_thread_entry, (void *)thread_ind); background_thread_entry, (void *)thread_ind);
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
post_reentrancy(tsd); post_reentrancy(tsd);
if (err != 0) { if (err != 0) {

View File

@ -1501,6 +1501,7 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
} }
background_thread_ctl_init(tsd_tsdn(tsd)); background_thread_ctl_init(tsd_tsdn(tsd));
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
if (newp == NULL) { if (newp == NULL) {
oldval = background_thread_enabled(); oldval = background_thread_enabled();
@ -1535,6 +1536,8 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
ret = 0; ret = 0;
label_return: label_return:
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
return ret; return ret;
} }

View File

@ -70,7 +70,7 @@ unsigned opt_narenas = 0;
unsigned ncpus; unsigned ncpus;
/* Protects arenas initialization. */ /* Protects arenas initialization. */
static malloc_mutex_t arenas_lock; malloc_mutex_t arenas_lock;
/* /*
* Arenas that are used to service external requests. Not all elements of the * Arenas that are used to service external requests. Not all elements of the
* arenas array are necessarily used; arenas are created lazily as needed. * arenas array are necessarily used; arenas are created lazily as needed.
@ -335,6 +335,25 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
return arena; return arena;
} }
static void
arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) {
if (ind == 0) {
return;
}
/* background_thread_create() handles reentrancy internally. */
if (have_background_thread) {
bool err;
malloc_mutex_lock(tsdn, &background_thread_lock);
err = background_thread_create(tsdn_tsd(tsdn), ind);
malloc_mutex_unlock(tsdn, &background_thread_lock);
if (err) {
malloc_printf("<jemalloc>: error in background thread "
"creation for arena %u. Abort.\n", ind);
abort();
}
}
}
arena_t * arena_t *
arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
arena_t *arena; arena_t *arena;
@ -342,6 +361,9 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
malloc_mutex_lock(tsdn, &arenas_lock); malloc_mutex_lock(tsdn, &arenas_lock);
arena = arena_init_locked(tsdn, ind, extent_hooks); arena = arena_init_locked(tsdn, ind, extent_hooks);
malloc_mutex_unlock(tsdn, &arenas_lock); malloc_mutex_unlock(tsdn, &arenas_lock);
arena_new_create_background_thread(tsdn, ind);
return arena; return arena;
} }
@ -475,6 +497,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) {
if (narenas_auto > 1) { if (narenas_auto > 1) {
unsigned i, j, choose[2], first_null; unsigned i, j, choose[2], first_null;
bool is_new_arena[2];
/* /*
* Determine binding for both non-internal and internal * Determine binding for both non-internal and internal
@ -486,6 +509,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) {
for (j = 0; j < 2; j++) { for (j = 0; j < 2; j++) {
choose[j] = 0; choose[j] = 0;
is_new_arena[j] = false;
} }
first_null = narenas_auto; first_null = narenas_auto;
@ -545,6 +569,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) {
&arenas_lock); &arenas_lock);
return NULL; return NULL;
} }
is_new_arena[j] = true;
if (!!j == internal) { if (!!j == internal) {
ret = arena; ret = arena;
} }
@ -552,6 +577,15 @@ arena_choose_hard(tsd_t *tsd, bool internal) {
arena_bind(tsd, choose[j], !!j); arena_bind(tsd, choose[j], !!j);
} }
malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock); malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock);
for (j = 0; j < 2; j++) {
if (is_new_arena[j]) {
assert(choose[j] > 0);
arena_new_create_background_thread(
tsd_tsdn(tsd), choose[j]);
}
}
} else { } else {
ret = arena_get(tsd_tsdn(tsd), 0, false); ret = arena_get(tsd_tsdn(tsd), 0, false);
arena_bind(tsd, 0, false); arena_bind(tsd, 0, false);