// stats. Every mutable list is copied during every GC.
if (g > 0) {
for (bd = generations[g].mut_list; bd != NULL; bd = bd->link) {
- copied += (bd->free - bd->start) * sizeof(StgWord);
+ copied += bd->free - bd->start;
}
}
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
-#if defined(SMP)
- tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
-#endif
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
p += sizeofW(StgTVar);
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
-#if defined(SMP)
- tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
-#endif
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
break;
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
-#if defined(SMP)
- tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
-#endif
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
break;
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);
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: