summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2010-03-16 14:31:03 +0000
committerSimon Marlow <marlowsd@gmail.com>2010-03-16 14:31:03 +0000
commit1a050f3cff3a93f634d2d929aba779585f39609c (patch)
tree5df677ea6d010ad4c2a32e56fd733ca4ba0856fe /rts
parent3a90968fac18bbf931420afff6ef866614ecdd7f (diff)
downloadhaskell-1a050f3cff3a93f634d2d929aba779585f39609c.tar.gz
copy_tag_nolock(): fix write ordering and add a write_barrier()
Fixes a rare crash in the parallel GC. If we copy a closure non-atomically during GC, as we do for all immutable values, then before writing the forwarding pointer we better make sure that the closure itself is visible to other threads that might follow the forwarding pointer. I imagine this doesn't happen very often, but I just found one case of it: in scavenge_stack, the RET_FUN case, after evacuating ret_fun->fun we then follow it and look up the info pointer.
Diffstat (limited to 'rts')
-rw-r--r--rts/sm/Evac.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/rts/sm/Evac.c b/rts/sm/Evac.c
index 21017a63a0..d5c9b8a4a5 100644
--- a/rts/sm/Evac.c
+++ b/rts/sm/Evac.c
@@ -140,14 +140,18 @@ copy_tag_nolock(StgClosure **p, const StgInfoTable *info,
to = alloc_for_copy(size,gen);
*p = TAG_CLOSURE(tag,(StgClosure*)to);
- src->header.info = (const StgInfoTable *)MK_FORWARDING_PTR(to);
-
+
from = (StgPtr)src;
to[0] = (W_)info;
for (i = 1; i < size; i++) { // unroll for small i
to[i] = from[i];
}
+ // if somebody else reads the forwarding pointer, we better make
+ // sure there's a closure at the end of it.
+ write_barrier();
+ src->header.info = (const StgInfoTable *)MK_FORWARDING_PTR(to);
+
// if (to+size+2 < bd->start + BLOCK_SIZE_W) {
// __builtin_prefetch(to + size + 2, 1);
// }