merge upstream HEAD
[ghc-hetmet.git] / rts / ThreadPaused.c
index 58c30e3..aeae1d4 100644 (file)
@@ -14,6 +14,7 @@
 #include "Updates.h"
 #include "RaiseAsync.h"
 #include "Trace.h"
+#include "Threads.h"
 
 #include <string.h> // for memmove()
 
@@ -28,7 +29,7 @@
 struct stack_gap { StgWord gap_size; struct stack_gap *next_gap; };
 
 static void
-stackSqueeze(StgTSO *tso, StgPtr bottom)
+stackSqueeze(Capability *cap, StgTSO *tso, StgPtr bottom)
 {
     StgPtr frame;
     rtsBool prev_was_update_frame;
@@ -43,13 +44,13 @@ stackSqueeze(StgTSO *tso, StgPtr bottom)
     //    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) {
        
@@ -75,7 +76,7 @@ stackSqueeze(StgTSO *tso, StgPtr bottom)
                 * screw us up if we don't check.
                 */
                if (upd->updatee != updatee && !closure_IND(upd->updatee)) {
-                   UPD_IND(upd->updatee, updatee);
+                    updateThunk(cap, tso, upd->updatee, updatee);
                }
 
                // now mark this update frame as a stack gap.  The gap
@@ -149,7 +150,7 @@ stackSqueeze(StgTSO *tso, StgPtr 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;
@@ -163,7 +164,7 @@ stackSqueeze(StgTSO *tso, StgPtr bottom)
            memmove(sp, next_gap_start, chunk_size);
        }
 
-       tso->sp = (StgPtr)sp;
+        tso->stackobj->sp = (StgPtr)sp;
     }
 }    
 
@@ -196,31 +197,31 @@ threadPaused(Capability *cap, StgTSO *tso)
     maybePerformBlockedException (cap, tso);
     if (tso->what_next == ThreadKilled) { return; }
 
-    // NB. Blackholing is *not* optional, we must either do lazy
+    // NB. Blackholing is *compulsory*, we must either do lazy
     // 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;
@@ -229,11 +230,12 @@ threadPaused(Capability *cap, StgTSO *tso)
 #ifdef THREADED_RTS
         retry:
 #endif
-           if (closure_flags[INFO_PTR_TO_STRUCT(bh_info)->type] & _IND
-                || bh_info == &stg_BLACKHOLE_info) {
+           if (bh_info == &stg_BLACKHOLE_info ||
+                bh_info == &stg_WHITEHOLE_info)
+            {
                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.
@@ -243,44 +245,49 @@ threadPaused(Capability *cap, StgTSO *tso)
 
                // 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->sp[0] = (W_)&stg_enter_info;
+                tso->stackobj->sp = (StgPtr)frame + sizeofW(StgUpdateFrame) - 2;
+                tso->stackobj->sp[1] = (StgWord)bh;
+                ASSERT(bh->header.info != &stg_TSO_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;
            }
 
-           if (bh->header.info != &stg_CAF_BLACKHOLE_info) {
-               // zero out the slop so that the sanity checker can tell
-               // where the next closure is.
-               DEBUG_FILL_SLOP(bh);
-#ifdef PROFILING
-               // @LDV profiling
-               // We pretend that bh is now dead.
-               LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)bh);
-#endif
-                // an EAGER_BLACKHOLE gets turned into a BLACKHOLE here.
+
+            // zero out the slop so that the sanity checker can tell
+            // where the next closure is.
+            OVERWRITING_CLOSURE(bh);
+
+            // an EAGER_BLACKHOLE or CAF_BLACKHOLE gets turned into a
+            // BLACKHOLE here.
 #ifdef THREADED_RTS
-                cur_bh_info = (const StgInfoTable *)
-                    cas((StgVolatilePtr)&bh->header.info, 
-                        (StgWord)bh_info, 
-                        (StgWord)&stg_BLACKHOLE_info);
-
-                if (cur_bh_info != bh_info) {
-                    bh_info = cur_bh_info;
-                    goto retry;
-                }
-#else
-               SET_INFO(bh,&stg_BLACKHOLE_info);
+            // first we turn it into a WHITEHOLE to claim it, and if
+            // successful we write our TSO and then the BLACKHOLE info pointer.
+            cur_bh_info = (const StgInfoTable *)
+                cas((StgVolatilePtr)&bh->header.info, 
+                    (StgWord)bh_info, 
+                    (StgWord)&stg_WHITEHOLE_info);
+            
+            if (cur_bh_info != bh_info) {
+                bh_info = cur_bh_info;
+                goto retry;
+            }
 #endif
 
-               // We pretend that bh has just been created.
-               LDV_RECORD_CREATE(bh);
-           }
+            // The payload of the BLACKHOLE points to the TSO
+            ((StgInd *)bh)->indirectee = (StgClosure *)tso;
+            write_barrier();
+            SET_INFO(bh,&stg_BLACKHOLE_info);
+
+            // .. and we need a write barrier, since we just mutated the closure:
+            recordClosureMutated(cap,bh);
+
+            // We pretend that bh has just been created.
+            LDV_RECORD_CREATE(bh);
            
            frame = (StgClosure *) ((StgUpdateFrame *)frame + 1);
            if (prev_was_update_frame) {
@@ -291,7 +298,8 @@ threadPaused(Capability *cap, StgTSO *tso)
            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
@@ -315,7 +323,13 @@ end:
     // the number of words we have to shift down is less than the
     // number of stack words we squeeze away by doing so.
     if (RtsFlags.GcFlags.squeezeUpdFrames == rtsTrue &&
-       ((weight <= 5 && words_to_squeeze > 0) || weight < words_to_squeeze)) {
-       stackSqueeze(tso, (StgPtr)frame);
+       ((weight <= 8 && words_to_squeeze > 0) || weight < words_to_squeeze)) {
+        // threshold above bumped from 5 to 8 as a result of #2797
+       stackSqueeze(cap, tso, (StgPtr)frame);
+        tso->flags |= TSO_SQUEEZED;
+        // This flag tells threadStackOverflow() that the stack was
+        // squeezed, because it may not need to be expanded.
+    } else {
+        tso->flags &= ~TSO_SQUEEZED;
     }
 }