Skip to content

Commit 394df95

Browse files
committed
Combine background_thread started / paused into state.
1 parent b83b5ad commit 394df95

File tree

4 files changed

+59
-34
lines changed

4 files changed

+59
-34
lines changed

include/jemalloc/internal/background_thread_structs.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,21 @@
99

1010
#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX
1111

12+
typedef enum {
13+
background_thread_stopped,
14+
background_thread_started,
15+
/* Thread waits on the global lock when paused (for arena_reset). */
16+
background_thread_paused,
17+
} background_thread_state_t;
18+
1219
struct background_thread_info_s {
1320
#ifdef JEMALLOC_BACKGROUND_THREAD
1421
/* Background thread is pthread specific. */
1522
pthread_t thread;
1623
pthread_cond_t cond;
1724
#endif
1825
malloc_mutex_t mtx;
19-
/* Whether the thread has been created. */
20-
bool started;
21-
/* Pause execution (for arena reset / destroy). */
22-
bool pause;
26+
background_thread_state_t state;
2327
/* When true, it means no wakeup scheduled. */
2428
atomic_b_t indefinite_sleep;
2529
/* Next scheduled wakeup time (absolute time in ns). */

src/background_thread.c

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ static bool background_thread_enabled_at_fork;
6767
static void
6868
background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) {
6969
background_thread_wakeup_time_set(tsdn, info, 0);
70-
info->pause = false;
7170
info->npages_to_purge_new = 0;
7271
if (config_stats) {
7372
info->tot_n_runs = 0;
@@ -263,13 +262,20 @@ background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info,
263262
nstime_add(&info->tot_sleep_time, &after_sleep);
264263
}
265264
}
266-
while (info->pause) {
265+
}
266+
267+
static bool
268+
background_thread_pause_check(tsdn_t *tsdn, background_thread_info_t *info) {
269+
if (unlikely(info->state == background_thread_paused)) {
267270
malloc_mutex_unlock(tsdn, &info->mtx);
268271
/* Wait on global lock to update status. */
269272
malloc_mutex_lock(tsdn, &background_thread_lock);
270273
malloc_mutex_unlock(tsdn, &background_thread_lock);
271274
malloc_mutex_lock(tsdn, &info->mtx);
275+
return true;
272276
}
277+
278+
return false;
273279
}
274280

275281
static inline void
@@ -310,9 +316,10 @@ background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) {
310316
pre_reentrancy(tsd);
311317
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
312318
bool has_thread;
313-
if (info->started) {
319+
assert(info->state != background_thread_paused);
320+
if (info->state == background_thread_started) {
314321
has_thread = true;
315-
info->started = false;
322+
info->state = background_thread_stopped;
316323
pthread_cond_signal(&info->cond);
317324
} else {
318325
has_thread = false;
@@ -344,14 +351,17 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created,
344351
return;
345352
}
346353

354+
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_info[0].mtx);
355+
label_restart:
356+
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
347357
for (unsigned i = 1; i < ncpus; i++) {
348358
if (created_threads[i]) {
349359
continue;
350360
}
351361
background_thread_info_t *info = &background_thread_info[i];
352362
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
353-
354-
bool create = info->started;
363+
assert(info->state != background_thread_paused);
364+
bool create = (info->state == background_thread_started);
355365
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
356366
if (!create) {
357367
continue;
@@ -361,14 +371,12 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created,
361371
* To avoid deadlock with prefork handlers (which waits for the
362372
* mutex held here), unlock before calling pthread_create().
363373
*/
364-
malloc_mutex_unlock(tsd_tsdn(tsd),
365-
&background_thread_info[0].mtx);
374+
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
375+
366376
pre_reentrancy(tsd);
367377
int err = pthread_create_wrapper(&info->thread, NULL,
368378
background_thread_entry, (void *)(uintptr_t)i);
369379
post_reentrancy(tsd);
370-
malloc_mutex_lock(tsd_tsdn(tsd),
371-
&background_thread_info[0].mtx);
372380

373381
if (err == 0) {
374382
(*n_created)++;
@@ -380,9 +388,11 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created,
380388
abort();
381389
}
382390
}
383-
/* Since we unlocked and may miss signals, restart. */
384-
i = 1;
391+
/* Restart since we unlocked. */
392+
goto label_restart;
385393
}
394+
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_info[0].mtx);
395+
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
386396
}
387397

