[project @ 2000-03-14 09:55:05 by simonmar]
[ghc-hetmet.git] / ghc / rts / Schedule.c
index 9b7cdf4..e3100ef 100644 (file)
@@ -1,7 +1,7 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.42 2000/01/14 11:45:21 hwloidl Exp $
+ * $Id: Schedule.c,v 1.52 2000/03/14 09:55:05 simonmar Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2000
  *
  * Scheduler
  *
@@ -72,6 +72,7 @@
 #include "Sanity.h"
 #include "Stats.h"
 #include "Sparks.h"
+#include "Prelude.h"
 #if defined(GRAN) || defined(PAR)
 # include "GranSimRts.h"
 # include "GranSim.h"
@@ -121,28 +122,10 @@ static StgMainThread *main_threads;
  * Locks required: sched_mutex.
  */
 
-#if DEBUG
-char *whatNext_strs[] = {
-  "ThreadEnterGHC",
-  "ThreadRunGHC",
-  "ThreadEnterHugs",
-  "ThreadKilled",
-  "ThreadComplete"
-};
-
-char *threadReturnCode_strs[] = {
-  "HeapOverflow",                      /* might also be StackOverflow */
-  "StackOverflow",
-  "ThreadYielding",
-  "ThreadBlocked",
-  "ThreadFinished"
-};
-#endif
-
 #if defined(GRAN)
 
 StgTSO* ActiveTSO = NULL; /* for assigning system costs; GranSim-Light only */
-// rtsTime TimeOfNextEvent, EndOfTimeSlice;            now in GranSim.c
+/* rtsTime TimeOfNextEvent, EndOfTimeSlice;            now in GranSim.c */
 
 /* 
    In GranSim we have a runable and a blocked queue for each processor.
@@ -276,16 +259,6 @@ StgTSO   *MainTSO;
 //@node Prototypes, Main scheduling loop, Variables and Data structures, Main scheduling code
 //@subsection Prototypes
 
-#if 0 && defined(GRAN)
-// ToDo: replace these with macros
-static /* inline */ void    add_to_run_queue(StgTSO* tso); 
-static /* inline */ void    push_on_run_queue(StgTSO* tso); 
-static /* inline */ StgTSO *take_off_run_queue(StgTSO *tso);
-
-/* Thread management */
-void initScheduler(void);
-#endif
-
 //@node Main scheduling loop, Suspend and Resume, Prototypes, Main scheduling code
 //@subsection Main scheduling loop
 
@@ -323,6 +296,7 @@ schedule( void )
   StgTSO *tso;
   GlobalTaskId pe;
 #endif
+  rtsBool was_interrupted = rtsFalse;
   
   ACQUIRE_LOCK(&sched_mutex);
 
@@ -352,6 +326,8 @@ schedule( void )
       }
       run_queue_hd = run_queue_tl = END_TSO_QUEUE;
       blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
