[project @ 2005-11-24 16:51:18 by simonmar]
authorsimonmar <unknown>
Thu, 24 Nov 2005 16:51:18 +0000 (16:51 +0000)
committersimonmar <unknown>
Thu, 24 Nov 2005 16:51:18 +0000 (16:51 +0000)
In SMP mode it is still possible for an update frame on the stack to
point to an indirection, when two threads evaluate the same thunk (see
comment for details).

So we use the following trick: when the GC discovers an update frame
pointing to an indirection, it changes the indirection to be an
IND_PERM, so it will be retained rather than discarded.

ghc/rts/GC.c

index 513d14a..1641e3a 100644 (file)
@@ -3999,6 +3999,32 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
     switch (info->i.type) {
        
     case UPDATE_FRAME:
+       // In SMP, we can get update frames that point to indirections
+       // when two threads evaluate the same thunk.  We do attempt to
+       // discover this situation in threadPaused(), but it's
+       // possible that the following sequence occurs:
+       //
+       //        A             B
+       //                  enter T
+       //     enter T
+       //     blackhole T
+       //                  update T
+       //     GC
+       //
+       // Now T is an indirection, and the update frame is already
+       // marked on A's stack, so we won't traverse it again in
+       // threadPaused().  We could traverse the whole stack again
+       // before GC, but that seems like overkill.
+       //
+       // Scavenging this update frame as normal would be disastrous;
+       // the updatee would end up pointing to the value.  So we turn
+       // the indirection into an IND_PERM, so that evacuate will
+       // copy the indirection into the old generation instead of
+       // discarding it.
+       if (get_itbl(((StgUpdateFrame *)p)->updatee)->type == IND) {
+           ((StgUpdateFrame *)p)->updatee->header.info = 
+               (StgInfoTable *)&stg_IND_PERM_info;
+       }
        ((StgUpdateFrame *)p)->updatee 
            = evacuate(((StgUpdateFrame *)p)->updatee);
        p += sizeofW(StgUpdateFrame);
@@ -4430,7 +4456,7 @@ threadPaused(Capability *cap, StgTSO *tso)
            bh = ((StgUpdateFrame *)frame)->updatee;
 
            if (closure_IND(bh) || bh->header.info == &stg_BLACKHOLE_info) {
-               IF_DEBUG(squeeze, debugBelch("suspending duplicate work: %d words of stack\n", (StgPtr)frame - tso->sp));
+               IF_DEBUG(squeeze, debugBelch("suspending duplicate work: %ld words of stack\n", (StgPtr)frame - tso->sp));
 
                // If this closure is already an indirection, then
                // suspend the computation up to this point: