[project @ 2002-02-15 17:49:23 by sof]
[ghc-hetmet.git] / ghc / rts / Schedule.c
index 92d2cf6..1f8d06b 100644 (file)
@@ -1,5 +1,5 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.118 2002/02/06 01:29:27 sof Exp $
+ * $Id: Schedule.c,v 1.127 2002/02/15 17:49:23 sof Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -158,7 +158,7 @@ StgTSO* ActiveTSO = NULL; /* for assigning system costs; GranSim-Light only */
 /* rtsTime TimeOfNextEvent, EndOfTimeSlice;            now in GranSim.c */
 
 /* 
-   In GranSim we have a runable and a blocked queue for each processor.
+   In GranSim we have a runnable and a blocked queue for each processor.
    In order to minimise code changes new arrays run_queue_hds/tls
    are created. run_queue_hd is then a short cut (macro) for
    run_queue_hds[CurrentProc] (see GranSim.h).
@@ -185,7 +185,9 @@ StgTSO *sleeping_queue;             /* perhaps replace with a hash table? */
  */
 StgTSO *all_threads;
 
-/* Threads suspended in _ccall_GC.
+/* When a thread performs a safe C call (_ccall_GC, using old
+ * terminology), it gets put on the suspended_ccalling_threads
+ * list. Used by the garbage collector.
  */
 static StgTSO *suspended_ccalling_threads;
 
@@ -263,57 +265,13 @@ static void sched_belch(char *s, ...);
  */
 Mutex     sched_mutex       = INIT_MUTEX_VAR;
 Mutex     term_mutex        = INIT_MUTEX_VAR;
-#if defined(THREADED_RTS)
-/*
- * The rts_mutex is the 'big lock' that the active native
- * thread within the RTS holds while executing code.
- * It is given up when the thread makes a transition out of
- * the RTS (e.g., to perform an external C call), hopefully
- * for another thread to take over its chores and enter
- * the RTS.
- *
- */
-Mutex     rts_mutex         = INIT_MUTEX_VAR;
-/*
- * When a native thread has completed executing an external
- * call, it needs to communicate the result back to the
- * (Haskell) thread that made the call. Do this as follows:
- *
- *  - in resumeThread(), the thread increments the counter
- *    threads_waiting, and then blocks on the 'big' RTS lock.
- *  - upon entry to the scheduler, the thread that's currently
- *    holding the RTS lock checks threads_waiting. If there
- *    are native threads waiting, it gives up its RTS lock
- *    and tries to re-grab the RTS lock [perhaps after having
- *    waited for a bit..?]
- *  - care must be taken to deal with the case where more than
- *    one external thread are waiting on the lock. [ToDo: more]
- *    
- */
-
-static nat threads_waiting = 0;
-/*
- * thread_ready_aux_mutex is used to handle the scenario where the
- * the RTS executing thread runs out of work, but there are
- * active external threads. The RTS executing thread gives up
- * its RTS mutex, and blocks waiting for the thread_ready_cond.
- * Unfortunately, a condition variable needs to be associated
- * with a mutex in pthreads, so rts_thread_waiting_mutex is
- * used for just this purpose.
- * 
- */
-Mutex  thread_ready_aux_mutex = INIT_MUTEX_VAR;
-#endif
-
-
-/* thread_ready_cond: when signalled, a thread has
- * become runnable. When used?
- */
-Condition thread_ready_cond = INIT_COND_VAR;
-Condition gc_pending_cond   = INIT_COND_VAR;
 
+# if defined(SMP)
+static Condition gc_pending_cond = INIT_COND_VAR;
 nat await_death;
-#endif
+# endif
+
+#endif /* RTS_SUPPORTS_THREADS */
 
 #if defined(PAR)
 StgTSO *LastTSO;