+      interrupted = rtsFalse;
+      was_interrupted = rtsTrue;
     }
 
     /* Go through the list of main threads and wake up any
@@ -375,7 +351,11 @@ schedule( void )
          break;
        case ThreadKilled:
          *prev = m->link;
-         m->stat = Killed;
+         if (was_interrupted) {
+           m->stat = Interrupted;
+         } else {
+           m->stat = Killed;
+         }
          pthread_cond_broadcast(&m->wakeup);
          break;
        default:
@@ -397,7 +377,11 @@ schedule( void )
          m->stat = Success;
          return;
        } else {
-         m->stat = Killed;
+         if (was_interrupted) {
+           m->stat = Interrupted;
+         } else {
+           m->stat = Killed;
+         }
          return;
        }
       }
@@ -425,7 +409,9 @@ schedule( void )
        if (spark == NULL) {
          break; /* no more sparks in the pool */
        } else {
-         // I'd prefer this to be done in activateSpark -- HWL
+         /* I'd prefer this to be done in activateSpark -- HWL */
+         /* tricky - it needs to hold the scheduler lock and
+          * not try to re-acquire it -- SDM */
          StgTSO *tso;
          tso = createThread_(RtsFlags.GcFlags.initialStkSize, rtsTrue);
          pushClosure(tso,spark);
@@ -521,7 +507,7 @@ schedule( void )
 #if defined(GRAN)
 # error ToDo: implement GranSim scheduler
 #elif defined(PAR)
-    // ToDo: phps merge with spark activation above
+    /* ToDo: phps merge with spark activation above */
     /* check whether we have local work and send requests if we have none */
     if (run_queue_hd == END_TSO_QUEUE) {  /* no runnable threads */
       /* :-[  no local threads => look out for local sparks */
@@ -544,10 +530,10 @@ schedule( void )
                       belch("== [%x] schedule: Created TSO %p (%d); %d threads active",
                             mytid, tso, tso->id, advisory_thread_count));
 
-         if (tso==END_TSO_QUEUE) { // failed to activate spark -> back to loop
+         if (tso==END_TSO_QUEUE) { /* failed to activate spark->back to loop */
            belch("^^ failed to activate spark");
            goto next_thread;
-         }                         // otherwise fall through & pick-up new tso
+         }               /* otherwise fall through & pick-up new tso */
        } else {
          IF_PAR_DEBUG(verbose,
                       belch("^^ no local sparks (spark pool contains only NFs: %d)", 
@@ -623,6 +609,7 @@ schedule( void )
     /* grab a thread from the run queue
      */
     t = POP_RUN_QUEUE();
+    IF_DEBUG(sanity,checkTSO(t));
 
 #endif
     
@@ -723,13 +710,14 @@ schedule( void )
        
        /* This TSO has moved, so update any pointers to it from the
         * main thread stack.  It better not be on any other queues...
-        * (it shouldn't be)
+        * (it shouldn't be).
         */
        for (m = main_threads; m != NULL; m = m->link) {
          if (m->tso == t) {
            m->tso = new_t;
          }
        }
+       threadPaused(new_t);
        PUSH_ON_RUN_QUEUE(new_t);
       }
       break;
@@ -1509,21 +1497,6 @@ take_off_run_queue(StgTSO *tso) {
 
 #endif /* 0 */
 
-nat
-run_queue_len(void)
-{
-  nat i;
-  StgTSO *tso;
-
-  for (i=0, tso=run_queue_hd; 
-       tso != END_TSO_QUEUE;
-       i++, tso=tso->link)
-    /* nothing */
-
-  return i;
-}
-
-
 //@node Garbage Collextion Routines, Blocking Queue Routines, Run queue code, Main scheduling code
 //@subsection Garbage Collextion Routines
 
@@ -1545,30 +1518,28 @@ run_queue_len(void)
 static void GetRoots(void)
 {
   StgMainThread *m;
-  nat i;
 
 #if defined(GRAN)
-  for (i=0; i<=RtsFlags.GranFlags.proc; i++) {
-    if ((run_queue_hds[i] != END_TSO_QUEUE) && ((run_queue_hds[i] != NULL)))
-      run_queue_hds[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_hds[i]);
-    if ((run_queue_tls[i] != END_TSO_QUEUE) && ((run_queue_tls[i] != NULL)))
-      run_queue_tls[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_tls[i]);
-    
-    if ((blocked_queue_hds[i] != END_TSO_QUEUE) && ((blocked_queue_hds[i] != NULL)))
-      blocked_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hds[i]);
-    if ((blocked_queue_tls[i] != END_TSO_QUEUE) && ((blocked_queue_tls[i] != NULL)))
-      blocked_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tls[i]);
-    if ((ccalling_threadss[i] != END_TSO_QUEUE) && ((ccalling_threadss[i] != NULL)))
-      ccalling_threadss[i] = (StgTSO *)MarkRoot((StgClosure *)ccalling_threadss[i]);
+  {
+    nat i;
+    for (i=0; i<=RtsFlags.GranFlags.proc; i++) {
+      if ((run_queue_hds[i] != END_TSO_QUEUE) && ((run_queue_hds[i] != NULL)))
+       run_queue_hds[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_hds[i]);
+      if ((run_queue_tls[i] != END_TSO_QUEUE) && ((run_queue_tls[i] != NULL)))
+       run_queue_tls[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_tls[i]);
+      
+      if ((blocked_queue_hds[i] != END_TSO_QUEUE) && ((blocked_queue_hds[i] != NULL)))
+       blocked_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hds[i]);
+      if ((blocked_queue_tls[i] != END_TSO_QUEUE) && ((blocked_queue_tls[i] != NULL)))
+       blocked_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tls[i]);
+      if ((ccalling_threadss[i] != END_TSO_QUEUE) && ((ccalling_threadss[i] != NULL)))
+       ccalling_threadss[i] = (StgTSO *)MarkRoot((StgClosure *)ccalling_threadss[i]);
+    }
   }
 
   markEventQueue();
-#elif defined(PAR)
-  run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
-  run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
-  blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
-  blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
-#else
+
+#else /* !GRAN */
   run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
   run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
 
@@ -1626,9 +1597,10 @@ performGCWithRoots(void (*get_roots)(void))
 /* -----------------------------------------------------------------------------
    Stack overflow
 
-   If the thread has reached its maximum stack size,
-   then bomb out.  Otherwise relocate the TSO into a larger chunk of
-   memory and adjust its stack size appropriately.
+   If the thread has reached its maximum stack size, then raise the
+   StackOverflow exception in the offending thread.  Otherwise
+   relocate the TSO into a larger chunk of memory and adjust its stack
+   size appropriately.
    -------------------------------------------------------------------------- */
 
 static StgTSO *
@@ -1638,6 +1610,7 @@ threadStackOverflow(StgTSO *tso)
   StgPtr new_sp;
   StgTSO *dest;
 
+  IF_DEBUG(sanity,checkTSO(tso));
   if (tso->stack_size >= tso->max_stack_size) {
 #if 0
     /* If we're debugging, just print out the top of the stack */
@@ -1649,7 +1622,7 @@ threadStackOverflow(StgTSO *tso)
     exit(1);
 #else
     /* Send this thread the StackOverflow exception */
-    raiseAsync(tso, (StgClosure *)&stackOverflow_closure);
+    raiseAsync(tso, (StgClosure *)stackOverflow_closure);
 #endif
     return tso;
   }
@@ -1685,14 +1658,15 @@ threadStackOverflow(StgTSO *tso)
   /* and relocate the update frame list */
   relocate_TSO(tso, dest);
 
-  /* Mark the old one as dead so we don't try to scavenge it during
-   * garbage collection (the TSO will likely be on a mutables list in
-   * some generation, but it'll get collected soon enough).  It's
-   * important to set the sp and su values to just beyond the end of
-   * the stack, so we don't attempt to scavenge any part of the dead
-   * TSO's stack.
+  /* Mark the old TSO as relocated.  We have to check for relocated
+   * TSOs in the garbage collector and any primops that deal with TSOs.
+   *
+   * It's important to set the sp and su values to just beyond the end
+   * of the stack, so we don't attempt to scavenge any part of the
+   * dead TSO's stack.
    */
-  tso->whatNext = ThreadKilled;
+  tso->whatNext = ThreadRelocated;
+  tso->link = dest;
   tso->sp = (P_)&(tso->stack[tso->stack_size]);
   tso->su = (StgUpdateFrame *)tso->sp;
   tso->why_blocked = NotBlocked;
@@ -1703,12 +1677,6 @@ threadStackOverflow(StgTSO *tso)
   IF_DEBUG(scheduler,printTSO(dest));
 #endif
 
-#if 0
-  /* This will no longer work: KH */
-  if (tso == MainTSO) { /* hack */
-      MainTSO = dest;
-  }
-#endif
   return dest;
 }
 
