@@ -156,13 +156,6 @@ static atomic_uintnat num_domains_orphaning_finalisers = 0;
156
156
static atomic_uintnat alloc_counter ;
157
157
static atomic_uintnat work_counter ;
158
158
159
- enum global_roots_status {
160
- WORK_UNSTARTED ,
161
- WORK_STARTED ,
162
- WORK_COMPLETE
163
- };
164
- static atomic_uintnat domain_global_roots_started ;
165
-
166
159
gc_phase_t caml_gc_phase ;
167
160
168
161
/* 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)
335
328
caml_plat_unlock (& ephe_lock );
336
329
}
337
330
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
+
338
344
/* Record that ephemeron marking was done for the given ephemeron cycle. */
339
345
static void record_ephe_marking_done (uintnat ephe_cycle )
340
346
{
@@ -491,12 +497,16 @@ static int no_orphaned_work (void)
491
497
atomic_load_acquire (& orph_structs .final_info ) == NULL ;
492
498
}
493
499
494
- static void adopt_orphaned_work (void )
500
+ static void adopt_orphaned_work (int expected_status )
495
501
{
496
502
caml_domain_state * domain_state = Caml_state ;
497
503
value orph_ephe_list_live , last ;
498
504
struct caml_final_info * f , * myf , * temp ;
499
505
506
+ #ifdef DEBUG
507
+ orph_ephe_list_verify_status (expected_status );
508
+ #endif
509
+
500
510
if (no_orphaned_work () || caml_domain_is_terminating ())
501
511
return ;
502
512
@@ -1399,36 +1409,35 @@ void caml_mark_roots_stw (int participant_count, caml_domain_state** barrier_par
1399
1409
if (caml_gc_phase != Phase_sweep_main )
1400
1410
return ;
1401
1411
1412
+ enum global_roots_status {
1413
+ WORK_UNSTARTED ,
1414
+ WORK_STARTED ,
1415
+ WORK_COMPLETE
1416
+ };
1417
+ static atomic_uintnat global_roots_scanned ;
1418
+
1402
1419
Caml_global_barrier_if_final (participant_count ) {
1403
1420
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 );
1405
1422
}
1406
1423
1407
1424
caml_domain_state * domain = Caml_state ;
1408
1425
1409
- /* Ephemerons */
1410
- #ifdef DEBUG
1411
- orph_ephe_list_verify_status (caml_global_heap_state .UNMARKED );
1412
- #endif
1413
1426
/* Adopt orphaned work from domains that were spawned and terminated in the
1414
1427
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 ();
1423
1431
1424
1432
CAML_EV_BEGIN (EV_MAJOR_MARK_ROOTS );
1425
1433
{
1426
1434
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 ,
1429
1437
& work_unstarted , WORK_STARTED )) {
1438
+ /* This domain did the CAS, so this domain marks the roots */
1430
1439
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 );
1432
1441
}
1433
1442
}
1434
1443
/* Locals, C locals, systhreads & finalisers */
@@ -1448,11 +1457,11 @@ void caml_mark_roots_stw (int participant_count, caml_domain_state** barrier_par
1448
1457
1449
1458
/* Wait until global roots are marked. It's fine if other domains are still
1450
1459
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 ) {
1452
1461
CAML_EV_BEGIN (EV_MAJOR_MARK_OPPORTUNISTIC );
1453
1462
SPIN_WAIT {
1454
1463
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 )
1456
1465
break ;
1457
1466
}
1458
1467
CAML_EV_END (EV_MAJOR_MARK_OPPORTUNISTIC );
@@ -1842,10 +1851,7 @@ static void major_collection_slice(intnat howmuch,
1842
1851
/* Nothing has been marked while updating last */
1843
1852
}
1844
1853
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 );
1849
1855
1850
1856
/* Ephemerons */
1851
1857
if (caml_gc_phase != Phase_sweep_ephe ) {
@@ -2073,6 +2079,9 @@ int caml_mark_stack_is_empty(void)
2073
2079
static void empty_mark_stack (void )
2074
2080
{
2075
2081
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 */
2076
2085
while (!caml_marking_started ()) {
2077
2086
request_mark_phase ();
2078
2087
/* This calls caml_mark_roots_stw with the minor heap empty */
0 commit comments