@@ -355,12 +313,6 @@ static void taskStart(void);
 static void
 taskStart(void)
 {
-  /* threads start up using 'taskStart', so make them
-     them grab the RTS lock. */
-#if defined(THREADED_RTS)
-  ACQUIRE_LOCK(&rts_mutex);
-  taskNotAvailable();
-#endif
   schedule();
 }
 #endif
@@ -428,31 +380,17 @@ schedule( void )
   rtsBool was_interrupted = rtsFalse;
   
   ACQUIRE_LOCK(&sched_mutex);
-  
-#if defined(THREADED_RTS)
-  /* ToDo: consider SMP support */
-  if (threads_waiting > 0) {
-    /* (At least) one native thread is waiting to
-     * deposit the result of an external call. So,
-     * give up our RTS executing privileges and let
-     * one of them continue.
-     * 
-     */
-    taskAvailable();
-    RELEASE_LOCK(&sched_mutex);
-    IF_DEBUG(scheduler, sched_belch("worker thread (%d): giving up RTS token (threads_waiting=%d)\n", osThreadId(), threads_waiting));
-    RELEASE_LOCK(&rts_mutex);
-    /* ToDo: come up with mechanism that guarantees that
-     * the main thread doesn't loop here.
-     */
-    yieldThread();
-    /* ToDo: longjmp() */
-    taskStart();
-  }
+#if defined(RTS_SUPPORTS_THREADS)
+  /* Check to see whether there are any worker threads
+     waiting to deposit external call results. If so,
+     yield our capability */
+  yieldToReturningWorker(&sched_mutex, cap);
+
+  waitForWorkCapability(&sched_mutex, &cap, rtsFalse);
 #endif
 
 #if defined(GRAN)
