Skip to content

Commit 5d2b2dc

Browse files
committed
review
1 parent 02c9740 commit 5d2b2dc

File tree

2 files changed

+44
-30
lines changed

2 files changed

+44
-30
lines changed

ocaml/runtime/major_gc.c

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,6 @@ static atomic_uintnat num_domains_orphaning_finalisers = 0;
156156
static atomic_uintnat alloc_counter;
157157
static atomic_uintnat work_counter;
158158

159-
enum global_roots_status{
160-
WORK_UNSTARTED,
161-
WORK_STARTED,
162-
WORK_COMPLETE
163-
};
164-
static atomic_uintnat domain_global_roots_started;
165-
166159
gc_phase_t caml_gc_phase;
167160

168161
/* The caml_gc_phase global is only ever updated at the end of the STW
@@ -335,6 +328,19 @@ static void ephe_todo_list_emptied (void)
335328
caml_plat_unlock(&ephe_lock);
336329
}
337330

331+
/* Begin ephemeron marking by making all 'live' ephes become 'todo' */
332+
static void begin_ephe_marking(void)
333+
{
334+
caml_domain_state* domain = Caml_state;
335+
CAMLassert(domain->ephe_info->todo == (value) NULL);
336+
domain->ephe_info->todo = domain->ephe_info->live;
337+
domain->ephe_info->live = (value) NULL;
338+
domain->ephe_info->must_sweep_ephe = 0;
339+
domain->ephe_info->cycle = 0;
340+
domain->ephe_info->cursor.todop = NULL;
341+
domain->ephe_info->cursor.cycle = 0;
342+
}
343+
338344
/* Record that ephemeron marking was done for the given ephemeron cycle. */
339345
static void record_ephe_marking_done (uintnat ephe_cycle)
340346
{
@@ -491,12 +497,16 @@ static int no_orphaned_work (void)
491497
atomic_load_acquire(&orph_structs.final_info) == NULL;
492498
}
493499

