Skip to content

Commit b83b5ad

Browse files
committed
Not re-enable background thread after fork.
Avoid calling pthread_create in postfork handlers.
1 parent 464cb60 commit b83b5ad

File tree

3 files changed

+50
-37
lines changed

3 files changed

+50
-37
lines changed

doc/jemalloc.xml.in

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,10 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
750750
background threads will be no more than the number of CPUs or active
751751
arenas). Threads run periodically, and handle <link
752752
linkend="arena.i.decay">purging</link> asynchronously. When switching
753-
off, background threads are terminated synchronously. See <link
753+
off, background threads are terminated synchronously. Note that after
754+
<citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry>
755+
function, the state in the child process will be disabled regardless
756+
the state in parent process. See <link
754757
linkend="stats.background_thread.num_threads"><mallctl>stats.background_thread</mallctl></link>
755758
for related stats. <link
756759
linkend="opt.background_thread"><mallctl>opt.background_thread</mallctl></link>

src/background_thread.c

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -350,24 +350,38 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created,
350350
}
351351
background_thread_info_t *info = &background_thread_info[i];
352352
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
353-
if (info->started) {
354-
pre_reentrancy(tsd);
355-
int err = pthread_create_wrapper(&info->thread, NULL,
356-
background_thread_entry, (void *)(uintptr_t)i);
357-
post_reentrancy(tsd);
358-
359-
if (err == 0) {
360-
(*n_created)++;
361-
created_threads[i] = true;
362-
} else {
363-
malloc_printf("<jemalloc>: background thread "
364-
"creation failed (%d)\n", err);
365-
if (opt_abort) {
366-
abort();
367-
}
353+
354+
bool create = info->started;
355+
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
356+
if (!create) {
357+
continue;
358+
}
359+
360+
/*
361+
* To avoid deadlock with prefork handlers (which waits for the
362+
* mutex held here), unlock before calling pthread_create().
363+
*/
364+
malloc_mutex_unlock(tsd_tsdn(tsd),
365+
&background_thread_info[0].mtx);
366+
pre_reentrancy(tsd);
367+
int err = pthread_create_wrapper(&info->thread, NULL,
368+
background_thread_entry, (void *)(uintptr_t)i);
369+
post_reentrancy(tsd);
370+
malloc_mutex_lock(tsd_tsdn(tsd),
371+
&background_thread_info[0].mtx);
372+
373+
if (err == 0) {
374+
(*n_created)++;
375+
created_threads[i] = true;
376+
} else {
377+
malloc_printf("<jemalloc>: background thread "
378+
"creation failed (%d)\n", err);
379+
if (opt_abort) {
380+
abort();
368381
}
369382
}
370-
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
383+
/* Since we unlocked and may miss signals, restart. */
384+
i = 1;
371385
}
372386
}
373387

@@ -643,14 +657,7 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena,
643657
void
644658
background_thread_prefork0(tsdn_t *tsdn) {
645659
malloc_mutex_prefork(tsdn, &background_thread_lock);
646-
if (background_thread_enabled()) {
647-
background_thread_enabled_at_fork = true;
648-
background_thread_enabled_set(tsdn, false);
649-
background_threads_disable(tsdn_tsd(tsdn));
650-
} else {
651-
background_thread_enabled_at_fork = false;
652-
}
653-
assert(n_background_threads == 0);
660+
background_thread_enabled_at_fork = background_thread_enabled();
654661
}
655662

656663
void
@@ -660,22 +667,12 @@ background_thread_prefork1(tsdn_t *tsdn) {
660667
}
661668
}
662669

663-
static void
664-
background_thread_postfork_init(tsdn_t *tsdn) {
665-
assert(n_background_threads == 0);
666-
if (background_thread_enabled_at_fork) {
667-
background_thread_enabled_set(tsdn, true);
668-
background_threads_enable(tsdn_tsd(tsdn));
669-
}
670-
}
671-
672670
void
673671
background_thread_postfork_parent(tsdn_t *tsdn) {
674672
for (unsigned i = 0; i < ncpus; i++) {
675673
malloc_mutex_postfork_parent(tsdn,
676674
&background_thread_info[i].mtx);
677675
}
678-
background_thread_postfork_init(tsdn);
679676
malloc_mutex_postfork_parent(tsdn, &background_thread_lock);
680677
}
681678

@@ -686,9 +683,23 @@ background_thread_postfork_child(tsdn_t *tsdn) {
686683
&background_thread_info[i].mtx);
687684
}
688685
malloc_mutex_postfork_child(tsdn, &background_thread_lock);
686+
if (!background_thread_enabled_at_fork) {
687+
return;
688+
}
689689

690+
/* Clear background_thread state (reset to disabled for child). */
690691
malloc_mutex_lock(tsdn, &background_thread_lock);
691-
background_thread_postfork_init(tsdn);
692+
n_background_threads = 0;
693+
background_thread_enabled_set(tsdn, false);
694+
for (unsigned i = 0; i < ncpus; i++) {
695+
background_thread_info_t *info = &background_thread_info[i];
696+
malloc_mutex_lock(tsdn, &info->mtx);
697+
info->started = false;
698+
int ret = pthread_cond_init(&info->cond, NULL);
699+
assert(ret == 0);
700+
background_thread_info_init(tsdn, info);
701+
malloc_mutex_unlock(tsdn, &info->mtx);
702+
}
692703
malloc_mutex_unlock(tsdn, &background_thread_lock);
693704
}
694705

src/jemalloc.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,6 @@ arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) {
340340
if (ind == 0) {
341341
return;
342342
}
343-
/* background_thread_create() handles reentrancy internally. */
344343
if (have_background_thread) {
345344
bool err;
346345
malloc_mutex_lock(tsdn, &background_thread_lock);

0 commit comments

Comments
 (0)