-
   /* set up first event to get things going */
   /* ToDo: assign costs for system setup and init MainTSO ! */
   new_event(CurrentProc, CurrentProc, CurrentTime[CurrentProc],
@@ -619,9 +557,8 @@ schedule( void )
      * ToDo: what if another client comes along & requests another
      * main thread?
      */
-    if (blocked_queue_hd != END_TSO_QUEUE || sleeping_queue != END_TSO_QUEUE) {
-      awaitEvent(
-          (run_queue_hd == END_TSO_QUEUE)
+    if ( !EMPTY_QUEUE(blocked_queue_hd) || !EMPTY_QUEUE(sleeping_queue) ) {
+      awaitEvent( EMPTY_RUN_QUEUE()
 #if defined(SMP)
        && allFreeCapabilities()
 #endif
@@ -642,24 +579,28 @@ schedule( void )
      * inform all the main threads.
      */
 #ifndef PAR
-    if (blocked_queue_hd == END_TSO_QUEUE
-       && run_queue_hd == END_TSO_QUEUE
-       && sleeping_queue == END_TSO_QUEUE
-#if defined(SMP)
+    if (   EMPTY_RUN_QUEUE()
+       && EMPTY_QUEUE(blocked_queue_hd)
+       && EMPTY_QUEUE(sleeping_queue)
+#if defined(RTS_SUPPORTS_THREADS)
+       && EMPTY_QUEUE(suspended_ccalling_threads)
+#endif
+#ifdef SMP
        && allFreeCapabilities()
-#elif defined(THREADED_RTS)
-       && suspended_ccalling_threads == END_TSO_QUEUE
 #endif
        )
     {
        IF_DEBUG(scheduler, sched_belch("deadlocked, forcing major GC..."));
+#if defined(THREADED_RTS)
+       /* and SMP mode ..? */
+       releaseCapability(cap);
+#endif
        RELEASE_LOCK(&sched_mutex);
        GarbageCollect(GetRoots,rtsTrue);
        ACQUIRE_LOCK(&sched_mutex);
-       IF_DEBUG(scheduler, sched_belch("GC done."));
-       if (blocked_queue_hd == END_TSO_QUEUE
-           && run_queue_hd == END_TSO_QUEUE
-           && sleeping_queue == END_TSO_QUEUE) {
+       if (   EMPTY_QUEUE(blocked_queue_hd)
+           && EMPTY_RUN_QUEUE()
+           && EMPTY_QUEUE(sleeping_queue) ) {
 
            IF_DEBUG(scheduler, sched_belch("still deadlocked, checking for black holes..."));
            detectBlackHoles();
@@ -669,7 +610,7 @@ schedule( void )
             * build, send *all* main threads the deadlock exception,
             * since none of them can make progress).
             */
-           if (run_queue_hd == END_TSO_QUEUE) {
+           if ( EMPTY_RUN_QUEUE() ) {
                StgMainThread *m;
 #if defined(RTS_SUPPORTS_THREADS)
                for (m = main_threads; m != NULL; m = m->link) {
@@ -701,13 +642,14 @@ schedule( void )
 #endif
            }
 #if defined(RTS_SUPPORTS_THREADS)
-           if ( run_queue_hd == END_TSO_QUEUE ) {
-             IF_DEBUG(scheduler, sched_belch("all done, it seems...shut down."));
+           /* ToDo: revisit conditions (and mechanism) for shutting
+              down a multi-threaded world  */
+           if ( EMPTY_RUN_QUEUE() ) {
+             IF_DEBUG(scheduler, sched_belch("all done, i think...shutting down."));
              shutdownHaskellAndExit(0);
-           
            }
 #endif
-           ASSERT( run_queue_hd != END_TSO_QUEUE );
+           ASSERT( !EMPTY_RUN_QUEUE() );
        }
     }
 #elif defined(PAR)
@@ -724,39 +666,27 @@ schedule( void )
     }
 #endif    
 
-#if defined(SMP)
+#if defined(RTS_SUPPORTS_THREADS)
     /* block until we've got a thread on the run queue and a free
      * capability.
+     *
      */
-    while ( run_queue_hd == END_TSO_QUEUE 
-           || noFreeCapabilities() 
-           ) {
-      IF_DEBUG(scheduler, sched_belch("waiting for work"));
-      waitCondition( &thread_ready_cond, &sched_mutex );
-      IF_DEBUG(scheduler, sched_belch("work now available"));
+    if ( EMPTY_RUN_QUEUE() ) {
+      /* Give up our capability */
+      releaseCapability(cap);
+      IF_DEBUG(scheduler, sched_belch("thread %d: waiting for work", osThreadId()));
+      waitForWorkCapability(&sched_mutex, &cap, rtsTrue);
+      IF_DEBUG(scheduler, sched_belch("thread %d: work now available", osThreadId()));
+#if 0
+      while ( EMPTY_RUN_QUEUE() ) {
+       waitForWorkCapability(&sched_mutex, &cap);
+       IF_DEBUG(scheduler, sched_belch("thread %d: work now available", osThreadId()));
+      }
+#endif
     }
-#elif defined(THREADED_RTS)
-   if ( run_queue_hd == END_TSO_QUEUE ) {
-     /* no work available, wait for external calls to complete. */
-     IF_DEBUG(scheduler, sched_belch("worker thread (%d): waiting for external thread to complete..", osThreadId()));
-     taskAvailable();
-     RELEASE_LOCK(&sched_mutex);
-     RELEASE_LOCK(&rts_mutex);
-
-     /* Sigh - need to have a mutex locked in order to wait on the
-        condition variable. */
-     ACQUIRE_LOCK(&thread_ready_aux_mutex);
-     waitCondition(&thread_ready_cond, &thread_ready_aux_mutex);
-     RELEASE_LOCK(&thread_ready_aux_mutex);
-
-     IF_DEBUG(scheduler, sched_belch("worker thread (%d): re-awakened from no-work slumber..\n", osThreadId()));
-     /* ToDo: longjmp() */
-     taskStart();
-   }
 #endif
 
 #if defined(GRAN)
-
     if (RtsFlags.GranFlags.Light)
       GranSimLight_enter_system(event, &ActiveTSO); // adjust ActiveTSO etc
 
@@ -1002,7 +932,7 @@ schedule( void )
             belch("--=^ %d threads, %d sparks on [%#x]", 
                   run_queue_len(), spark_queue_len(pool), CURRENT_PROC));
 
-#if 1
+# if 1
     if (0 && RtsFlags.ParFlags.ParStats.Full && 
        t && LastTSO && t->id != LastTSO->id && 
        LastTSO->why_blocked == NotBlocked && 
@@ -1027,11 +957,10 @@ schedule( void )
       emitSchedule = rtsFalse;
     }
      
-#endif
+# endif
 #else /* !GRAN && !PAR */
   
-    /* grab a thread from the run queue
-     */
+    /* grab a thread from the run queue */
     ASSERT(run_queue_hd != END_TSO_QUEUE);
     t = POP_RUN_QUEUE();
     // Sanity check the thread we're about to run.  This can be
@@ -1388,7 +1317,8 @@ schedule( void )
       barf("schedule: invalid thread return code %d", (int)ret);
     }
     
-#ifdef SMP
+#if defined(RTS_SUPPORTS_THREADS)
+    /* I don't understand what this re-grab is doing -- sof */
     grabCapability(&cap);
 #endif
 
@@ -1401,12 +1331,11 @@ schedule( void )
     }
 #endif
 
+    if (ready_to_gc 
 #ifdef SMP
-    if (ready_to_gc && allFreeCapabilities() )
-#else
-    if (ready_to_gc) 
+       && allFreeCapabilities() 
 #endif
-      {
+       ) {
       /* everybody back, start the GC.
        * Could do it in this thread, or signal a condition var
        * to do it in another thread.  Either way, we need to
@@ -1518,11 +1447,15 @@ suspendThread( StgRegTable *reg )
   cap->r.rCurrentTSO->link = suspended_ccalling_threads;
   suspended_ccalling_threads = cap->r.rCurrentTSO;
 
+#if defined(RTS_SUPPORTS_THREADS)
+  cap->r.rCurrentTSO->why_blocked  = BlockedOnCCall;
+#endif
+
   /* Use the thread ID as the token; it should be unique */
   tok = cap->r.rCurrentTSO->id;
 
   /* Hand back capability */
-  releaseCapability(&cap);
+  releaseCapability(cap);
   
 #if defined(RTS_SUPPORTS_THREADS) && !defined(SMP)
   /* Preparing to leave the RTS, so ensure there's a native thread/task
@@ -1532,13 +1465,12 @@ suspendThread( StgRegTable *reg )
      for one (i.e., if there's only one Concurrent Haskell thread alive,
      there's no need to create a new task).
   */
-  IF_DEBUG(scheduler, sched_belch("worker thread (%d): leaving RTS\n", tok));
+  IF_DEBUG(scheduler, sched_belch("worker thread (%d): leaving RTS", tok));
   startTask(taskStart);
-
 #endif
-  
+
+  THREAD_RUNNABLE();
   RELEASE_LOCK(&sched_mutex);
-  RELEASE_LOCK(&rts_mutex);
   return tok; 
 }
 
@@ -1548,23 +1480,11 @@ resumeThread( StgInt tok )
   StgTSO *tso, **prev;
   Capability *cap;
 
-#if defined(THREADED_RTS)
-  IF_DEBUG(scheduler, sched_belch("thread %d returning, waiting for sched. lock.\n", tok));
-  ACQUIRE_LOCK(&sched_mutex);
-  threads_waiting++;
-  IF_DEBUG(scheduler, sched_belch("thread %d returning, threads waiting: %d.\n", tok, threads_waiting));
-  RELEASE_LOCK(&sched_mutex);
-  
-  IF_DEBUG(scheduler, sched_belch("thread %d waiting for RTS lock...\n", tok));
-  ACQUIRE_LOCK(&rts_mutex);
-  threads_waiting--;
-  taskNotAvailable();
-  IF_DEBUG(scheduler, sched_belch("thread %d acquired RTS lock...\n", tok));
-#endif
-
-#if defined(THREADED_RTS)
-  /* Free up any RTS-blocked threads. */
-  broadcastCondition(&thread_ready_cond);
+#if defined(RTS_SUPPORTS_THREADS)
+  /* Wait for permission to re-enter the RTS with the result. */
+  grabReturnCapability(&sched_mutex, &cap);
+#else
+  grabCapability(&cap);
 #endif
 
   /* Remove the thread off of the suspended list */
@@ -1581,19 +1501,12 @@ resumeThread( StgInt tok )
     barf("resumeThread: thread not found");
   }
   tso->link = END_TSO_QUEUE;
+  /* Reset blocking status */
+  tso->why_blocked  = NotBlocked;
 
-#if defined(SMP)
-  while ( noFreeCapabilities() ) {
-    IF_DEBUG(scheduler, sched_belch("waiting to resume"));
-    waitCondition(&thread_ready_cond, &sched_mutex);
-    IF_DEBUG(scheduler, sched_belch("resuming thread %d", tso->id));
-  }
-#endif
-
-  grabCapability(&cap);
+  RELEASE_LOCK(&sched_mutex);
 
   cap->r.rCurrentTSO = tso;
-
   return &cap->r;
 }
 
@@ -1898,8 +1811,15 @@ activateSpark (rtsSpark spark)
  * on this thread's stack before the scheduler is invoked.
  * ------------------------------------------------------------------------ */
 
+static void scheduleThread_ (StgTSO* tso, rtsBool createTask);
+
 void
-scheduleThread(StgTSO *tso)
+scheduleThread_(StgTSO *tso
+              , rtsBool createTask
+#if !defined(THREADED_RTS)
+                STG_UNUSED
+#endif
+             )
 {
   ACQUIRE_LOCK(&sched_mutex);
 
@@ -1909,6 +1829,14 @@ scheduleThread(StgTSO *tso)
    * soon as we release the scheduler lock below.
    */
   PUSH_ON_RUN_QUEUE(tso);
+#if defined(THREADED_RTS)
+  /* If main() is scheduling a thread, don't bother creating a 
+   * new task.
+   */
+  if ( createTask ) {
+    startTask(taskStart);
+  }
+#endif
   THREAD_RUNNABLE();
 
 #if 0
@@ -1917,6 +1845,16 @@ scheduleThread(StgTSO *tso)
   RELEASE_LOCK(&sched_mutex);
 }
 
+void scheduleThread(StgTSO* tso)
+{
+  return scheduleThread_(tso, rtsFalse);
+}
+
+void scheduleExtThread(StgTSO* tso)
+{
+  return scheduleThread_(tso, rtsTrue);
+}
+
 /* ---------------------------------------------------------------------------
  * initScheduler()
  *
@@ -1974,26 +1912,22 @@ initScheduler(void)
 #if defined(RTS_SUPPORTS_THREADS)
   /* Initialise the mutex and condition variables used by
    * the scheduler. */
-  initMutex(&rts_mutex);
   initMutex(&sched_mutex);
   initMutex(&term_mutex);
-#if defined(THREADED_RTS)
-  initMutex(&thread_ready_aux_mutex);
+
+  initCondition(&thread_ready_cond);
 #endif
   
-  initCondition(&thread_ready_cond);
+#if defined(SMP)
   initCondition(&gc_pending_cond);
 #endif
 
-#if defined(THREADED_RTS)
-  /* Grab big lock */
-  ACQUIRE_LOCK(&rts_mutex);
-  IF_DEBUG(scheduler, 
-          sched_belch("worker thread (%d): acquired RTS lock\n", osThreadId()));
+#if defined(RTS_SUPPORTS_THREADS)
+  ACQUIRE_LOCK(&sched_mutex);
 #endif
 
   /* Install the SIGHUP handler */
-#ifdef SMP
+#if defined(SMP)
   {
     struct sigaction action,oact;
 
@@ -2024,6 +1958,11 @@ initScheduler(void)
 #if /* defined(SMP) ||*/ defined(PAR)
   initSparkPools();
 #endif
+
+#if defined(RTS_SUPPORTS_THREADS)
+  RELEASE_LOCK(&sched_mutex);
+#endif
+
 }
 
 void
@@ -2078,13 +2017,13 @@ finishAllThreads ( void )
 {
    do {
       while (run_queue_hd != END_TSO_QUEUE) {
-         waitThread ( run_queue_hd, NULL );
+         waitThread ( run_queue_hd, NULL);
       }
       while (blocked_queue_hd != END_TSO_QUEUE) {
-         waitThread ( blocked_queue_hd, NULL );
+         waitThread ( blocked_queue_hd, NULL);
       }
       while (sleeping_queue != END_TSO_QUEUE) {
-         waitThread ( blocked_queue_hd, NULL );
+         waitThread ( blocked_queue_hd, NULL);
       }
    } while 
       (blocked_queue_hd != END_TSO_QUEUE || 
@@ -2094,6 +2033,21 @@ finishAllThreads ( void )
 
 SchedulerStatus
 waitThread(StgTSO *tso, /*out*/StgClosure **ret)
+{ 
+#if defined(THREADED_RTS)
+  return waitThread_(tso,ret, rtsFalse);
+#else
+  return waitThread_(tso,ret);
+#endif
+}
+
+SchedulerStatus
+waitThread_(StgTSO *tso,
+           /*out*/StgClosure **ret
+#if defined(THREADED_RTS)
+           , rtsBool blockWaiting
+#endif
+          )
 {
   StgMainThread *m;
   SchedulerStatus stat;
@@ -2112,13 +2066,27 @@ waitThread(StgTSO *tso, /*out*/StgClosure **ret)
   m->link = main_threads;
   main_threads = m;
 
-  IF_DEBUG(scheduler, fprintf(stderr, "== scheduler: new main thread (%d)\n", 
-                             m->tso->id));
+  IF_DEBUG(scheduler, sched_belch("== scheduler: new main thread (%d)\n", m->tso->id));
 
-#ifdef SMP
-  do {
-    waitCondition(&m->wakeup, &sched_mutex);
-  } while (m->stat == NoStatus);
+#if defined(RTS_SUPPORTS_THREADS)
+
+# if defined(THREADED_RTS)
+  if (!blockWaiting) {
+    /* In the threaded case, the OS thread that called main()
+     * gets to enter the RTS directly without going via another
+     * task/thread.
+     */
+    RELEASE_LOCK(&sched_mutex);
+    schedule();
+    ASSERT(m->stat != NoStatus);
+  } else 
+# endif
+  {
+    IF_DEBUG(scheduler, sched_belch("sfoo"));
+    do {
+      waitCondition(&m->wakeup, &sched_mutex);
+    } while (m->stat == NoStatus);
+  }
 #elif defined(GRAN)
   /* GranSim specific init */
   CurrentTSO = m->tso;                // the TSO to run
@@ -2142,7 +2110,10 @@ waitThread(StgTSO *tso, /*out*/StgClosure **ret)
                              m->tso->id));
   free(m);
 
-  RELEASE_LOCK(&sched_mutex);
+#if defined(THREADED_RTS)
+  if (blockWaiting) 
+#endif
+    RELEASE_LOCK(&sched_mutex);
 
   return stat;
 }
@@ -3101,51 +3072,39 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
     StgAP_UPD * ap;
 
     /* If we find a CATCH_FRAME, and we've got an exception to raise,
-     * then build PAP(handler,exception,realworld#), and leave it on
-     * top of the stack ready to enter.
+     * then build the THUNK raise(exception), and leave it on
+     * top of the CATCH_FRAME ready to enter.
      */
     if (get_itbl(su)->type == CATCH_FRAME && exception != NULL) {
       StgCatchFrame *cf = (StgCatchFrame *)su;
+      StgClosure *raise;
+
       /* we've got an exception to raise, so let's pass it to the
        * handler in this frame.
        */
-      ap = (StgAP_UPD *)allocate(sizeofW(StgPAP) + 2);
-      TICK_ALLOC_UPD_PAP(3,0);
-      SET_HDR(ap,&stg_PAP_info,cf->header.prof.ccs);
-             
-      ap->n_args = 2;
-      ap->fun = cf->handler;   /* :: Exception -> IO a */
-      ap->payload[0] = exception;
-      ap->payload[1] = ARG_TAG(0); /* realworld token */
-
-      /* throw away the stack from Sp up to and including the
-       * CATCH_FRAME.
-       */
-      sp = (P_)su + sizeofW(StgCatchFrame) - 1; 
-      tso->su = cf->link;
-
-      /* Restore the blocked/unblocked state for asynchronous exceptions
-       * at the CATCH_FRAME.  
-       *
-       * If exceptions were unblocked at the catch, arrange that they
-       * are unblocked again after executing the handler by pushing an
-       * unblockAsyncExceptions_ret stack frame.
+      raise = (StgClosure *)allocate(sizeofW(StgClosure)+1);
+      TICK_ALLOC_SE_THK(1,0);
+      SET_HDR(raise,&stg_raise_info,cf->header.prof.ccs);
+      raise->payload[0] = exception;
+
+      /* throw away the stack from Sp up to the CATCH_FRAME.
        */
-      if (!cf->exceptions_blocked) {
-       *(sp--) = (W_)&stg_unblockAsyncExceptionszh_ret_info;
-      }
-      
-      /* Ensure that async exceptions are blocked when running the handler.
+      sp = (P_)su - 1;
+
+      /* Ensure that async excpetions are blocked now, so we don't get
+       * a surprise exception before we get around to executing the
+       * handler.
        */
       if (tso->blocked_exceptions == NULL) {
-       tso->blocked_exceptions = END_TSO_QUEUE;
+         tso->blocked_exceptions = END_TSO_QUEUE;
       }
-      
-      /* Put the newly-built PAP on top of the stack, ready to execute
+
+      /* Put the newly-built THUNK on top of the stack, ready to execute
        * when the thread restarts.
        */
-      sp[0] = (W_)ap;
+      sp[0] = (W_)raise;
       tso->sp = sp;
+      tso->su = su;
       tso->what_next = ThreadEnterGHC;
       IF_DEBUG(sanity, checkTSO(tso));
       return;
@@ -3417,6 +3376,11 @@ printThreadBlockage(StgTSO *tso)
            tso->block_info.closure, info_type(tso->block_info.closure));
     break;
 #endif
+#if defined(RTS_SUPPORTS_THREADS)
+  case BlockedOnCCall:
+    fprintf(stderr,"is blocked on an external call");
+    break;
+#endif
   default:
     barf("printThreadBlockage: strange tso->why_blocked: %d for TSO %d (%d)",
         tso->why_blocked, tso->id, tso);
@@ -3657,7 +3621,6 @@ sched_belch(char *s, ...)
 //@subsection Index
 
 //@index
-//* MainRegTable::  @cindex\s-+MainRegTable
 //* StgMainThread::  @cindex\s-+StgMainThread
 //* awaken_blocked_queue::  @cindex\s-+awaken_blocked_queue
 //* blocked_queue_hd::  @cindex\s-+blocked_queue_hd
@@ -3675,5 +3638,4 @@ sched_belch(char *s, ...)
 //* schedule::  @cindex\s-+schedule
 //* take_off_run_queue::  @cindex\s-+take_off_run_queue
 //* term_mutex::  @cindex\s-+term_mutex
-//* thread_ready_cond::  @cindex\s-+thread_ready_cond
 //@end index