[project @ 2004-10-14 14:58:37 by simonmar]
[ghc-hetmet.git] / ghc / rts / Schedule.c
index b1b9fda..04e70da 100644 (file)
@@ -216,7 +216,9 @@ void            addToBlockedQueue ( StgTSO *tso );
 static void     schedule          ( StgMainThread *mainThread, Capability *initialCapability );
        void     interruptStgRts   ( void );
 
+#if !defined(PAR) && !defined(RTS_SUPPORTS_THREADS)
 static void     detectBlackHoles  ( void );
+#endif
 
 #if defined(RTS_SUPPORTS_THREADS)
 /* ToDo: carefully document the invariants that go together
@@ -371,7 +373,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
            CurrentTSO, (StgClosure*)NULL, (rtsSpark*)NULL);
 
   IF_DEBUG(gran,
-          fprintf(stderr, "GRAN: Init CurrentTSO (in schedule) = %p\n", CurrentTSO);
+          debugBelch("GRAN: Init CurrentTSO (in schedule) = %p\n", CurrentTSO);
           G_TSO(CurrentTSO, 5));
 
   if (RtsFlags.GranFlags.Light) {
@@ -428,7 +430,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
 #if defined(RTS_SUPPORTS_THREADS)
        // In the threaded RTS, deadlock detection doesn't work,
        // so just exit right away.
-       prog_belch("interrupted");
+       errorBelch("interrupted");
        releaseCapability(cap);
        RELEASE_LOCK(&sched_mutex);
        shutdownHaskellAndExit(EXIT_SUCCESS);
@@ -451,13 +453,13 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     // run queue is empty, and there are no other tasks running, we
     // can wait indefinitely for something to happen.
     //
-    if ( !EMPTY_QUEUE(blocked_queue_hd) || !EMPTY_QUEUE(sleeping_queue)
+    if ( !EMPTY_QUEUE(blocked_queue_hd) || !EMPTY_QUEUE(sleeping_queue) )
+    {
 #if defined(RTS_SUPPORTS_THREADS)
-               || EMPTY_RUN_QUEUE()
+       // We shouldn't be here...
+       barf("schedule: awaitEvent() in threaded RTS");
 #endif
-       )
-    {
-      awaitEvent( EMPTY_RUN_QUEUE() );
+       awaitEvent( EMPTY_RUN_QUEUE() );
     }
     // we can be interrupted while waiting for I/O...
     if (interrupted) continue;
@@ -477,18 +479,13 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     if (   EMPTY_THREAD_QUEUES() )
     {
        IF_DEBUG(scheduler, sched_belch("deadlocked, forcing major GC..."));
+
        // Garbage collection can release some new threads due to
        // either (a) finalizers or (b) threads resurrected because
-       // they are about to be send BlockedOnDeadMVar.  Any threads
-       // thus released will be immediately runnable.
+       // they are unreachable and will therefore be sent an
+       // exception.  Any threads thus released will be immediately
+       // runnable.
        GarbageCollect(GetRoots,rtsTrue);
-
-       if ( !EMPTY_RUN_QUEUE() ) { goto not_deadlocked; }
-
-       IF_DEBUG(scheduler, 
-                sched_belch("still deadlocked, checking for black holes..."));
-       detectBlackHoles();
-
        if ( !EMPTY_RUN_QUEUE() ) { goto not_deadlocked; }
 
 #if defined(RTS_USER_SIGNALS)
@@ -561,13 +558,13 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     if (!RtsFlags.GranFlags.Light)
       handleIdlePEs();
 
-    IF_DEBUG(gran, fprintf(stderr, "GRAN: switch by event-type\n"));
+    IF_DEBUG(gran, debugBelch("GRAN: switch by event-type\n"));
 
     /* main event dispatcher in GranSim */
     switch (event->evttype) {
       /* Should just be continuing execution */
     case ContinueThread:
-      IF_DEBUG(gran, fprintf(stderr, "GRAN: doing ContinueThread\n"));
+      IF_DEBUG(gran, debugBelch("GRAN: doing ContinueThread\n"));
       /* ToDo: check assertion
       ASSERT(run_queue_hd != (StgTSO*)NULL &&
             run_queue_hd != END_TSO_QUEUE);
@@ -575,25 +572,25 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
       /* Ignore ContinueThreads for fetching threads (if synchr comm) */
       if (!RtsFlags.GranFlags.DoAsyncFetch &&
          procStatus[CurrentProc]==Fetching) {
-       belch("ghuH: Spurious ContinueThread while Fetching ignored; TSO %d (%p) [PE %d]",
+       debugBelch("ghuH: Spurious ContinueThread while Fetching ignored; TSO %d (%p) [PE %d]\n",
              CurrentTSO->id, CurrentTSO, CurrentProc);
        goto next_thread;
       }        
       /* Ignore ContinueThreads for completed threads */
       if (CurrentTSO->what_next == ThreadComplete) {
-       belch("ghuH: found a ContinueThread event for completed thread %d (%p) [PE %d] (ignoring ContinueThread)", 
+       debugBelch("ghuH: found a ContinueThread event for completed thread %d (%p) [PE %d] (ignoring ContinueThread)\n", 
              CurrentTSO->id, CurrentTSO, CurrentProc);
        goto next_thread;
       }        
       /* Ignore ContinueThreads for threads that are being migrated */
       if (PROCS(CurrentTSO)==Nowhere) { 
-       belch("ghuH: trying to run the migrating TSO %d (%p) [PE %d] (ignoring ContinueThread)",
+       debugBelch("ghuH: trying to run the migrating TSO %d (%p) [PE %d] (ignoring ContinueThread)\n",
              CurrentTSO->id, CurrentTSO, CurrentProc);
        goto next_thread;
       }
       /* The thread should be at the beginning of the run queue */
       if (CurrentTSO!=run_queue_hds[CurrentProc]) { 
-       belch("ghuH: TSO %d (%p) [PE %d] is not at the start of the run_queue when doing a ContinueThread",
+       debugBelch("ghuH: TSO %d (%p) [PE %d] is not at the start of the run_queue when doing a ContinueThread\n",
              CurrentTSO->id, CurrentTSO, CurrentProc);
        break; // run the thread anyway
       }
@@ -650,14 +647,14 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     
     /* This point was scheduler_loop in the old RTS */
 
-    IF_DEBUG(gran, belch("GRAN: after main switch"));
+    IF_DEBUG(gran, debugBelch("GRAN: after main switch\n"));
 
     TimeOfLastEvent = CurrentTime[CurrentProc];
     TimeOfNextEvent = get_time_of_next_event();
     IgnoreEvents=(TimeOfNextEvent==0); // HWL HACK
     // CurrentTSO = ThreadQueueHd;
 
-    IF_DEBUG(gran, belch("GRAN: time of next event is: %ld", 
+    IF_DEBUG(gran, debugBelch("GRAN: time of next event is: %ld\n", 
                         TimeOfNextEvent));
 
     if (RtsFlags.GranFlags.Light) 
@@ -666,7 +663,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     EndOfTimeSlice = CurrentTime[CurrentProc]+RtsFlags.GranFlags.time_slice;
 
     IF_DEBUG(gran, 
-            belch("GRAN: end of time-slice is %#lx", EndOfTimeSlice));
+            debugBelch("GRAN: end of time-slice is %#lx\n", EndOfTimeSlice));
 
     /* in a GranSim setup the TSO stays on the run queue */
     t = CurrentTSO;
@@ -674,7 +671,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     POP_RUN_QUEUE(t); // take_off_run_queue(t);
 
     IF_DEBUG(gran, 
-            fprintf(stderr, "GRAN: About to run current thread, which is\n");
+            debugBelch("GRAN: About to run current thread, which is\n");
             G_TSO(t,5));
 
     context_switch = 0; // turned on via GranYield, checking events and time slice
@@ -710,16 +707,16 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
        if (spark != (rtsSpark) NULL) {
          tso = activateSpark(spark);       /* turn the spark into a thread */
          IF_PAR_DEBUG(schedule,
-                      belch("==== schedule: Created TSO %d (%p); %d threads active",
+                      debugBelch("==== schedule: Created TSO %d (%p); %d threads active\n",
                             tso->id, tso, advisory_thread_count));
 
          if (tso==END_TSO_QUEUE) { /* failed to activate spark->back to loop */
-           belch("==^^ failed to activate spark");
+           debugBelch("==^^ failed to activate spark\n");
            goto next_thread;
          }               /* otherwise fall through & pick-up new tso */
        } else {
          IF_PAR_DEBUG(verbose,
-                      belch("==^^ no local sparks (spark pool contains only NFs: %d)", 
+                      debugBelch("==^^ no local sparks (spark pool contains only NFs: %d)\n", 
                             spark_queue_len(pool)));
          goto next_thread;
        }
@@ -740,12 +737,12 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
         */
        TIME now = msTime() /*CURRENT_TIME*/;
        IF_PAR_DEBUG(verbose, 
-                    belch("--  now=%ld", now));
+                    debugBelch("--  now=%ld\n", now));
        IF_PAR_DEBUG(verbose,
                     if (outstandingFishes < RtsFlags.ParFlags.maxFishes &&
                         (last_fish_arrived_at!=0 &&
                          last_fish_arrived_at+RtsFlags.ParFlags.fishDelay > now)) {
-                      belch("--$$ delaying FISH until %ld (last fish %ld, delay %ld, now %ld)",
+                      debugBelch("--$$ delaying FISH until %ld (last fish %ld, delay %ld, now %ld)\n",
                             last_fish_arrived_at+RtsFlags.ParFlags.fishDelay,
                             last_fish_arrived_at,
                             RtsFlags.ParFlags.fishDelay, now);
@@ -791,7 +788,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
     pool = &(MainRegTable.rSparks); // generalise to cap = &MainRegTable
 
     IF_DEBUG(scheduler, 
-            belch("--=^ %d threads, %d sparks on [%#x]", 
+            debugBelch("--=^ %d threads, %d sparks on [%#x]\n", 
                   run_queue_len(), spark_queue_len(pool), CURRENT_PROC));
 
 # if 1
@@ -887,7 +884,7 @@ run_thread:
     RELEASE_LOCK(&sched_mutex);
 
     IF_DEBUG(scheduler, sched_belch("-->> running thread %ld %s ...", 
-                             t->id, whatNext_strs[t->what_next]));
+                             (long)t->id, whatNext_strs[t->what_next]));
 
 #ifdef PROFILING
     startHeapProfTimer();
@@ -937,9 +934,9 @@ run_thread:
     ACQUIRE_LOCK(&sched_mutex);
     
 #ifdef RTS_SUPPORTS_THREADS
-    IF_DEBUG(scheduler,fprintf(stderr,"sched (task %p): ", osThreadId()););
+    IF_DEBUG(scheduler,debugBelch("sched (task %p): ", osThreadId()););
 #elif !defined(GRAN) && !defined(PAR)
-    IF_DEBUG(scheduler,fprintf(stderr,"sched: "););
+    IF_DEBUG(scheduler,debugBelch("sched: "););
 #endif
     
 #if defined(PAR)
@@ -967,8 +964,8 @@ run_thread:
          
          blocks = (nat)BLOCK_ROUND_UP(cap->r.rHpAlloc) / BLOCK_SIZE;
 
-         IF_DEBUG(scheduler,belch("--<< thread %ld (%s) stopped: requesting a large block (size %d)", 
-                                  t->id, whatNext_strs[t->what_next], blocks));
+         IF_DEBUG(scheduler,debugBelch("--<< thread %ld (%s) stopped: requesting a large block (size %d)\n", 
+                                  (long)t->id, whatNext_strs[t->what_next], blocks));
 
          // don't do this if it would push us over the
          // alloc_blocks_lim limit; we'll GC first.
@@ -1027,8 +1024,8 @@ run_thread:
        * maybe set context_switch and wait till they all pile in,
        * then have them wait on a GC condition variable.
        */
-      IF_DEBUG(scheduler,belch("--<< thread %ld (%s) stopped: HeapOverflow", 
-                              t->id, whatNext_strs[t->what_next]));
+      IF_DEBUG(scheduler,debugBelch("--<< thread %ld (%s) stopped: HeapOverflow\n", 
+                              (long)t->id, whatNext_strs[t->what_next]));
       threadPaused(t);
 #if defined(GRAN)
       ASSERT(!is_on_queue(t,CurrentProc));
@@ -1059,8 +1056,8 @@ run_thread:
       // DumpGranEvent(GR_DESCHEDULE, t);
       globalParStats.tot_stackover++;
 #endif
-      IF_DEBUG(scheduler,belch("--<< thread %ld (%s) stopped, StackOverflow", 
-                              t->id, whatNext_strs[t->what_next]));
+      IF_DEBUG(scheduler,debugBelch("--<< thread %ld (%s) stopped, StackOverflow\n", 
+                              (long)t->id, whatNext_strs[t->what_next]));
       /* just adjust the stack for this thread, then pop it back
        * on the run queue.
        */
@@ -1105,16 +1102,16 @@ run_thread:
        */
       IF_DEBUG(scheduler,
                if (t->what_next != prev_what_next) {
-                  belch("--<< thread %ld (%s) stopped to switch evaluators", 
-                        t->id, whatNext_strs[t->what_next]);
+                  debugBelch("--<< thread %ld (%s) stopped to switch evaluators\n", 
+                        (long)t->id, whatNext_strs[t->what_next]);
                } else {
-                   belch("--<< thread %ld (%s) stopped, yielding", 
-                        t->id, whatNext_strs[t->what_next]);
+                   debugBelch("--<< thread %ld (%s) stopped, yielding\n",
+                        (long)t->id, whatNext_strs[t->what_next]);
                }
                );
 
       IF_DEBUG(sanity,
-              //belch("&& Doing sanity check on yielding TSO %ld.", t->id);
+              //debugBelch("&& Doing sanity check on yielding TSO %ld.", t->id);
               checkTSO(t));
       ASSERT(t->link == END_TSO_QUEUE);
 
@@ -1131,7 +1128,7 @@ run_thread:
       ASSERT(!is_on_queue(t,CurrentProc));
 
       IF_DEBUG(sanity,
-              //belch("&& Doing sanity check on all ThreadQueues (and their TSOs).");
+              //debugBelch("&& Doing sanity check on all ThreadQueues (and their TSOs).");
               checkThreadQsSanity(rtsTrue));
 #endif
 
@@ -1154,7 +1151,7 @@ run_thread:
                ContinueThread,
                t, (StgClosure*)NULL, (rtsSpark*)NULL);
       IF_GRAN_DEBUG(bq, 
-              belch("GRAN: eventq and runnableq after adding yielded thread to queue again:");
+              debugBelch("GRAN: eventq and runnableq after adding yielded thread to queue again:\n");
               G_EVENTQ(0);
               G_CURR_THREADQ(0));
 #endif /* GRAN */
@@ -1163,7 +1160,7 @@ run_thread:
     case ThreadBlocked:
 #if defined(GRAN)
       IF_DEBUG(scheduler,
-              belch("--<< thread %ld (%p; %s) stopped, blocking on node %p [PE %d] with BQ: ", 
+              debugBelch("--<< thread %ld (%p; %s) stopped, blocking on node %p [PE %d] with BQ: \n", 
                               t->id, t, whatNext_strs[t->what_next], t->block_info.closure, (t->block_info.closure==(StgClosure*)NULL ? 99 : where_is(t->block_info.closure)));
               if (t->block_info.closure!=(StgClosure*)NULL) print_bq(t->block_info.closure));
 
@@ -1183,7 +1180,7 @@ run_thread:
       */
 #elif defined(PAR)
       IF_DEBUG(scheduler,
-              belch("--<< thread %ld (%p; %s) stopped, blocking on node %p with BQ: ", 
+              debugBelch("--<< thread %ld (%p; %s) stopped, blocking on node %p with BQ: \n", 
                     t->id, t, whatNext_strs[t->what_next], t->block_info.closure));
       IF_PAR_DEBUG(bq,
 
@@ -1203,11 +1200,10 @@ run_thread:
        * case it'll be on the relevant queue already.
        */
       IF_DEBUG(scheduler,
-              fprintf(stderr, "--<< thread %d (%s) stopped: ", 
+              debugBelch("--<< thread %d (%s) stopped: ", 
                       t->id, whatNext_strs[t->what_next]);
               printThreadBlockage(t);
-              fprintf(stderr, "\n"));
-      fflush(stderr);
+              debugBelch("\n"));
 
       /* Only for dumping event to log file 
         ToDo: do I need this in GranSim, too?
@@ -1226,7 +1222,7 @@ run_thread:
       /* We also end up here if the thread kills itself with an
        * uncaught exception, see Exception.hc.
        */
-      IF_DEBUG(scheduler,belch("--++ thread %d (%s) finished", 
+      IF_DEBUG(scheduler,debugBelch("--++ thread %d (%s) finished\n", 
                               t->id, whatNext_strs[t->what_next]));
 #if defined(GRAN)
       endThread(t, CurrentProc); // clean-up the thread
@@ -1346,7 +1342,7 @@ run_thread:
                ContinueThread,
                t, (StgClosure*)NULL, (rtsSpark*)NULL);
       IF_GRAN_DEBUG(bq, 
-              fprintf(stderr, "GRAN: eventq and runnableq after Garbage collection:\n");
+              debugBelch("GRAN: eventq and runnableq after Garbage collection:\n\n");
               G_EVENTQ(0);
               G_CURR_THREADQ(0));
 #endif /* GRAN */
@@ -1366,7 +1362,7 @@ run_thread:
   } /* end of while(1) */
 
   IF_PAR_DEBUG(verbose,
-              belch("== Leaving schedule() after having received Finish"));
+              debugBelch("== Leaving schedule() after having received Finish\n"));
 }
 
 /* ---------------------------------------------------------------------------
@@ -1456,12 +1452,6 @@ forkProcess(HsStablePtr *entry
       stgFree(m);
     }
     
-# ifdef RTS_SUPPORTS_THREADS
-    resetTaskManagerAfterFork();      // tell startTask() and friends that
-    startingWorkerThread = rtsFalse;  // we have no worker threads any more
-    resetWorkerWakeupPipeAfterFork();
-# endif
-    
     rc = rts_evalStableIO(entry, NULL);  // run the action
     rts_checkSchedStatus("forkProcess",rc);
     
@@ -1567,8 +1557,6 @@ suspendThread( StgRegTable *reg )
   IF_DEBUG(scheduler, sched_belch("worker (token %d): leaving RTS", tok));
 #endif
 
-  /* Other threads _might_ be available for execution; signal this */
-  THREAD_RUNNABLE();
   RELEASE_LOCK(&sched_mutex);
   
   errno = saved_errno;
@@ -1703,7 +1691,7 @@ createThread(nat size)
   /* check that no more than RtsFlags.ParFlags.maxThreads threads are created */
   if (advisory_thread_count >= RtsFlags.ParFlags.maxThreads) {
     threadsIgnored++;
-    belch("{createThread}Daq ghuH: refusing to create another thread; no more than %d threads allowed (currently %d)",
+    debugBelch("{createThread}Daq ghuH: refusing to create another thread; no more than %d threads allowed (currently %d)\n",
          RtsFlags.ParFlags.maxThreads, advisory_thread_count);
     return END_TSO_QUEUE;
   }
@@ -1836,22 +1824,22 @@ createThread(nat size)
   // collect parallel global statistics (currently done together with GC stats)
   if (RtsFlags.ParFlags.ParStats.Global &&
       RtsFlags.GcFlags.giveStats > NO_GC_STATS) {
-    //fprintf(stderr, "Creating thread %d @ %11.2f\n", tso->id, usertime()); 
+    //debugBelch("Creating thread %d @ %11.2f\n", tso->id, usertime()); 
     globalParStats.tot_threads_created++;
   }
 #endif 
 
 #if defined(GRAN)
   IF_GRAN_DEBUG(pri,
-               belch("==__ schedule: Created TSO %d (%p);",
+               sched_belch("==__ schedule: Created TSO %d (%p);",
                      CurrentProc, tso, tso->id));
 #elif defined(PAR)
     IF_PAR_DEBUG(verbose,
-                belch("==__ schedule: Created TSO %d (%p); %d threads active",
-                      tso->id, tso, advisory_thread_count));
+                sched_belch("==__ schedule: Created TSO %d (%p); %d threads active",
+                      (long)tso->id, tso, advisory_thread_count));
 #else
   IF_DEBUG(scheduler,sched_belch("created thread %ld, stack size = %lx words", 
-                                tso->id, tso->stack_size));
+                               (long)tso->id, (long)tso->stack_size));
 #endif    
   return tso;
 }
@@ -1900,7 +1888,7 @@ activateSpark (rtsSpark spark)
   if (RtsFlags.ParFlags.ParStats.Full) {   
     //ASSERT(run_queue_hd == END_TSO_QUEUE); // I think ...
     IF_PAR_DEBUG(verbose,
-                belch("==^^ activateSpark: turning spark of closure %p (%s) into a thread",
+                debugBelch("==^^ activateSpark: turning spark of closure %p (%s) into a thread\n",
                       (StgClosure *)spark, info_type((StgClosure *)spark)));
   }
   // ToDo: fwd info on local/global spark to thread -- HWL
@@ -1932,11 +1920,10 @@ static void scheduleThread_ (StgTSO* tso);
 void
 scheduleThread_(StgTSO *tso)
 {
-  // Precondition: sched_mutex must be held.
   // The thread goes at the *end* of the run-queue, to avoid possible
   // starvation of any threads already on the queue.
   APPEND_TO_RUN_QUEUE(tso);
-  THREAD_RUNNABLE();
+  threadRunnable();
 }
 
 void
@@ -1996,7 +1983,7 @@ scheduleWaitThread(StgTSO* tso, /*[out]*/HaskellObj* ret,
     IF_DEBUG(scheduler, sched_belch("waiting for thread (%d)", tso->id));
     
     APPEND_TO_RUN_QUEUE(tso);
-    // NB. Don't call THREAD_RUNNABLE() here, because the thread is
+    // NB. Don't call threadRunnable() here, because the thread is
     // bound and only runnable by *this* OS thread, so waking up other
     // workers will just slow things down.
 
@@ -2268,8 +2255,8 @@ threadStackOverflow(StgTSO *tso)
   if (tso->stack_size >= tso->max_stack_size) {
 
     IF_DEBUG(gc,
-            belch("@@ threadStackOverflow of TSO %d (%p): stack too large (now %ld; max is %ld)",
-                  tso->id, tso, tso->stack_size, tso->max_stack_size);
+            debugBelch("@@ threadStackOverflow of TSO %ld (%p): stack too large (now %ld; max is %ld)\n",
+                  (long)tso->id, tso, (long)tso->stack_size, (long)tso->max_stack_size);
             /* If we're debugging, just print out the top of the stack */
             printStackChunk(tso->sp, stg_min(tso->stack+tso->stack_size, 
                                              tso->sp+64)));
@@ -2289,7 +2276,7 @@ threadStackOverflow(StgTSO *tso)
   new_tso_size = round_to_mblocks(new_tso_size);  /* Be MBLOCK-friendly */
   new_stack_size = new_tso_size - TSO_STRUCT_SIZEW;
 
-  IF_DEBUG(scheduler, fprintf(stderr,"== sched: increasing stack size from %d words to %d.\n", tso->stack_size, new_stack_size));
+  IF_DEBUG(scheduler, debugBelch("== sched: increasing stack size from %d words to %d.\n", tso->stack_size, new_stack_size));
 
   dest = (StgTSO *)allocate(new_tso_size);
   TICK_ALLOC_TSO(new_stack_size,0);
@@ -2318,7 +2305,7 @@ threadStackOverflow(StgTSO *tso)
   dest->mut_link = NULL;
 
   IF_PAR_DEBUG(verbose,
-              belch("@@ threadStackOverflow of TSO %d (now at %p): stack size increased to %ld",
+              debugBelch("@@ threadStackOverflow of TSO %d (now at %p): stack size increased to %ld\n",
                     tso->id, tso, tso->stack_size);
               /* If we're debugging, just print out the top of the stack */
               printStackChunk(tso->sp, stg_min(tso->stack+tso->stack_size, 
@@ -2407,11 +2394,11 @@ unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
     }
     /* the thread-queue-overhead is accounted for in either Resume or UnblockThread */
     IF_GRAN_DEBUG(bq,
-                 fprintf(stderr," %s TSO %d (%p) [PE %d] (block_info.closure=%p) (next=%p) ,",
+                 debugBelch(" %s TSO %d (%p) [PE %d] (block_info.closure=%p) (next=%p) ,",
                          (node_loc==tso_loc ? "Local" : "Global"), 
                          tso->id, tso, CurrentProc, tso->block_info.closure, tso->link));
     tso->block_info.closure = NULL;
-    IF_DEBUG(scheduler,belch("-- Waking up thread %ld (%p)", 
+    IF_DEBUG(scheduler,debugBelch("-- Waking up thread %ld (%p)\n", 
                             tso->id, tso));
 }
 #elif defined(PAR)
@@ -2425,9 +2412,9 @@ unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
       ASSERT(((StgTSO *)bqe)->why_blocked != NotBlocked);
       /* if it's a TSO just push it onto the run_queue */
       next = bqe->link;
-      // ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging?
+      ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging?
       APPEND_TO_RUN_QUEUE((StgTSO *)bqe); 
-      THREAD_RUNNABLE();
+      threadRunnable();
       unblockCount(bqe, node);
       /* reset blocking status after dumping event */
       ((StgTSO *)bqe)->why_blocked = NotBlocked;
@@ -2456,7 +2443,7 @@ unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
           (StgClosure *)bqe);
 # endif
     }
-  IF_PAR_DEBUG(bq, fprintf(stderr, ", %p (%s)", bqe, info_type((StgClosure*)bqe)));
+  IF_PAR_DEBUG(bq, debugBelch(", %p (%s)\n", bqe, info_type((StgClosure*)bqe)));
   return next;
 }
 
@@ -2470,9 +2457,10 @@ unblockOneLocked(StgTSO *tso)
   ASSERT(tso->why_blocked != NotBlocked);
   tso->why_blocked = NotBlocked;
   next = tso->link;
+  tso->link = END_TSO_QUEUE;
   APPEND_TO_RUN_QUEUE(tso);
-  THREAD_RUNNABLE();
-  IF_DEBUG(scheduler,sched_belch("waking up thread %ld", tso->id));
+  threadRunnable();
+  IF_DEBUG(scheduler,sched_belch("waking up thread %ld", (long)tso->id));
   return next;
 }
 #endif
@@ -2506,7 +2494,7 @@ awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
   nat len = 0; 
 
   IF_GRAN_DEBUG(bq, 
-               belch("##-_ AwBQ for node %p on PE %d @ %ld by TSO %d (%p): ", \
+               debugBelch("##-_ AwBQ for node %p on PE %d @ %ld by TSO %d (%p): \n", \
                      node, CurrentProc, CurrentTime[CurrentProc], 
                      CurrentTSO->id, CurrentTSO));
 
@@ -2523,13 +2511,13 @@ awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
   */
   if (CurrentProc!=node_loc) {
     IF_GRAN_DEBUG(bq, 
-                 belch("## node %p is on PE %d but CurrentProc is %d (TSO %d); assuming fake fetch and adjusting bitmask (old: %#x)",
+                 debugBelch("## node %p is on PE %d but CurrentProc is %d (TSO %d); assuming fake fetch and adjusting bitmask (old: %#x)\n",
                        node, node_loc, CurrentProc, CurrentTSO->id, 
                        // CurrentTSO, where_is(CurrentTSO),
                        node->header.gran.procs));
     node->header.gran.procs = (node->header.gran.procs) | PE_NUMBER(CurrentProc);
     IF_GRAN_DEBUG(bq, 
-                 belch("## new bitmask of node %p is %#x",
+                 debugBelch("## new bitmask of node %p is %#x\n",
                        node, node->header.gran.procs));
     if (RtsFlags.GranFlags.GranSimStats.Global) {
       globalGranStats.tot_fake_fetches++;
@@ -2564,7 +2552,7 @@ awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
     ((StgRBH *)node)->mut_link       = (StgMutClosure *)((StgRBHSave *)bqe)->payload[1];
 
     IF_GRAN_DEBUG(bq,
-                 belch("## Filled in RBH_Save for %p (%s) at end of AwBQ",
+                 debugBelch("## Filled in RBH_Save for %p (%s) at end of AwBQ\n",
                        node, info_type(node)));
   }
 
@@ -2576,7 +2564,7 @@ awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
     globalGranStats.tot_awbq++;             // total no. of bqs awakened
   }
   IF_GRAN_DEBUG(bq,
-               fprintf(stderr,"## BQ Stats of %p: [%d entries] %s\n",
+               debugBelch("## BQ Stats of %p: [%d entries] %s\n",
                        node, len, (bqe!=END_BQ_QUEUE) ? "RBH" : ""));
 }
 #elif defined(PAR)
@@ -2588,12 +2576,12 @@ awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
   ACQUIRE_LOCK(&sched_mutex);
 
   IF_PAR_DEBUG(verbose, 
-              belch("##-_ AwBQ for node %p on [%x]: ",
+              debugBelch("##-_ AwBQ for node %p on [%x]: \n",
                     node, mytid));
 #ifdef DIST  
   //RFP
   if(get_itbl(q)->type == CONSTR || q==END_BQ_QUEUE) {
-    IF_PAR_DEBUG(verbose, belch("## ... nothing to unblock so lets just return. RFP (BUG?)"));
+    IF_PAR_DEBUG(verbose, debugBelch("## ... nothing to unblock so lets just return. RFP (BUG?)\n"));
     return;
   }
 #endif
@@ -2642,9 +2630,6 @@ interruptStgRts(void)
 {
     interrupted    = 1;
     context_switch = 1;
-#ifdef RTS_SUPPORTS_THREADS
-    wakeBlockedWorkerThread();
-#endif
 }
 
 /* -----------------------------------------------------------------------------
@@ -3005,7 +2990,7 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
     }
 
     IF_DEBUG(scheduler, 
-            sched_belch("raising exception in thread %ld.", tso->id));
+            sched_belch("raising exception in thread %ld.", (long)tso->id));
     
     // Remove it from any blocking queues
     unblockThread(tso);
@@ -3120,9 +3105,9 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
            TICK_ALLOC_UP_THK(words+1,0);
            
            IF_DEBUG(scheduler,
-                    fprintf(stderr,  "sched: Updating ");
+                    debugBelch("sched: Updating ");
                     printPtr((P_)((StgUpdateFrame *)frame)->updatee); 
-                    fprintf(stderr,  " with ");
+                    debugBelch(" with ");
                     printObj((StgClosure *)ap);
                );
 
@@ -3275,68 +3260,6 @@ resurrectThreads( StgTSO *threads )
   }
 }
 
-/* -----------------------------------------------------------------------------
- * Blackhole detection: if we reach a deadlock, test whether any
- * threads are blocked on themselves.  Any threads which are found to
- * be self-blocked get sent a NonTermination exception.
- *
- * This is only done in a deadlock situation in order to avoid
- * performance overhead in the normal case.
- *
- * Locks: sched_mutex is held upon entry and exit.
- * -------------------------------------------------------------------------- */
-
-static void
-detectBlackHoles( void )
-{
-    StgTSO *tso = all_threads;
-    StgClosure *frame;
-    StgClosure *blocked_on;
-    StgRetInfoTable *info;
-
-    for (tso = all_threads; tso != END_TSO_QUEUE; tso = tso->global_link) {
-
-       while (tso->what_next == ThreadRelocated) {
-           tso = tso->link;
-           ASSERT(get_itbl(tso)->type == TSO);
-       }
-      
-       if (tso->why_blocked != BlockedOnBlackHole) {
-           continue;
-       }
-       blocked_on = tso->block_info.closure;
-
-       frame = (StgClosure *)tso->sp;
-
-       while(1) {
-           info = get_ret_itbl(frame);
-           switch (info->i.type) {
-           case UPDATE_FRAME:
-               if (((StgUpdateFrame *)frame)->updatee == blocked_on) {
-                   /* We are blocking on one of our own computations, so
-                    * send this thread the NonTermination exception.  
-                    */
-                   IF_DEBUG(scheduler, 
-                            sched_belch("thread %d is blocked on itself", tso->id));
-                   raiseAsync(tso, (StgClosure *)NonTermination_closure);
-                   goto done;
-               }
-               
-               frame = (StgClosure *) ((StgUpdateFrame *)frame + 1);
-               continue;
-
-           case STOP_FRAME:
-               goto done;
-
-               // normal stack frames; do nothing except advance the pointer
-           default:
-               (StgPtr)frame += stack_frame_sizeW(frame);
-           }
-       }   
-       done: ;
-    }
-}
-
 /* ----------------------------------------------------------------------------
  * Debugging: why is a thread blocked
  * [Also provides useful information when debugging threaded programs
@@ -3349,47 +3272,47 @@ printThreadBlockage(StgTSO *tso)
 {
   switch (tso->why_blocked) {
   case BlockedOnRead:
-    fprintf(stderr,"is blocked on read from fd %d", tso->block_info.fd);
+    debugBelch("is blocked on read from fd %d", tso->block_info.fd);
     break;
   case BlockedOnWrite:
-    fprintf(stderr,"is blocked on write to fd %d", tso->block_info.fd);
+    debugBelch("is blocked on write to fd %d", tso->block_info.fd);
     break;
 #if defined(mingw32_TARGET_OS)
     case BlockedOnDoProc:
-    fprintf(stderr,"is blocked on proc (request: %d)", tso->block_info.async_result->reqID);
+    debugBelch("is blocked on proc (request: %d)", tso->block_info.async_result->reqID);
     break;
 #endif
   case BlockedOnDelay:
-    fprintf(stderr,"is blocked until %d", tso->block_info.target);
+    debugBelch("is blocked until %d", tso->block_info.target);
     break;
   case BlockedOnMVar:
-    fprintf(stderr,"is blocked on an MVar");
+    debugBelch("is blocked on an MVar");
     break;
   case BlockedOnException:
-    fprintf(stderr,"is blocked on delivering an exception to thread %d",
+    debugBelch("is blocked on delivering an exception to thread %d",
            tso->block_info.tso->id);
     break;
   case BlockedOnBlackHole:
-    fprintf(stderr,"is blocked on a black hole");
+    debugBelch("is blocked on a black hole");
     break;
   case NotBlocked:
-    fprintf(stderr,"is not blocked");
+    debugBelch("is not blocked");
     break;
 #if defined(PAR)
   case BlockedOnGA:
-    fprintf(stderr,"is blocked on global address; local FM_BQ is %p (%s)",
+    debugBelch("is blocked on global address; local FM_BQ is %p (%s)",
            tso->block_info.closure, info_type(tso->block_info.closure));
     break;
   case BlockedOnGA_NoSend:
-    fprintf(stderr,"is blocked on global address (no send); local FM_BQ is %p (%s)",
+    debugBelch("is blocked on global address (no send); local FM_BQ is %p (%s)",
            tso->block_info.closure, info_type(tso->block_info.closure));
     break;
 #endif
   case BlockedOnCCall:
-    fprintf(stderr,"is blocked on an external call");
+    debugBelch("is blocked on an external call");
     break;
   case BlockedOnCCall_NoUnblockExc:
-    fprintf(stderr,"is blocked on an external call (exceptions were already blocked)");
+    debugBelch("is blocked on an external call (exceptions were already blocked)");
     break;
   default:
     barf("printThreadBlockage: strange tso->why_blocked: %d for TSO %d (%d)",
@@ -3403,10 +3326,10 @@ printThreadStatus(StgTSO *tso)
 {
   switch (tso->what_next) {
   case ThreadKilled:
-    fprintf(stderr,"has been killed");
+    debugBelch("has been killed");
     break;
   case ThreadComplete:
-    fprintf(stderr,"has completed");
+    debugBelch("has completed");
     break;
   default:
     printThreadBlockage(tso);
@@ -3417,30 +3340,33 @@ void
 printAllThreads(void)
 {
   StgTSO *t;
-  void *label;
 
 # if defined(GRAN)
   char time_string[TIME_STR_LEN], node_str[NODE_STR_LEN];
   ullong_format_string(TIME_ON_PROC(CurrentProc), 
                       time_string, rtsFalse/*no commas!*/);
 
-  fprintf(stderr, "all threads at [%s]:\n", time_string);
+  debugBelch("all threads at [%s]:\n", time_string);
 # elif defined(PAR)
   char time_string[TIME_STR_LEN], node_str[NODE_STR_LEN];
   ullong_format_string(CURRENT_TIME,
                       time_string, rtsFalse/*no commas!*/);
 
-  fprintf(stderr,"all threads at [%s]:\n", time_string);
+  debugBelch("all threads at [%s]:\n", time_string);
 # else
-  fprintf(stderr,"all threads:\n");
+  debugBelch("all threads:\n");
 # endif
 
   for (t = all_threads; t != END_TSO_QUEUE; t = t->global_link) {
-    fprintf(stderr, "\tthread %d @ %p ", t->id, (void *)t);
-    label = lookupThreadLabel(t->id);
-    if (label) fprintf(stderr,"[\"%s\"] ",(char *)label);
+    debugBelch("\tthread %d @ %p ", t->id, (void *)t);
+#if defined(DEBUG)
+    {
+      void *label = lookupThreadLabel(t->id);
+      if (label) debugBelch("[\"%s\"] ",(char *)label);
+    }
+#endif
     printThreadStatus(t);
-    fprintf(stderr,"\n");
+    debugBelch("\n");
   }
 }
     
@@ -3457,7 +3383,7 @@ print_bq (StgClosure *node)
   StgTSO *tso;
   rtsBool end;
 
-  fprintf(stderr,"## BQ of closure %p (%s): ",
+  debugBelch("## BQ of closure %p (%s): ",
          node, info_type(node));
 
   /* should cover all closures that may have a blocking queue */
@@ -3497,18 +3423,18 @@ print_bqe (StgBlockingQueueElement *bqe)
 
     switch (get_itbl(bqe)->type) {
     case TSO:
-      fprintf(stderr," TSO %u (%x),",
+      debugBelch(" TSO %u (%x),",
              ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
       break;
     case BLOCKED_FETCH:
-      fprintf(stderr," BF (node=%p, ga=((%x, %d, %x)),",
+      debugBelch(" BF (node=%p, ga=((%x, %d, %x)),",
              ((StgBlockedFetch *)bqe)->node, 
              ((StgBlockedFetch *)bqe)->ga.payload.gc.gtid,
              ((StgBlockedFetch *)bqe)->ga.payload.gc.slot,
              ((StgBlockedFetch *)bqe)->ga.weight);
       break;
     case CONSTR:
-      fprintf(stderr," %s (IP %p),",
+      debugBelch(" %s (IP %p),",
              (get_itbl(bqe) == &stg_RBH_Save_0_info ? "RBH_Save_0" :
               get_itbl(bqe) == &stg_RBH_Save_1_info ? "RBH_Save_1" :
               get_itbl(bqe) == &stg_RBH_Save_2_info ? "RBH_Save_2" :
@@ -3520,7 +3446,7 @@ print_bqe (StgBlockingQueueElement *bqe)
       break;
     }
   } /* for */
-  fputc('\n', stderr);
+  debugBelch("\n");
 }
 # elif defined(GRAN)
 void 
@@ -3538,7 +3464,7 @@ print_bq (StgClosure *node)
   ASSERT(node!=(StgClosure*)NULL);         // sanity check
   node_loc = where_is(node);
 
-  fprintf(stderr,"## BQ of closure %p (%s) on [PE %d]: ",
+  debugBelch("## BQ of closure %p (%s) on [PE %d]: ",
          node, info_type(node), node_loc);
 
   /* 
@@ -3558,11 +3484,11 @@ print_bq (StgClosure *node)
     tso_loc = where_is((StgClosure *)bqe);
     switch (get_itbl(bqe)->type) {
     case TSO:
-      fprintf(stderr," TSO %d (%p) on [PE %d],",
+      debugBelch(" TSO %d (%p) on [PE %d],",
              ((StgTSO *)bqe)->id, (StgTSO *)bqe, tso_loc);
       break;
     case CONSTR:
-      fprintf(stderr," %s (IP %p),",
+      debugBelch(" %s (IP %p),",
              (get_itbl(bqe) == &stg_RBH_Save_0_info ? "RBH_Save_0" :
               get_itbl(bqe) == &stg_RBH_Save_1_info ? "RBH_Save_1" :
               get_itbl(bqe) == &stg_RBH_Save_2_info ? "RBH_Save_2" :
@@ -3574,7 +3500,7 @@ print_bq (StgClosure *node)
       break;
     }
   } /* for */
-  fputc('\n', stderr);
+  debugBelch("\n");
 }
 #else
 /* 
@@ -3591,9 +3517,9 @@ print_bq (StgClosure *node)
        tso=tso->link) {
     ASSERT(tso!=NULL && tso!=END_TSO_QUEUE);   // sanity check
     ASSERT(get_itbl(tso)->type == TSO);  // guess what, sanity check
-    fprintf(stderr," TSO %d (%p),", tso->id, tso);
+    debugBelch(" TSO %d (%p),", tso->id, tso);
   }
-  fputc('\n', stderr);
+  debugBelch("\n");
 }
 # endif
 
@@ -3619,15 +3545,14 @@ sched_belch(char *s, ...)
   va_list ap;
   va_start(ap,s);
 #ifdef RTS_SUPPORTS_THREADS
-  fprintf(stderr, "sched (task %p): ", osThreadId());
+  debugBelch("sched (task %p): ", osThreadId());
 #elif defined(PAR)
-  fprintf(stderr, "== ");
+  debugBelch("== ");
 #else
-  fprintf(stderr, "sched: ");
+  debugBelch("sched: ");
 #endif
-  vfprintf(stderr, s, ap);
-  fprintf(stderr, "\n");
-  fflush(stderr);
+  vdebugBelch(s, ap);
+  debugBelch("\n");
   va_end(ap);
 }