@@ -1719,7 +1687,7 @@ threadStackOverflow(StgTSO *tso)
    Wake up a queue that was blocked on some resource.
    ------------------------------------------------------------------------ */
 
-// ToDo: check push_on_run_queue vs. PUSH_ON_RUN_QUEUE
+/* ToDo: check push_on_run_queue vs. PUSH_ON_RUN_QUEUE */
 
 #if defined(GRAN)
 static inline void
@@ -1878,16 +1846,7 @@ unblockOneLocked(StgTSO *tso)
 }
 #endif
 
-#if defined(GRAN)
-inline StgTSO *
-unblockOne(StgTSO *tso, StgClosure *node)
-{
-  ACQUIRE_LOCK(&sched_mutex);
-  tso = unblockOneLocked(tso, node);
-  RELEASE_LOCK(&sched_mutex);
-  return tso;
-}
-#elif defined(PAR)
+#if defined(PAR) || defined(GRAN)
 inline StgTSO *
 unblockOne(StgTSO *tso, StgClosure *node)
 {
@@ -2009,266 +1968,6 @@ awakenBlockedQueue(StgTSO *tso)
 }
 #endif
 
-#if 0
-// ngoq ngo'
-
-#if defined(GRAN)
-/* 
-   Awakening a blocking queue in GranSim means checking for each of the
-   TSOs in the queue whether they are local or not, issuing a ResumeThread
-   or an UnblockThread event, respectively. The basic iteration over the
-   blocking queue is the same as in the standard setup.  
-*/
-void
-awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node)
-{
-  StgBlockingQueueElement *bqe, *next;
-  StgTSO *tso;
-  PEs node_loc, tso_loc;
-  rtsTime bq_processing_time = 0;
-  nat len = 0, len_local = 0;
-
-  IF_GRAN_DEBUG(bq, 
-               belch("## AwBQ for node %p on PE %d @ %ld by TSO %d (%p): ", \
-                     node, CurrentProc, CurrentTime[CurrentProc], 
-                     CurrentTSO->id, CurrentTSO));
-
-  node_loc = where_is(node);
-
-  ASSERT(get_itbl(q)->type == TSO ||   // q is either a TSO or an RBHSave
-        get_itbl(q)->type == CONSTR); // closure (type constructor)
-  ASSERT(is_unique(node));
-
-  /* FAKE FETCH: magically copy the node to the tso's proc;
-     no Fetch necessary because in reality the node should not have been 
-     moved to the other PE in the first place
-  */
-  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)",
-                       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",
-                       node, node->header.gran.procs));
-    if (RtsFlags.GranFlags.GranSimStats.Global) {
-      globalGranStats.tot_fake_fetches++;
-    }
-  }
-
-  next = q;
-  // ToDo: check: ASSERT(CurrentProc==node_loc);
-  while (get_itbl(next)->type==TSO) { // q != END_TSO_QUEUE) {
-    bqe = next;
-    next = bqe->link;
-    /* 
-       bqe points to the current element in the queue
-       next points to the next element in the queue
-    */
-    tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
-    tso_loc = where_is(tso);
-    if (IS_LOCAL_TO(PROCS(node),tso_loc)) { // TSO is local
-      /* !fake_fetch => TSO is on CurrentProc is same as IS_LOCAL_TO */
-      ASSERT(CurrentProc!=node_loc || tso_loc==CurrentProc);
-      bq_processing_time += RtsFlags.GranFlags.Costs.lunblocktime;
-      // insertThread(tso, node_loc);
-      new_event(tso_loc, tso_loc,
-               CurrentTime[CurrentProc]+bq_processing_time,
-               ResumeThread,
-               tso, node, (rtsSpark*)NULL);
-      tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
-      len_local++;
-      len++;
-    } else { // TSO is remote (actually should be FMBQ)
-      bq_processing_time += RtsFlags.GranFlags.Costs.mpacktime;
-      bq_processing_time += RtsFlags.GranFlags.Costs.gunblocktime;
-      new_event(tso_loc, CurrentProc, 
-               CurrentTime[CurrentProc]+bq_processing_time+
-               RtsFlags.GranFlags.Costs.latency,
-               UnblockThread,
-               tso, node, (rtsSpark*)NULL);
-      tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
-      bq_processing_time += RtsFlags.GranFlags.Costs.mtidytime;
-      len++;
-    }      
-    /* the thread-queue-overhead is accounted for in either Resume or UnblockThread */
-    IF_GRAN_DEBUG(bq,
-                 fprintf(stderr," %s TSO %d (%p) [PE %d] (blocked_on=%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)", 
-                            tso->id, tso));
-  }
-
-  /* if this is the BQ of an RBH, we have to put back the info ripped out of
-     the closure to make room for the anchor of the BQ */
-  if (next!=END_BQ_QUEUE) {
-    ASSERT(get_itbl(node)->type == RBH && get_itbl(next)->type == CONSTR);
-    /*
-    ASSERT((info_ptr==&RBH_Save_0_info) ||
-          (info_ptr==&RBH_Save_1_info) ||
-          (info_ptr==&RBH_Save_2_info));
-    */
-    /* cf. convertToRBH in RBH.c for writing the RBHSave closure */
-    ((StgRBH *)node)->blocking_queue = ((StgRBHSave *)next)->payload[0];
-    ((StgRBH *)node)->mut_link       = ((StgRBHSave *)next)->payload[1];
-
-    IF_GRAN_DEBUG(bq,
-                 belch("## Filled in RBH_Save for %p (%s) at end of AwBQ",
-                       node, info_type(node)));
-  }
-
-  /* statistics gathering */
-  if (RtsFlags.GranFlags.GranSimStats.Global) {
-    globalGranStats.tot_bq_processing_time += bq_processing_time;
-    globalGranStats.tot_bq_len += len;      // total length of all bqs awakened
-    globalGranStats.tot_bq_len_local += len_local;  // same for local TSOs only
-    globalGranStats.tot_awbq++;             // total no. of bqs awakened
-  }
-  IF_GRAN_DEBUG(bq,
-               fprintf(stderr,"## BQ Stats of %p: [%d entries, %d local] %s\n",
-                       node, len, len_local, (next!=END_TSO_QUEUE) ? "RBH" : ""));
-}
-
-#elif defined(PAR)
-
-/*
-  Awakening a blocking queue in GUM has to check whether an entry in the
-  queue is a normal TSO or a BLOCKED_FETCH. The later indicates that a TSO is
-  waiting for the result of this computation on another PE. Thus, when
-  finding a BLOCKED_FETCH we have to send off a message to that PE. 
-  Actually, we defer sending off a message, by just putting the BLOCKED_FETCH
-  onto the PendingFetches queue, which will be later traversed by
-  processFetches, sending off a RESUME message for each BLOCKED_FETCH.
-
-  NB: There is no check for an RBHSave closure (type CONSTR) in the code 
-      below. The reason is, if we awaken the BQ of an RBH closure (RBHSaves 
-      only exist at the end of such BQs) we know that the closure has been
-      unpacked successfully on the other PE, and we can discard the info
-      contained in the RBHSave closure. The current closure will be turned 
-      into a FetchMe closure anyway.
-*/
-void 
-awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node)
-{
-  StgBlockingQueueElement *bqe, *next;
-
-  IF_PAR_DEBUG(verbose, 
-              belch("## AwBQ for node %p on [%x]: ",
-                    node, mytid));
-
-  ASSERT(get_itbl(q)->type == TSO ||           
-        get_itbl(q)->type == BLOCKED_FETCH || 
-        get_itbl(q)->type == CONSTR); 
-
-  next = q;
-  while (get_itbl(next)->type==TSO || 
-        get_itbl(next)->type==BLOCKED_FETCH) {
-    bqe = next;
-    switch (get_itbl(bqe)->type) {
-    case TSO:
-      /* if it's a TSO just push it onto the run_queue */
-      next = bqe->link;
-#if defined(DEBUG)
-      ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging only
-#endif
-      push_on_run_queue((StgTSO *)bqe); // HWL: was: PUSH_ON_RUN_QUEUE(tso);
-
-      /* write RESUME events to log file and
-        update blocked and fetch time (depending on type of the orig closure) */
-      if (RtsFlags.ParFlags.ParStats.Full) {
-       DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC, 
-                        GR_RESUMEQ, ((StgTSO *)bqe), ((StgTSO *)bqe)->block_info.closure,
-                        0, spark_queue_len(ADVISORY_POOL));
-
-       switch (get_itbl(node)->type) {
-       case FETCH_ME_BQ:
-         ((StgTSO *)bqe)->par.fetchtime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
-         break;
-       case RBH:
-       case FETCH_ME:
-       case BLACKHOLE_BQ:
-         ((StgTSO *)bqe)->par.blocktime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
-         break;
-       default:
-         barf("{awaken_blocked_queue}Daq Qagh: unexpected closure %p (%s) with blocking queue",
-              node, info_type(node));
-       }
-      }
-      /* reset block_info.closure field after dumping event */
-      ((StgTSO *)bqe)->block_info.closure = NULL;
-
-      /* rest of this branch is debugging only */
-      IF_PAR_DEBUG(verbose,
-                  fprintf(stderr," TSO %d (%p) [PE %lx] (block_info.closure=%p) (next=%p) ,",
-                          ((StgTSO *)bqe)->id, (StgTSO *)bqe,
-                          mytid, ((StgTSO *)bqe)->block_info.closure, ((StgTSO *)bqe)->link));
-
-      IF_DEBUG(scheduler,
-              if (!RtsFlags.ParFlags.Debug.verbose)
-                belch("-- Waking up thread %ld (%p)", 
-                      ((StgTSO *)bqe)->id, (StgTSO *)bqe));
-      break;
-
-    case BLOCKED_FETCH:
-      /* if it's a BLOCKED_FETCH put it on the PendingFetches list */
-      next = bqe->link;
-      bqe->link = PendingFetches;
-      PendingFetches = bqe;
-      // bqe.tso->block_info.closure = NULL;
-
-      /* rest of this branch is debugging only */
-      IF_PAR_DEBUG(verbose,
-                  fprintf(stderr," BLOCKED_FETCH (%p) on node %p [PE %lx] (next=%p) ,",
-                          ((StgBlockedFetch *)bqe), 
-                          ((StgBlockedFetch *)bqe)->node, 
-                          mytid, ((StgBlockedFetch *)bqe)->link));
-      break;
-
-# if defined(DEBUG)
-      /* can ignore this case in a non-debugging setup; 
-        see comments on RBHSave closures above */
-    case CONSTR:
-      /* check that the closure is an RBHSave closure */
-      ASSERT(get_itbl((StgClosure *)bqe) == &RBH_Save_0_info ||
-            get_itbl((StgClosure *)bqe) == &RBH_Save_1_info ||
-            get_itbl((StgClosure *)bqe) == &RBH_Save_2_info);
-      break;
-
-    default:
-      barf("{awaken_blocked_queue}Daq Qagh: Unexpected IP (%#lx; %s) in blocking queue at %#lx\n",
-          get_itbl((StgClosure *)bqe), info_type((StgClosure *)bqe), 
-          (StgClosure *)bqe);
-# endif
-    }
-  }
-}
-
-#else /* !GRAN && !PAR */
-
-void 
-awaken_blocked_queue(StgTSO *q) { awakenBlockedQueue(q); }
-
-/*
-{
-  StgTSO *tso;
-
-  while (q != END_TSO_QUEUE) {
-    ASSERT(get_itbl(q)->type == TSO);
-    tso = q;
-    q = tso->link;
-    push_on_run_queue(tso); // HWL: was: PUSH_ON_RUN_QUEUE(tso);
-    //tso->block_info.closure = NULL;
-    IF_DEBUG(scheduler, belch("-- Waking up thread %ld (%p)", tso->id, tso));
-  }
-}
-*/
-#endif /* GRAN */
-#endif /* 0 */
-
 //@node Exception Handling Routines, Debugging Routines, Blocking Queue Routines, Main scheduling code
 //@subsection Exception Handling Routines
 