388398
static void
@@ -395,7 +405,11 @@ background_thread0_work(tsd_t *tsd) {
395405
}
396406
/* Start working, and create more threads when asked. */
397407
unsigned n_created = 1;
398-
while (background_thread_info[0].started) {
408+
while (background_thread_info[0].state != background_thread_stopped) {
409+
if (background_thread_pause_check(tsd_tsdn(tsd),
410+
&background_thread_info[0])) {
411+
continue;
412+
}
399413
check_background_thread_creation(tsd, &n_created,
400414
(bool *)&created_threads);
401415
background_work_sleep_once(tsd_tsdn(tsd),
@@ -409,16 +423,17 @@ background_thread0_work(tsd_t *tsd) {
409423
assert(!background_thread_enabled());
410424
for (i = 1; i < ncpus; i++) {
411425
background_thread_info_t *info = &background_thread_info[i];
426+
assert(info->state != background_thread_paused);
412427
if (created_threads[i]) {
413428
background_threads_disable_single(tsd, info);
414429
} else {
415430
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
416431
/* Clear in case the thread wasn't created. */
417-
info->started = false;
432+
info->state = background_thread_stopped;
418433
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
419434
}
420435
}
421-
background_thread_info[0].started = false;
436+
background_thread_info[0].state = background_thread_stopped;
422437
assert(n_background_threads == 1);
423438
}
424439

@@ -432,10 +447,15 @@ background_work(tsd_t *tsd, unsigned ind) {
432447
if (ind == 0) {
433448
background_thread0_work(tsd);
434449
} else {
435-
while (info->started) {
450+
while (info->state != background_thread_stopped) {
451+
if (background_thread_pause_check(tsd_tsdn(tsd),
452+
info)) {
453+
continue;
454+
}
436455
background_work_sleep_once(tsd_tsdn(tsd), info, ind);
437456
}
438457
}
458+
assert(info->state == background_thread_stopped);
439459
background_thread_wakeup_time_set(tsd_tsdn(tsd), info, 0);
440460
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
441461
}
@@ -463,7 +483,7 @@ background_thread_entry(void *ind_arg) {
463483
static void
464484
background_thread_init(tsd_t *tsd, background_thread_info_t *info) {
465485
malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
466-
info->started = true;
486+
info->state = background_thread_started;
467487
background_thread_info_init(tsd_tsdn(tsd), info);
468488
n_background_threads++;
469489
}
@@ -480,7 +500,8 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) {
480500

481501
bool need_new_thread;
482502
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
483-
need_new_thread = background_thread_enabled() && !info->started;
503+
need_new_thread = background_thread_enabled() &&
504+
(info->state == background_thread_stopped);
484505
if (need_new_thread) {
485506
background_thread_init(tsd, info);
486507
}
@@ -492,7 +513,7 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) {
492513
/* Threads are created asynchronously by Thread 0. */
493514
background_thread_info_t *t0 = &background_thread_info[0];
494515
malloc_mutex_lock(tsd_tsdn(tsd), &t0->mtx);
495-
assert(t0->started);
516+
assert(t0->state == background_thread_started);
496517
pthread_cond_signal(&t0->cond);
497518
malloc_mutex_unlock(tsd_tsdn(tsd), &t0->mtx);
498519

@@ -512,7 +533,7 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) {
512533
malloc_printf("<jemalloc>: arena 0 background thread creation "
513534
"failed (%d)\n", err);
514535
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
515-
info->started = false;
536+
info->state = background_thread_stopped;
516537
n_background_threads--;
517538
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
518539

@@ -543,7 +564,7 @@ background_threads_enable(tsd_t *tsd) {
543564
}
544565
background_thread_info_t *info = &background_thread_info[i];
545566
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
546-
assert(!info->started);
567+
assert(info->state == background_thread_stopped);
547568
background_thread_init(tsd, info);
548569
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
549570
marked[i % ncpus] = true;
@@ -586,7 +607,7 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena,
586607
return;
587608
}
588609

589-
if (!info->started) {
610+
if (info->state != background_thread_started) {
590611
goto label_done;
591612
}
592613
if (malloc_mutex_trylock(tsdn, &decay->mtx)) {
@@ -694,7 +715,7 @@ background_thread_postfork_child(tsdn_t *tsdn) {
694715
for (unsigned i = 0; i < ncpus; i++) {
695716
background_thread_info_t *info = &background_thread_info[i];
696717
malloc_mutex_lock(tsdn, &info->mtx);
697-
info->started = false;
718+
info->state = background_thread_stopped;
698719
int ret = pthread_cond_init(&info->cond, NULL);
699720
assert(ret == 0);
700721
background_thread_info_init(tsdn, info);
@@ -718,7 +739,7 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) {
718739
for (unsigned i = 0; i < ncpus; i++) {
719740
background_thread_info_t *info = &background_thread_info[i];
720741
malloc_mutex_lock(tsdn, &info->mtx);
721-
if (info->started) {
742+
if (info->state != background_thread_stopped) {
722743
num_runs += info->tot_n_runs;
723744
nstime_add(&stats->run_interval, &info->tot_sleep_time);
724745
}
@@ -807,7 +828,7 @@ background_thread_boot1(tsdn_t *tsdn) {
807828
return true;
808829
}
809830
malloc_mutex_lock(tsdn, &info->mtx);
810-
info->started = false;
831+
info->state = background_thread_stopped;
811832
background_thread_info_init(tsdn, info);
812833
malloc_mutex_unlock(tsdn, &info->mtx);
813834
}

src/ctl.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,9 +1948,9 @@ arena_reset_prepare_background_thread(tsd_t *tsd, unsigned arena_ind) {
19481948
unsigned ind = arena_ind % ncpus;
19491949
background_thread_info_t *info =
19501950
&background_thread_info[ind];
1951-
assert(info->started && !info->pause);
1951+
assert(info->state == background_thread_started);
19521952
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
1953-
info->pause = true;
1953+
info->state = background_thread_paused;
19541954
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
19551955
}
19561956
}
@@ -1963,9 +1963,9 @@ arena_reset_finish_background_thread(tsd_t *tsd, unsigned arena_ind) {
19631963
unsigned ind = arena_ind % ncpus;
19641964
background_thread_info_t *info =
19651965
&background_thread_info[ind];
1966-
assert(info->started && info->pause);
1966+
assert(info->state = background_thread_paused);
19671967
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
1968-
info->pause = false;
1968+
info->state = background_thread_started;
19691969
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
19701970
}
19711971
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);

test/unit/background_thread.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ TEST_BEGIN(test_background_thread_running) {
8080

8181
test_repeat_background_thread_ctl(false);
8282
test_switch_background_thread_ctl(true);
83-
assert_b_eq(info->started, true,
83+
assert_b_eq(info->state, background_thread_started,
8484
"Background_thread did not start.\n");
8585

8686
nstime_t start, now;

0 commit comments

Comments
 (0)