summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-11-10 12:20:19 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-12-23 19:09:30 -0500
commit18d2acd2791a751c0b1894fd72dd0317583619cd (patch)
tree0346e0754521db617ebe684cd5c22f8bc20aa15e /rts
parent16a1bcd1d72c7a4567671f6a7f610df3fc477519 (diff)
downloadhaskell-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.
Diffstat (limited to 'rts')
-rw-r--r--rts/include/stg/SMP.h2
-rw-r--r--rts/sm/NonMovingMark.c8
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 {