// contains two values: the size of the gap, and the distance
// to the next gap (or the stack top).
- frame = tso->sp;
+ frame = tso->stackobj->sp;
ASSERT(frame < bottom);
prev_was_update_frame = rtsFalse;
current_gap_size = 0;
- gap = (struct stack_gap *) (tso->sp - sizeofW(StgUpdateFrame));
+ gap = (struct stack_gap *) (frame - sizeofW(StgUpdateFrame));
while (frame <= bottom) {
next_gap_start = (StgWord8*)gap + sizeof(StgUpdateFrame);
sp = next_gap_start;
- while ((StgPtr)gap > tso->sp) {
+ while ((StgPtr)gap > tso->stackobj->sp) {
// we're working in *bytes* now...
gap_start = next_gap_start;
memmove(sp, next_gap_start, chunk_size);
}
- tso->sp = (StgPtr)sp;
+ tso->stackobj->sp = (StgPtr)sp;
}
}
// blackholing, or eager blackholing consistently. See Note
// [upd-black-hole] in sm/Scav.c.
- stack_end = &tso->stack[tso->stack_size];
+ stack_end = tso->stackobj->stack + tso->stackobj->stack_size;
- frame = (StgClosure *)tso->sp;
+ frame = (StgClosure *)tso->stackobj->sp;
- while (1) {
- // If we've already marked this frame, then stop here.
- if (frame->header.info == (StgInfoTable *)&stg_marked_upd_frame_info) {
- if (prev_was_update_frame) {
- words_to_squeeze += sizeofW(StgUpdateFrame);
- weight += weight_pending;
- weight_pending = 0;
- }
- goto end;
- }
-
- info = get_ret_itbl(frame);
+ while ((P_)frame < stack_end) {
+ info = get_ret_itbl(frame);
switch (info->i.type) {
-
+
case UPDATE_FRAME:
+ // If we've already marked this frame, then stop here.
+ if (frame->header.info == (StgInfoTable *)&stg_marked_upd_frame_info) {
+ if (prev_was_update_frame) {
+ words_to_squeeze += sizeofW(StgUpdateFrame);
+ weight += weight_pending;
+ weight_pending = 0;
+ }
+ goto end;
+ }
+
SET_INFO(frame, (StgInfoTable *)&stg_marked_upd_frame_info);
bh = ((StgUpdateFrame *)frame)->updatee;
#ifdef THREADED_RTS
retry:
#endif
- if (bh_info == &stg_BLACKHOLE_info ||
- bh_info == &stg_WHITEHOLE_info)
+ // If the info table is a WHITEHOLE or a BLACKHOLE, then
+ // another thread has claimed it (via the SET_INFO()
+ // below), or is in the process of doing so. In that case
+ // we want to suspend the work that the current thread has
+ // done on this thunk and wait until the other thread has
+ // finished.
+ //
+ // If eager blackholing is taking place, it could be the
+ // case that the blackhole points to the current
+ // TSO. e.g.:
+ //
+ // this thread other thread
+ // --------------------------------------------------------
+ // c->indirectee = other_tso;
+ // c->header.info = EAGER_BH
+ // threadPaused():
+ // c->header.info = WHITEHOLE
+ // c->indirectee = other_tso
+ // c->indirectee = this_tso;
+ // c->header.info = EAGER_BH
+ // c->header.info = BLACKHOLE
+ // threadPaused()
+ // *** c->header.info is now BLACKHOLE,
+ // c->indirectee points to this_tso
+ //
+ // So in this case do *not* suspend the work of the
+ // current thread, because the current thread will become
+ // deadlocked on itself. See #5226 for an instance of
+ // this bug.
+ //
+ if ((bh_info == &stg_WHITEHOLE_info ||
+ bh_info == &stg_BLACKHOLE_info)
+ &&
+ ((StgInd*)bh)->indirectee != (StgClosure*)tso)
{
debugTrace(DEBUG_squeeze,
"suspending duplicate work: %ld words of stack",
- (long)((StgPtr)frame - tso->sp));
+ (long)((StgPtr)frame - tso->stackobj->sp));
// If this closure is already an indirection, then
// suspend the computation up to this point.
// Now drop the update frame, and arrange to return
// the value to the frame underneath:
- tso->sp = (StgPtr)frame + sizeofW(StgUpdateFrame) - 2;
- tso->sp[1] = (StgWord)bh;
+ tso->stackobj->sp = (StgPtr)frame + sizeofW(StgUpdateFrame) - 2;
+ tso->stackobj->sp[1] = (StgWord)bh;
ASSERT(bh->header.info != &stg_TSO_info);
- tso->sp[0] = (W_)&stg_enter_info;
+ tso->stackobj->sp[0] = (W_)&stg_enter_info;
// And continue with threadPaused; there might be
// yet more computation to suspend.
- frame = (StgClosure *)(tso->sp + 2);
+ frame = (StgClosure *)(tso->stackobj->sp + 2);
prev_was_update_frame = rtsFalse;
continue;
}
+
// zero out the slop so that the sanity checker can tell
// where the next closure is.
- DEBUG_FILL_SLOP(bh);
-
- // @LDV profiling
- // We pretend that bh is now dead.
- LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC((StgClosure *)bh);
+ OVERWRITING_CLOSURE(bh);
// an EAGER_BLACKHOLE or CAF_BLACKHOLE gets turned into a
// BLACKHOLE here.
prev_was_update_frame = rtsTrue;
break;
- case STOP_FRAME:
+ case UNDERFLOW_FRAME:
+ case STOP_FRAME:
goto end;
// normal stack frames; do nothing except advance the pointer