@@ -2464,25 +2163,27 @@ 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), and leave it on top of
-     * the stack ready to enter.
+     * then build PAP(handler,exception,realworld#), and leave it on
+     * top of the stack ready to enter.
      */
     if (get_itbl(su)->type == CATCH_FRAME && exception != NULL) {
       StgCatchFrame *cf = (StgCatchFrame *)su;
       /* we've got an exception to raise, so let's pass it to the
        * handler in this frame.
        */
-      ap = (StgAP_UPD *)allocate(sizeofW(StgPAP) + 1);
-      TICK_ALLOC_UPD_PAP(2,0);
+      ap = (StgAP_UPD *)allocate(sizeofW(StgPAP) + 2);
+      TICK_ALLOC_UPD_PAP(3,0);
       SET_HDR(ap,&PAP_info,cf->header.prof.ccs);
              
-      ap->n_args = 1;
-      ap->fun = cf->handler;
+      ap->n_args = 2;
+      ap->fun = cf->handler;   /* :: Exception -> IO a */
       ap->payload[0] = (P_)exception;
+      ap->payload[1] = ARG_TAG(0); /* realworld token */
 
-      /* sp currently points to the word above the CATCH_FRAME on the stack.
+      /* throw away the stack from Sp up to and including the
+       * CATCH_FRAME.
        */
-      sp += sizeofW(StgCatchFrame);
+      sp = (P_)su + sizeofW(StgCatchFrame) - 1; 
       tso->su = cf->link;
 
       /* Restore the blocked/unblocked state for asynchronous exceptions
@@ -2796,26 +2497,27 @@ print_bq (StgClosure *node)
   for (tso = ((StgBlockingQueue*)node)->blocking_queue;
        tso != END_TSO_QUEUE; 
        tso=tso->link) {
-    ASSERT(tso!=(StgTSO*)NULL && tso!=END_TSO_QUEUE);   // sanity check
+    ASSERT(tso!=NULL && tso!=END_TSO_QUEUE);   // sanity check
     ASSERT(get_itbl(tso)->type == TSO);  // guess what, sanity check
-    fprintf(stderr," TSO %d (%x),", tso->id, tso);
+    fprintf(stderr," TSO %d (%p),", tso->id, tso);
   }
   fputc('\n', stderr);
 }
 # endif
 
-/* A debugging function used all over the place in GranSim and GUM.
-   Dummy function in other setups.
-*/
-# if !defined(GRAN) && !defined(PAR)
-char *
-info_type(StgClosure *closure){ 
-  return "petaQ";
-}
+#if defined(PAR)
+static nat
+run_queue_len(void)
+{
+  nat i;
+  StgTSO *tso;
 
-char *
-info_type_by_ip(StgInfoTable *ip){ 
-  return "petaQ";
+  for (i=0, tso=run_queue_hd; 
+       tso != END_TSO_QUEUE;
+       i++, tso=tso->link)
+    /* nothing */
+
+  return i;
 }
 #endif