Skip to content

Commit

Permalink
use atomics in the write barrier slow path (#52463)
Browse files Browse the repository at this point in the history
Use atomics in the write-barrier slow-path to prevent duplicates in the
remset.

As discussed in #50419, setting
the mark bit is idempotent, but updating page metadata in the mark phase
is not.
  • Loading branch information
d-netto authored Dec 10, 2023
1 parent 84cfe04 commit e2a26aa
Showing 1 changed file with 11 additions and 7 deletions.
18 changes: 11 additions & 7 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1788,13 +1788,17 @@ JL_DLLEXPORT void jl_gc_queue_root(const jl_value_t *ptr)
{
jl_ptls_t ptls = jl_current_task->ptls;
jl_taggedvalue_t *o = jl_astaggedvalue(ptr);
// The modification of the `gc_bits` is not atomic but it
// should be safe here since GC is not allowed to run here and we only
// write GC_OLD to the GC bits outside GC. This could cause
// duplicated objects in the remset but that shouldn't be a problem.
o->bits.gc = GC_MARKED;
arraylist_push(ptls->heap.remset, (jl_value_t*)ptr);
ptls->heap.remset_nptr++; // conservative
// The modification of the `gc_bits` needs to be atomic.
// We need to ensure that objects are in the remset at
// most once, since the mark phase may update page metadata,
// which is not idempotent. See comments in https://github.com/JuliaLang/julia/issues/50419
uintptr_t header = jl_atomic_load_relaxed((_Atomic(uintptr_t) *)&o->header);
header &= ~GC_OLD; // clear the age bit
header = jl_atomic_exchange_relaxed((_Atomic(uintptr_t) *)&o->header, header);
if (header & GC_OLD) { // write barrier has not been triggered in this object yet
arraylist_push(ptls->heap.remset, (jl_value_t*)ptr);
ptls->heap.remset_nptr++; // conservative
}
}

void jl_gc_queue_multiroot(const jl_value_t *parent, const void *ptr, jl_datatype_t *dt) JL_NOTSAFEPOINT
Expand Down

0 comments on commit e2a26aa

Please sign in to comment.