494-
static void adopt_orphaned_work (void)
500+
static void adopt_orphaned_work (int expected_status)
495501
{
496502
caml_domain_state* domain_state = Caml_state;
497503
value orph_ephe_list_live, last;
498504
struct caml_final_info *f, *myf, *temp;
499505

506+
#ifdef DEBUG
507+
orph_ephe_list_verify_status(expected_status);
508+
#endif
509+
500510
if (no_orphaned_work() || caml_domain_is_terminating())
501511
return;
502512

@@ -1399,36 +1409,35 @@ void caml_mark_roots_stw (int participant_count, caml_domain_state** barrier_par
13991409
if (caml_gc_phase != Phase_sweep_main)
14001410
return;
14011411

1412+
enum global_roots_status {
1413+
WORK_UNSTARTED,
1414+
WORK_STARTED,
1415+
WORK_COMPLETE
1416+
};
1417+
static atomic_uintnat global_roots_scanned;
1418+
14021419
Caml_global_barrier_if_final(participant_count) {
14031420
caml_gc_phase = Phase_sweep_and_mark_main;
1404-
atomic_store_relaxed(&domain_global_roots_started, WORK_UNSTARTED);
1421+
atomic_store_relaxed(&global_roots_scanned, WORK_UNSTARTED);
14051422
}
14061423

14071424
caml_domain_state* domain = Caml_state;
14081425

1409-
/* Ephemerons */
1410-
#ifdef DEBUG
1411-
orph_ephe_list_verify_status (caml_global_heap_state.UNMARKED);
1412-
#endif
14131426
/* Adopt orphaned work from domains that were spawned and terminated in the
14141427
previous cycle. */
1415-
adopt_orphaned_work ();
1416-
CAMLassert(domain->ephe_info->todo == (value) NULL);
1417-
domain->ephe_info->todo = domain->ephe_info->live;
1418-
domain->ephe_info->live = (value) NULL;
1419-
domain->ephe_info->must_sweep_ephe = 0;
1420-
domain->ephe_info->cycle = 0;
1421-
domain->ephe_info->cursor.todop = NULL;
1422-
domain->ephe_info->cursor.cycle = 0;
1428+
adopt_orphaned_work (caml_global_heap_state.UNMARKED);
1429+
1430+
begin_ephe_marking();
14231431

14241432
CAML_EV_BEGIN(EV_MAJOR_MARK_ROOTS);
14251433
{
14261434
uintnat work_unstarted = WORK_UNSTARTED;
1427-
if (atomic_load_relaxed(&domain_global_roots_started) == WORK_UNSTARTED &&
1428-
atomic_compare_exchange_strong(&domain_global_roots_started,
1435+
if (atomic_load_relaxed(&global_roots_scanned) == WORK_UNSTARTED &&
1436+
atomic_compare_exchange_strong(&global_roots_scanned,
14291437
&work_unstarted, WORK_STARTED)) {
1438+
/* This domain did the CAS, so this domain marks the roots */
14301439
caml_scan_global_roots(&caml_darken, domain);
1431-
atomic_store_release(&domain_global_roots_started, WORK_COMPLETE);
1440+
atomic_store_release(&global_roots_scanned, WORK_COMPLETE);
14321441
}
14331442
}
14341443
/* Locals, C locals, systhreads & finalisers */
@@ -1448,11 +1457,11 @@ void caml_mark_roots_stw (int participant_count, caml_domain_state** barrier_par
14481457

14491458
/* Wait until global roots are marked. It's fine if other domains are still
14501459
marking their local roots, as long as the globals are done */
1451-
if (atomic_load_acquire(&domain_global_roots_started) != WORK_COMPLETE) {
1460+
if (atomic_load_acquire(&global_roots_scanned) != WORK_COMPLETE) {
14521461
CAML_EV_BEGIN(EV_MAJOR_MARK_OPPORTUNISTIC);
14531462
SPIN_WAIT {
14541463
caml_opportunistic_major_collection_slice(1000);
1455-
if (atomic_load_acquire(&domain_global_roots_started) == WORK_COMPLETE)
1464+
if (atomic_load_acquire(&global_roots_scanned) == WORK_COMPLETE)
14561465
break;
14571466
}
14581467
CAML_EV_END(EV_MAJOR_MARK_OPPORTUNISTIC);
@@ -1842,10 +1851,7 @@ static void major_collection_slice(intnat howmuch,
18421851
/* Nothing has been marked while updating last */
18431852
}
18441853

1845-
#ifdef DEBUG
1846-
orph_ephe_list_verify_status (caml_global_heap_state.MARKED);
1847-
#endif
1848-
adopt_orphaned_work();
1854+
adopt_orphaned_work(caml_global_heap_state.MARKED);
18491855

18501856
/* Ephemerons */
18511857
if (caml_gc_phase != Phase_sweep_ephe) {
@@ -2073,6 +2079,9 @@ int caml_mark_stack_is_empty(void)
20732079
static void empty_mark_stack (void)
20742080
{
20752081
while (!Caml_state->marking_done){
2082+
/* while, not if: it is possible for caml_empty_minor_heaps_once
2083+
to actually do a full major GC cycle, and end up returning with
2084+
caml_marking_started false, because the next cycle has started */
20762085
while (!caml_marking_started()) {
20772086
request_mark_phase();
20782087
/* This calls caml_mark_roots_stw with the minor heap empty */

ocaml/runtime/minor_gc.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,11 @@ int caml_do_opportunistic_major_slice
829829

830830
/* Make sure the minor heap is empty by performing a minor collection
831831
if needed.
832+
833+
This function also samples [caml_gc_mark_phase_requested] to see whether
834+
[caml_mark_roots_stw] should be called. To guarantee that all domains
835+
agree on whether the roots should be marked, this variable is sampled
836+
only once, instead of having domains check it individually.
832837
*/
833838
void caml_empty_minor_heap_setup(caml_domain_state* domain_unused,
834839
void* mark_requested) {

0 commit comments

Comments
 (0)