diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-11-10 12:20:19 -0500 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-12-23 19:09:30 -0500 |
commit | 18d2acd2791a751c0b1894fd72dd0317583619cd (patch) | |
tree | 0346e0754521db617ebe684cd5c22f8bc20aa15e | |
parent | 16a1bcd1d72c7a4567671f6a7f610df3fc477519 (diff) | |
download | haskell-18d2acd2791a751c0b1894fd72dd0317583619cd.tar.gz |
nonmoving: Fix race in marking of blackholes
We must use an acquire-fence when marking to ensure that the indirectee
is visible.
-rw-r--r-- | rts/include/stg/SMP.h | 2 | ||||
-rw-r--r-- | rts/sm/NonMovingMark.c | 8 |
2 files changed, 8 insertions, 2 deletions
diff --git a/rts/include/stg/SMP.h b/rts/include/stg/SMP.h index 2c14c17081..bb30935aed 100644 --- a/rts/include/stg/SMP.h +++ b/rts/include/stg/SMP.h @@ -580,6 +580,7 @@ load_load_barrier(void) { // These are typically necessary only in very specific cases (e.g. WSDeque) // where the ordered operations aren't expressive enough to capture the desired // ordering. +#define ACQUIRE_FENCE() __atomic_thread_fence(__ATOMIC_ACQUIRE) #define RELEASE_FENCE() __atomic_thread_fence(__ATOMIC_RELEASE) #define SEQ_CST_FENCE() __atomic_thread_fence(__ATOMIC_SEQ_CST) @@ -614,6 +615,7 @@ EXTERN_INLINE void load_load_barrier () {} /* nothing */ #define SEQ_CST_RELAXED_CAS(p,o,n) cas(p,o,n) // Fences +#define ACQUIRE_FENCE() #define RELEASE_FENCE() #define SEQ_CST_FENCE() diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c index d9758b943f..a42c3c46ce 100644 --- a/rts/sm/NonMovingMark.c +++ b/rts/sm/NonMovingMark.c @@ -1510,8 +1510,12 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin) } case BLACKHOLE: { - PUSH_FIELD((StgInd *) p, indirectee); - StgClosure *indirectee = ((StgInd*)p)->indirectee; + // Synchronizes with the release-store in updateWithIndirection. + // See Note [Heap memory barriers] in SMP.h. + StgInd *ind = (StgInd *) p; + ACQUIRE_FENCE(); + StgClosure *indirectee = RELAXED_LOAD(&ind->indirectee); + markQueuePushClosure(queue, indirectee, &ind->indirectee); if (GET_CLOSURE_TAG(indirectee) == 0 || origin == NULL) { // do nothing } else { |