[project @ 2000-01-14 13:17:15 by hwloidl]
[ghc-hetmet.git] / ghc / rts / Schedule.c
1 /* ---------------------------------------------------------------------------
2  * $Id: Schedule.c,v 1.43 2000/01/14 13:17:16 hwloidl Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Scheduler
7  *
8  * The main scheduling code in GranSim is quite different from that in std
9  * (concurrent) Haskell: while concurrent Haskell just iterates over the
10  * threads in the runnable queue, GranSim is event driven, i.e. it iterates
11  * over the events in the global event queue.  -- HWL
12  * --------------------------------------------------------------------------*/
13
14 //@node Main scheduling code, , ,
15 //@section Main scheduling code
16
17 /* Version with scheduler monitor support for SMPs.
18
19    This design provides a high-level API to create and schedule threads etc.
20    as documented in the SMP design document.
21
22    It uses a monitor design controlled by a single mutex to exercise control
23    over accesses to shared data structures, and builds on the Posix threads
24    library.
25
26    The majority of state is shared.  In order to keep essential per-task state,
27    there is a Capability structure, which contains all the information
28    needed to run a thread: its STG registers, a pointer to its TSO, a
29    nursery etc.  During STG execution, a pointer to the capability is
30    kept in a register (BaseReg).
31
32    In a non-SMP build, there is one global capability, namely MainRegTable.
33
34    SDM & KH, 10/99
35 */
36
37 //@menu
38 //* Includes::                  
39 //* Variables and Data structures::  
40 //* Prototypes::                
41 //* Main scheduling loop::      
42 //* Suspend and Resume::        
43 //* Run queue code::            
44 //* Garbage Collextion Routines::  
45 //* Blocking Queue Routines::   
46 //* Exception Handling Routines::  
47 //* Debugging Routines::        
48 //* Index::                     
49 //@end menu
50
51 //@node Includes, Variables and Data structures, Main scheduling code, Main scheduling code
52 //@subsection Includes
53
54 #include "Rts.h"
55 #include "SchedAPI.h"
56 #include "RtsUtils.h"
57 #include "RtsFlags.h"
58 #include "Storage.h"
59 #include "StgRun.h"
60 #include "StgStartup.h"
61 #include "GC.h"
62 #include "Hooks.h"
63 #include "Schedule.h"
64 #include "StgMiscClosures.h"
65 #include "Storage.h"
66 #include "Evaluator.h"
67 #include "Exception.h"
68 #include "Printer.h"
69 #include "Main.h"
70 #include "Signals.h"
71 #include "Profiling.h"
72 #include "Sanity.h"
73 #include "Stats.h"
74 #include "Sparks.h"
75 #if defined(GRAN) || defined(PAR)
76 # include "GranSimRts.h"
77 # include "GranSim.h"
78 # include "ParallelRts.h"
79 # include "Parallel.h"
80 # include "ParallelDebug.h"
81 # include "FetchMe.h"
82 # include "HLC.h"
83 #endif
84
85 #include <stdarg.h>
86
87 //@node Variables and Data structures, Prototypes, Includes, Main scheduling code
88 //@subsection Variables and Data structures
89
90 /* Main threads:
91  *
92  * These are the threads which clients have requested that we run.  
93  *
94  * In an SMP build, we might have several concurrent clients all
95  * waiting for results, and each one will wait on a condition variable
96  * until the result is available.
97  *
98  * In non-SMP, clients are strictly nested: the first client calls
99  * into the RTS, which might call out again to C with a _ccall_GC, and
100  * eventually re-enter the RTS.
101  *
102  * Main threads information is kept in a linked list:
103  */
104 //@cindex StgMainThread
105 typedef struct StgMainThread_ {
106   StgTSO *         tso;
107   SchedulerStatus  stat;
108   StgClosure **    ret;
109 #ifdef SMP
110   pthread_cond_t wakeup;
111 #endif
112   struct StgMainThread_ *link;
113 } StgMainThread;
114
115 /* Main thread queue.
116  * Locks required: sched_mutex.
117  */
118 static StgMainThread *main_threads;
119
120 /* Thread queues.
121  * Locks required: sched_mutex.
122  */
123
124 #if DEBUG
125 char *whatNext_strs[] = {
126   "ThreadEnterGHC",
127   "ThreadRunGHC",
128   "ThreadEnterHugs",
129   "ThreadKilled",
130   "ThreadComplete"
131 };
132
133 char *threadReturnCode_strs[] = {
134   "HeapOverflow",                       /* might also be StackOverflow */
135   "StackOverflow",
136   "ThreadYielding",
137   "ThreadBlocked",
138   "ThreadFinished"
139 };
140 #endif
141
142 #if defined(GRAN)
143
144 StgTSO* ActiveTSO = NULL; /* for assigning system costs; GranSim-Light only */
145 // rtsTime TimeOfNextEvent, EndOfTimeSlice;            now in GranSim.c
146
147 /* 
148    In GranSim we have a runable and a blocked queue for each processor.
149    In order to minimise code changes new arrays run_queue_hds/tls
150    are created. run_queue_hd is then a short cut (macro) for
151    run_queue_hds[CurrentProc] (see GranSim.h).
152    -- HWL
153 */
154 StgTSO *run_queue_hds[MAX_PROC], *run_queue_tls[MAX_PROC];
155 StgTSO *blocked_queue_hds[MAX_PROC], *blocked_queue_tls[MAX_PROC];
156 StgTSO *ccalling_threadss[MAX_PROC];
157
158 #else /* !GRAN */
159
160 //@cindex run_queue_hd
161 //@cindex run_queue_tl
162 //@cindex blocked_queue_hd
163 //@cindex blocked_queue_tl
164 StgTSO *run_queue_hd, *run_queue_tl;
165 StgTSO *blocked_queue_hd, *blocked_queue_tl;
166
167 /* Threads suspended in _ccall_GC.
168  * Locks required: sched_mutex.
169  */
170 static StgTSO *suspended_ccalling_threads;
171
172 static void GetRoots(void);
173 static StgTSO *threadStackOverflow(StgTSO *tso);
174 #endif
175
176 /* KH: The following two flags are shared memory locations.  There is no need
177        to lock them, since they are only unset at the end of a scheduler
178        operation.
179 */
180
181 /* flag set by signal handler to precipitate a context switch */
182 //@cindex context_switch
183 nat context_switch;
184
185 /* if this flag is set as well, give up execution */
186 //@cindex interrupted
187 rtsBool interrupted;
188
189 /* Next thread ID to allocate.
190  * Locks required: sched_mutex
191  */
192 //@cindex next_thread_id
193 StgThreadID next_thread_id = 1;
194
195 /*
196  * Pointers to the state of the current thread.
197  * Rule of thumb: if CurrentTSO != NULL, then we're running a Haskell
198  * thread.  If CurrentTSO == NULL, then we're at the scheduler level.
199  */
200  
201 /* The smallest stack size that makes any sense is:
202  *    RESERVED_STACK_WORDS    (so we can get back from the stack overflow)
203  *  + sizeofW(StgStopFrame)   (the stg_stop_thread_info frame)
204  *  + 1                       (the realworld token for an IO thread)
205  *  + 1                       (the closure to enter)
206  *
207  * A thread with this stack will bomb immediately with a stack
208  * overflow, which will increase its stack size.  
209  */
210
211 #define MIN_STACK_WORDS (RESERVED_STACK_WORDS + sizeofW(StgStopFrame) + 2)
212
213 /* Free capability list.
214  * Locks required: sched_mutex.
215  */
216 #ifdef SMP
217 //@cindex free_capabilities
218 //@cindex n_free_capabilities
219 Capability *free_capabilities; /* Available capabilities for running threads */
220 nat n_free_capabilities;       /* total number of available capabilities */
221 #else
222 //@cindex MainRegTable
223 Capability MainRegTable;       /* for non-SMP, we have one global capability */
224 #endif
225
226 #if defined(GRAN)
227 StgTSO      *CurrentTSOs[MAX_PROC];
228 #else
229 StgTSO      *CurrentTSO;
230 #endif
231
232 rtsBool ready_to_gc;
233
234 /* All our current task ids, saved in case we need to kill them later.
235  */
236 #ifdef SMP
237 //@cindex task_ids
238 task_info *task_ids;
239 #endif
240
241 void            addToBlockedQueue ( StgTSO *tso );
242
243 static void     schedule          ( void );
244        void     interruptStgRts   ( void );
245 static StgTSO * createThread_     ( nat size, rtsBool have_lock );
246
247 #ifdef DEBUG
248 static void sched_belch(char *s, ...);
249 #endif
250
251 #ifdef SMP
252 //@cindex sched_mutex
253 //@cindex term_mutex
254 //@cindex thread_ready_cond
255 //@cindex gc_pending_cond
256 pthread_mutex_t sched_mutex       = PTHREAD_MUTEX_INITIALIZER;
257 pthread_mutex_t term_mutex        = PTHREAD_MUTEX_INITIALIZER;
258 pthread_cond_t  thread_ready_cond = PTHREAD_COND_INITIALIZER;
259 pthread_cond_t  gc_pending_cond   = PTHREAD_COND_INITIALIZER;
260
261 nat await_death;
262 #endif
263
264 #if defined(PAR)
265 StgTSO *LastTSO;
266 rtsTime TimeOfLastYield;
267 #endif
268
269 /*
270  * The thread state for the main thread.
271 // ToDo: check whether not needed any more
272 StgTSO   *MainTSO;
273  */
274
275
276 //@node Prototypes, Main scheduling loop, Variables and Data structures, Main scheduling code
277 //@subsection Prototypes
278
279 #if 0 && defined(GRAN)
280 // ToDo: replace these with macros
281 static /* inline */ void    add_to_run_queue(StgTSO* tso); 
282 static /* inline */ void    push_on_run_queue(StgTSO* tso); 
283 static /* inline */ StgTSO *take_off_run_queue(StgTSO *tso);
284
285 /* Thread management */
286 void initScheduler(void);
287 #endif
288
289 //@node Main scheduling loop, Suspend and Resume, Prototypes, Main scheduling code
290 //@subsection Main scheduling loop
291
292 /* ---------------------------------------------------------------------------
293    Main scheduling loop.
294
295    We use round-robin scheduling, each thread returning to the
296    scheduler loop when one of these conditions is detected:
297
298       * out of heap space
299       * timer expires (thread yields)
300       * thread blocks
301       * thread ends
302       * stack overflow
303
304    Locking notes:  we acquire the scheduler lock once at the beginning
305    of the scheduler loop, and release it when
306     
307       * running a thread, or
308       * waiting for work, or
309       * waiting for a GC to complete.
310
311    ------------------------------------------------------------------------ */
312 //@cindex schedule
313 static void
314 schedule( void )
315 {
316   StgTSO *t;
317   Capability *cap;
318   StgThreadReturnCode ret;
319 #if defined(GRAN)
320   rtsEvent *event;
321 #elif defined(PAR)
322   rtsSpark spark;
323   StgTSO *tso;
324   GlobalTaskId pe;
325 #endif
326   
327   ACQUIRE_LOCK(&sched_mutex);
328
329 #if defined(GRAN)
330 # error ToDo: implement GranSim scheduler
331 #elif defined(PAR)
332   while (!GlobalStopPending) {          /* GlobalStopPending set in par_exit */
333
334     if (PendingFetches != END_BF_QUEUE) {
335         processFetches();
336     }
337 #else
338   while (1) {
339 #endif
340
341     /* If we're interrupted (the user pressed ^C, or some other
342      * termination condition occurred), kill all the currently running
343      * threads.
344      */
345     if (interrupted) {
346       IF_DEBUG(scheduler, sched_belch("interrupted"));
347       for (t = run_queue_hd; t != END_TSO_QUEUE; t = t->link) {
348         deleteThread(t);
349       }
350       for (t = blocked_queue_hd; t != END_TSO_QUEUE; t = t->link) {
351         deleteThread(t);
352       }
353       run_queue_hd = run_queue_tl = END_TSO_QUEUE;
354       blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
355     }
356
357     /* Go through the list of main threads and wake up any
358      * clients whose computations have finished.  ToDo: this
359      * should be done more efficiently without a linear scan
360      * of the main threads list, somehow...
361      */
362 #ifdef SMP
363     { 
364       StgMainThread *m, **prev;
365       prev = &main_threads;
366       for (m = main_threads; m != NULL; m = m->link) {
367         switch (m->tso->whatNext) {
368         case ThreadComplete:
369           if (m->ret) {
370             *(m->ret) = (StgClosure *)m->tso->sp[0];
371           }
372           *prev = m->link;
373           m->stat = Success;
374           pthread_cond_broadcast(&m->wakeup);
375           break;
376         case ThreadKilled:
377           *prev = m->link;
378           m->stat = Killed;
379           pthread_cond_broadcast(&m->wakeup);
380           break;
381         default:
382           break;
383         }
384       }
385     }
386 #else
387     /* If our main thread has finished or been killed, return.
388      */
389     {
390       StgMainThread *m = main_threads;
391       if (m->tso->whatNext == ThreadComplete
392           || m->tso->whatNext == ThreadKilled) {
393         main_threads = main_threads->link;
394         if (m->tso->whatNext == ThreadComplete) {
395           /* we finished successfully, fill in the return value */
396           if (m->ret) { *(m->ret) = (StgClosure *)m->tso->sp[0]; };
397           m->stat = Success;
398           return;
399         } else {
400           m->stat = Killed;
401           return;
402         }
403       }
404     }
405 #endif
406
407     /* Top up the run queue from our spark pool.  We try to make the
408      * number of threads in the run queue equal to the number of
409      * free capabilities.
410      */
411 #if defined(SMP)
412     {
413       nat n = n_free_capabilities;
414       StgTSO *tso = run_queue_hd;
415
416       /* Count the run queue */
417       while (n > 0 && tso != END_TSO_QUEUE) {
418         tso = tso->link;
419         n--;
420       }
421
422       for (; n > 0; n--) {
423         StgClosure *spark;
424         spark = findSpark();
425         if (spark == NULL) {
426           break; /* no more sparks in the pool */
427         } else {
428           // I'd prefer this to be done in activateSpark -- HWL
429           StgTSO *tso;
430           tso = createThread_(RtsFlags.GcFlags.initialStkSize, rtsTrue);
431           pushClosure(tso,spark);
432           PUSH_ON_RUN_QUEUE(tso);
433 #ifdef PAR
434           advisory_thread_count++;
435 #endif
436           
437           IF_DEBUG(scheduler,
438                    sched_belch("turning spark of closure %p into a thread",
439                                (StgClosure *)spark));
440         }
441       }
442       /* We need to wake up the other tasks if we just created some
443        * work for them.
444        */
445       if (n_free_capabilities - n > 1) {
446           pthread_cond_signal(&thread_ready_cond);
447       }
448     }
449 #endif /* SMP */
450
451     /* Check whether any waiting threads need to be woken up.  If the
452      * run queue is empty, and there are no other tasks running, we
453      * can wait indefinitely for something to happen.
454      * ToDo: what if another client comes along & requests another
455      * main thread?
456      */
457     if (blocked_queue_hd != END_TSO_QUEUE) {
458       awaitEvent(
459            (run_queue_hd == END_TSO_QUEUE)
460 #ifdef SMP
461         && (n_free_capabilities == RtsFlags.ParFlags.nNodes)
462 #endif
463         );
464     }
465     
466     /* check for signals each time around the scheduler */
467 #ifndef __MINGW32__
468     if (signals_pending()) {
469       start_signal_handlers();
470     }
471 #endif
472
473     /* Detect deadlock: when we have no threads to run, there are
474      * no threads waiting on I/O or sleeping, and all the other
475      * tasks are waiting for work, we must have a deadlock.  Inform
476      * all the main threads.
477      */
478 #ifdef SMP
479     if (blocked_queue_hd == END_TSO_QUEUE
480         && run_queue_hd == END_TSO_QUEUE
481         && (n_free_capabilities == RtsFlags.ParFlags.nNodes)
482         ) {
483       StgMainThread *m;
484       for (m = main_threads; m != NULL; m = m->link) {
485           m->ret = NULL;
486           m->stat = Deadlock;
487           pthread_cond_broadcast(&m->wakeup);
488       }
489       main_threads = NULL;
490     }
491 #else /* ! SMP */
492     if (blocked_queue_hd == END_TSO_QUEUE
493         && run_queue_hd == END_TSO_QUEUE) {
494       StgMainThread *m = main_threads;
495       m->ret = NULL;
496       m->stat = Deadlock;
497       main_threads = m->link;
498       return;
499     }
500 #endif
501
502 #ifdef SMP
503     /* If there's a GC pending, don't do anything until it has
504      * completed.
505      */
506     if (ready_to_gc) {
507       IF_DEBUG(scheduler,sched_belch("waiting for GC"));
508       pthread_cond_wait(&gc_pending_cond, &sched_mutex);
509     }
510     
511     /* block until we've got a thread on the run queue and a free
512      * capability.
513      */
514     while (run_queue_hd == END_TSO_QUEUE || free_capabilities == NULL) {
515       IF_DEBUG(scheduler, sched_belch("waiting for work"));
516       pthread_cond_wait(&thread_ready_cond, &sched_mutex);
517       IF_DEBUG(scheduler, sched_belch("work now available"));
518     }
519 #endif
520
521 #if defined(GRAN)
522 # error ToDo: implement GranSim scheduler
523 #elif defined(PAR)
524     // ToDo: phps merge with spark activation above
525     /* check whether we have local work and send requests if we have none */
526     if (run_queue_hd == END_TSO_QUEUE) {  /* no runnable threads */
527       /* :-[  no local threads => look out for local sparks */
528       if (advisory_thread_count < RtsFlags.ParFlags.maxThreads &&
529           (pending_sparks_hd[REQUIRED_POOL] < pending_sparks_tl[REQUIRED_POOL] ||
530            pending_sparks_hd[ADVISORY_POOL] < pending_sparks_tl[ADVISORY_POOL])) {
531         /* 
532          * ToDo: add GC code check that we really have enough heap afterwards!!
533          * Old comment:
534          * If we're here (no runnable threads) and we have pending
535          * sparks, we must have a space problem.  Get enough space
536          * to turn one of those pending sparks into a
537          * thread... 
538          */
539         
540         spark = findSpark();                /* get a spark */
541         if (spark != (rtsSpark) NULL) {
542           tso = activateSpark(spark);       /* turn the spark into a thread */
543           IF_PAR_DEBUG(verbose,
544                        belch("== [%x] schedule: Created TSO %p (%d); %d threads active",
545                              mytid, tso, tso->id, advisory_thread_count));
546
547           if (tso==END_TSO_QUEUE) { // failed to activate spark -> back to loop
548             belch("^^ failed to activate spark");
549             goto next_thread;
550           }                         // otherwise fall through & pick-up new tso
551         } else {
552           IF_PAR_DEBUG(verbose,
553                        belch("^^ no local sparks (spark pool contains only NFs: %d)", 
554                              spark_queue_len(ADVISORY_POOL)));
555           goto next_thread;
556         }
557       } else  
558       /* =8-[  no local sparks => look for work on other PEs */
559       {
560         /*
561          * We really have absolutely no work.  Send out a fish
562          * (there may be some out there already), and wait for
563          * something to arrive.  We clearly can't run any threads
564          * until a SCHEDULE or RESUME arrives, and so that's what
565          * we're hoping to see.  (Of course, we still have to
566          * respond to other types of messages.)
567          */
568         if (//!fishing &&  
569             outstandingFishes < RtsFlags.ParFlags.maxFishes ) { // &&
570           // (last_fish_arrived_at+FISH_DELAY < CURRENT_TIME)) {
571           /* fishing set in sendFish, processFish;
572              avoid flooding system with fishes via delay */
573           pe = choosePE();
574           sendFish(pe, mytid, NEW_FISH_AGE, NEW_FISH_HISTORY, 
575                    NEW_FISH_HUNGER);
576         }
577         
578         processMessages();
579         goto next_thread;
580         // ReSchedule(0);
581       }
582     } else if (PacketsWaiting()) {  /* Look for incoming messages */
583       processMessages();
584     }
585
586     /* Now we are sure that we have some work available */
587     ASSERT(run_queue_hd != END_TSO_QUEUE);
588     /* Take a thread from the run queue, if we have work */
589     t = take_off_run_queue(END_TSO_QUEUE);
590
591     /* ToDo: write something to the log-file
592     if (RTSflags.ParFlags.granSimStats && !sameThread)
593         DumpGranEvent(GR_SCHEDULE, RunnableThreadsHd);
594     */
595
596     CurrentTSO = t;
597
598     IF_DEBUG(scheduler, belch("--^^ %d sparks on [%#x] (hd=%x; tl=%x; lim=%x)", 
599                               spark_queue_len(ADVISORY_POOL), CURRENT_PROC,
600                               pending_sparks_hd[ADVISORY_POOL], 
601                               pending_sparks_tl[ADVISORY_POOL], 
602                               pending_sparks_lim[ADVISORY_POOL]));
603
604     IF_DEBUG(scheduler, belch("--== %d threads on [%#x] (hd=%x; tl=%x)", 
605                               run_queue_len(), CURRENT_PROC,
606                               run_queue_hd, run_queue_tl));
607
608     if (t != LastTSO) {
609       /* 
610          we are running a different TSO, so write a schedule event to log file
611          NB: If we use fair scheduling we also have to write  a deschedule 
612              event for LastTSO; with unfair scheduling we know that the
613              previous tso has blocked whenever we switch to another tso, so
614              we don't need it in GUM for now
615       */
616       DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC,
617                        GR_SCHEDULE, t, (StgClosure *)NULL, 0, 0);
618       
619     }
620
621 #else /* !GRAN && !PAR */
622   
623     /* grab a thread from the run queue
624      */
625     t = POP_RUN_QUEUE();
626
627 #endif
628     
629     /* grab a capability
630      */
631 #ifdef SMP
632     cap = free_capabilities;
633     free_capabilities = cap->link;
634     n_free_capabilities--;
635 #else
636     cap = &MainRegTable;
637 #endif
638     
639     cap->rCurrentTSO = t;
640     
641     /* set the context_switch flag
642      */
643     if (run_queue_hd == END_TSO_QUEUE)
644       context_switch = 0;
645     else
646       context_switch = 1;
647
648     RELEASE_LOCK(&sched_mutex);
649     
650     IF_DEBUG(scheduler,sched_belch("running thread %d", t->id));
651
652     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
653     /* Run the current thread 
654      */
655     switch (cap->rCurrentTSO->whatNext) {
656     case ThreadKilled:
657     case ThreadComplete:
658       /* Thread already finished, return to scheduler. */
659       ret = ThreadFinished;
660       break;
661     case ThreadEnterGHC:
662       ret = StgRun((StgFunPtr) stg_enterStackTop, cap);
663       break;
664     case ThreadRunGHC:
665       ret = StgRun((StgFunPtr) stg_returnToStackTop, cap);
666       break;
667     case ThreadEnterHugs:
668 #ifdef INTERPRETER
669       {
670          StgClosure* c;
671          IF_DEBUG(scheduler,sched_belch("entering Hugs"));
672          c = (StgClosure *)(cap->rCurrentTSO->sp[0]);
673          cap->rCurrentTSO->sp += 1;
674          ret = enter(cap,c);
675          break;
676       }
677 #else
678       barf("Panic: entered a BCO but no bytecode interpreter in this build");
679 #endif
680     default:
681       barf("schedule: invalid whatNext field");
682     }
683     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
684     
685     /* Costs for the scheduler are assigned to CCS_SYSTEM */
686 #ifdef PROFILING
687     CCCS = CCS_SYSTEM;
688 #endif
689     
690     ACQUIRE_LOCK(&sched_mutex);
691
692 #ifdef SMP
693     IF_DEBUG(scheduler,fprintf(stderr,"scheduler (task %ld): ", pthread_self()););
694 #else
695     IF_DEBUG(scheduler,fprintf(stderr,"scheduler: "););
696 #endif
697     t = cap->rCurrentTSO;
698     
699     switch (ret) {
700     case HeapOverflow:
701       /* make all the running tasks block on a condition variable,
702        * maybe set context_switch and wait till they all pile in,
703        * then have them wait on a GC condition variable.
704        */
705       IF_DEBUG(scheduler,belch("thread %ld stopped: HeapOverflow", t->id));
706       threadPaused(t);
707       
708       ready_to_gc = rtsTrue;
709       context_switch = 1;               /* stop other threads ASAP */
710       PUSH_ON_RUN_QUEUE(t);
711       break;
712       
713     case StackOverflow:
714       /* just adjust the stack for this thread, then pop it back
715        * on the run queue.
716        */
717       IF_DEBUG(scheduler,belch("thread %ld stopped, StackOverflow", t->id));
718       threadPaused(t);
719       { 
720         StgMainThread *m;
721         /* enlarge the stack */
722         StgTSO *new_t = threadStackOverflow(t);
723         
724         /* This TSO has moved, so update any pointers to it from the
725          * main thread stack.  It better not be on any other queues...
726          * (it shouldn't be)
727          */
728         for (m = main_threads; m != NULL; m = m->link) {
729           if (m->tso == t) {
730             m->tso = new_t;
731           }
732         }
733         PUSH_ON_RUN_QUEUE(new_t);
734       }
735       break;
736
737     case ThreadYielding:
738 #if defined(GRAN)
739       IF_DEBUG(gran, 
740                DumpGranEvent(GR_DESCHEDULE, t));
741       globalGranStats.tot_yields++;
742 #elif defined(PAR)
743       IF_DEBUG(par, 
744                DumpGranEvent(GR_DESCHEDULE, t));
745 #endif
746       /* put the thread back on the run queue.  Then, if we're ready to
747        * GC, check whether this is the last task to stop.  If so, wake
748        * up the GC thread.  getThread will block during a GC until the
749        * GC is finished.
750        */
751       IF_DEBUG(scheduler,
752                if (t->whatNext == ThreadEnterHugs) {
753                  /* ToDo: or maybe a timer expired when we were in Hugs?
754                   * or maybe someone hit ctrl-C
755                   */
756                  belch("thread %ld stopped to switch to Hugs", t->id);
757                } else {
758                  belch("thread %ld stopped, yielding", t->id);
759                }
760                );
761       threadPaused(t);
762       APPEND_TO_RUN_QUEUE(t);
763       break;
764       
765     case ThreadBlocked:
766 #if defined(GRAN)
767 # error ToDo: implement GranSim scheduler
768 #elif defined(PAR)
769       IF_DEBUG(par, 
770                DumpGranEvent(GR_DESCHEDULE, t)); 
771 #else
772 #endif
773       /* don't need to do anything.  Either the thread is blocked on
774        * I/O, in which case we'll have called addToBlockedQueue
775        * previously, or it's blocked on an MVar or Blackhole, in which
776        * case it'll be on the relevant queue already.
777        */
778       IF_DEBUG(scheduler,
779                fprintf(stderr, "thread %d stopped, ", t->id);
780                printThreadBlockage(t);
781                fprintf(stderr, "\n"));
782       threadPaused(t);
783       break;
784       
785     case ThreadFinished:
786       /* Need to check whether this was a main thread, and if so, signal
787        * the task that started it with the return value.  If we have no
788        * more main threads, we probably need to stop all the tasks until
789        * we get a new one.
790        */
791       IF_DEBUG(scheduler,belch("thread %ld finished", t->id));
792       t->whatNext = ThreadComplete;
793 #if defined(GRAN)
794       // ToDo: endThread(t, CurrentProc); // clean-up the thread
795 #elif defined(PAR)
796       advisory_thread_count--;
797       if (RtsFlags.ParFlags.ParStats.Full) 
798         DumpEndEvent(CURRENT_PROC, t, rtsFalse /* not mandatory */);
799 #endif
800       break;
801       
802     default:
803       barf("doneThread: invalid thread return code");
804     }
805     
806 #ifdef SMP
807     cap->link = free_capabilities;
808     free_capabilities = cap;
809     n_free_capabilities++;
810 #endif
811
812 #ifdef SMP
813     if (ready_to_gc && n_free_capabilities == RtsFlags.ParFlags.nNodes) 
814 #else
815     if (ready_to_gc) 
816 #endif
817       {
818       /* everybody back, start the GC.
819        * Could do it in this thread, or signal a condition var
820        * to do it in another thread.  Either way, we need to
821        * broadcast on gc_pending_cond afterward.
822        */
823 #ifdef SMP
824       IF_DEBUG(scheduler,sched_belch("doing GC"));
825 #endif
826       GarbageCollect(GetRoots);
827       ready_to_gc = rtsFalse;
828 #ifdef SMP
829       pthread_cond_broadcast(&gc_pending_cond);
830 #endif
831     }
832 #if defined(GRAN)
833   next_thread:
834     IF_GRAN_DEBUG(unused,
835                   print_eventq(EventHd));
836
837     event = get_next_event();
838
839 #elif defined(PAR)
840   next_thread:
841     /* ToDo: wait for next message to arrive rather than busy wait */
842
843 #else /* GRAN */
844   /* not any more
845   next_thread:
846     t = take_off_run_queue(END_TSO_QUEUE);
847   */
848 #endif /* GRAN */
849   } /* end of while(1) */
850 }
851
852 /* A hack for Hugs concurrency support.  Needs sanitisation (?) */
853 void deleteAllThreads ( void )
854 {
855   StgTSO* t;
856   IF_DEBUG(scheduler,sched_belch("deleteAllThreads()"));
857   for (t = run_queue_hd; t != END_TSO_QUEUE; t = t->link) {
858     deleteThread(t);
859   }
860   for (t = blocked_queue_hd; t != END_TSO_QUEUE; t = t->link) {
861     deleteThread(t);
862   }
863   run_queue_hd = run_queue_tl = END_TSO_QUEUE;
864   blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
865 }
866
867 /* startThread and  insertThread are now in GranSim.c -- HWL */
868
869 //@node Suspend and Resume, Run queue code, Main scheduling loop, Main scheduling code
870 //@subsection Suspend and Resume
871
872 /* ---------------------------------------------------------------------------
873  * Suspending & resuming Haskell threads.
874  * 
875  * When making a "safe" call to C (aka _ccall_GC), the task gives back
876  * its capability before calling the C function.  This allows another
877  * task to pick up the capability and carry on running Haskell
878  * threads.  It also means that if the C call blocks, it won't lock
879  * the whole system.
880  *
881  * The Haskell thread making the C call is put to sleep for the
882  * duration of the call, on the susepended_ccalling_threads queue.  We
883  * give out a token to the task, which it can use to resume the thread
884  * on return from the C function.
885  * ------------------------------------------------------------------------- */
886    
887 StgInt
888 suspendThread( Capability *cap )
889 {
890   nat tok;
891
892   ACQUIRE_LOCK(&sched_mutex);
893
894   IF_DEBUG(scheduler,
895            sched_belch("thread %d did a _ccall_gc\n", cap->rCurrentTSO->id));
896
897   threadPaused(cap->rCurrentTSO);
898   cap->rCurrentTSO->link = suspended_ccalling_threads;
899   suspended_ccalling_threads = cap->rCurrentTSO;
900
901   /* Use the thread ID as the token; it should be unique */
902   tok = cap->rCurrentTSO->id;
903
904 #ifdef SMP
905   cap->link = free_capabilities;
906   free_capabilities = cap;
907   n_free_capabilities++;
908 #endif
909
910   RELEASE_LOCK(&sched_mutex);
911   return tok; 
912 }
913
914 Capability *
915 resumeThread( StgInt tok )
916 {
917   StgTSO *tso, **prev;
918   Capability *cap;
919
920   ACQUIRE_LOCK(&sched_mutex);
921
922   prev = &suspended_ccalling_threads;
923   for (tso = suspended_ccalling_threads; 
924        tso != END_TSO_QUEUE; 
925        prev = &tso->link, tso = tso->link) {
926     if (tso->id == (StgThreadID)tok) {
927       *prev = tso->link;
928       break;
929     }
930   }
931   if (tso == END_TSO_QUEUE) {
932     barf("resumeThread: thread not found");
933   }
934
935 #ifdef SMP
936   while (free_capabilities == NULL) {
937     IF_DEBUG(scheduler, sched_belch("waiting to resume"));
938     pthread_cond_wait(&thread_ready_cond, &sched_mutex);
939     IF_DEBUG(scheduler, sched_belch("resuming thread %d", tso->id));
940   }
941   cap = free_capabilities;
942   free_capabilities = cap->link;
943   n_free_capabilities--;
944 #else  
945   cap = &MainRegTable;
946 #endif
947
948   cap->rCurrentTSO = tso;
949
950   RELEASE_LOCK(&sched_mutex);
951   return cap;
952 }
953
954
955 /* ---------------------------------------------------------------------------
956  * Static functions
957  * ------------------------------------------------------------------------ */
958 static void unblockThread(StgTSO *tso);
959
960 /* ---------------------------------------------------------------------------
961  * Comparing Thread ids.
962  *
963  * This is used from STG land in the implementation of the
964  * instances of Eq/Ord for ThreadIds.
965  * ------------------------------------------------------------------------ */
966
967 int cmp_thread(const StgTSO *tso1, const StgTSO *tso2) 
968
969   StgThreadID id1 = tso1->id; 
970   StgThreadID id2 = tso2->id;
971  
972   if (id1 < id2) return (-1);
973   if (id1 > id2) return 1;
974   return 0;
975 }
976
977 /* ---------------------------------------------------------------------------
978    Create a new thread.
979
980    The new thread starts with the given stack size.  Before the
981    scheduler can run, however, this thread needs to have a closure
982    (and possibly some arguments) pushed on its stack.  See
983    pushClosure() in Schedule.h.
984
985    createGenThread() and createIOThread() (in SchedAPI.h) are
986    convenient packaged versions of this function.
987    ------------------------------------------------------------------------ */
988 //@cindex createThread
989 #if defined(GRAN)
990 /* currently pri (priority) is only used in a GRAN setup -- HWL */
991 StgTSO *
992 createThread(nat stack_size, StgInt pri)
993 {
994   return createThread_(stack_size, rtsFalse, pri);
995 }
996
997 static StgTSO *
998 createThread_(nat size, rtsBool have_lock, StgInt pri)
999 {
1000 #else
1001 StgTSO *
1002 createThread(nat stack_size)
1003 {
1004   return createThread_(stack_size, rtsFalse);
1005 }
1006
1007 static StgTSO *
1008 createThread_(nat size, rtsBool have_lock)
1009 {
1010 #endif
1011     StgTSO *tso;
1012     nat stack_size;
1013
1014     /* First check whether we should create a thread at all */
1015 #if defined(PAR)
1016   /* check that no more than RtsFlags.ParFlags.maxThreads threads are created */
1017   if (advisory_thread_count >= RtsFlags.ParFlags.maxThreads) {
1018     threadsIgnored++;
1019     belch("{createThread}Daq ghuH: refusing to create another thread; no more than %d threads allowed (currently %d)",
1020           RtsFlags.ParFlags.maxThreads, advisory_thread_count);
1021     return END_TSO_QUEUE;
1022   }
1023   threadsCreated++;
1024 #endif
1025
1026 #if defined(GRAN)
1027   ASSERT(!RtsFlags.GranFlags.Light || CurrentProc==0);
1028 #endif
1029
1030   // ToDo: check whether size = stack_size - TSO_STRUCT_SIZEW
1031
1032   /* catch ridiculously small stack sizes */
1033   if (size < MIN_STACK_WORDS + TSO_STRUCT_SIZEW) {
1034     size = MIN_STACK_WORDS + TSO_STRUCT_SIZEW;
1035   }
1036
1037   tso = (StgTSO *)allocate(size);
1038   TICK_ALLOC_TSO(size-sizeofW(StgTSO),0);
1039   
1040   stack_size = size - TSO_STRUCT_SIZEW;
1041
1042   // Hmm, this CCS_MAIN is not protected by a PROFILING cpp var;
1043   SET_HDR(tso, &TSO_info, CCS_MAIN);
1044 #if defined(GRAN)
1045   SET_GRAN_HDR(tso, ThisPE);
1046 #endif
1047   tso->whatNext     = ThreadEnterGHC;
1048
1049   /* tso->id needs to be unique.  For now we use a heavyweight mutex to
1050          protect the increment operation on next_thread_id.
1051          In future, we could use an atomic increment instead.
1052   */
1053   
1054   if (!have_lock) { ACQUIRE_LOCK(&sched_mutex); }
1055   tso->id = next_thread_id++; 
1056   if (!have_lock) { RELEASE_LOCK(&sched_mutex); }
1057
1058   tso->why_blocked  = NotBlocked;
1059   tso->blocked_exceptions = NULL;
1060
1061   tso->splim        = (P_)&(tso->stack) + RESERVED_STACK_WORDS;
1062   tso->stack_size   = stack_size;
1063   tso->max_stack_size = round_to_mblocks(RtsFlags.GcFlags.maxStkSize) 
1064                               - TSO_STRUCT_SIZEW;
1065   tso->sp           = (P_)&(tso->stack) + stack_size;
1066
1067 #ifdef PROFILING
1068   tso->prof.CCCS = CCS_MAIN;
1069 #endif
1070
1071   /* put a stop frame on the stack */
1072   tso->sp -= sizeofW(StgStopFrame);
1073   SET_HDR((StgClosure*)tso->sp,(StgInfoTable *)&stg_stop_thread_info,CCS_MAIN);
1074   tso->su = (StgUpdateFrame*)tso->sp;
1075
1076   IF_DEBUG(scheduler,belch("---- Initialised TSO %ld (%p), stack size = %lx words", 
1077                            tso->id, tso, tso->stack_size));
1078
1079   // ToDo: check this
1080 #if defined(GRAN)
1081   tso->link = END_TSO_QUEUE;
1082   /* uses more flexible routine in GranSim */
1083   insertThread(tso, CurrentProc);
1084 #else
1085   /* In a non-GranSim setup the pushing of a TSO onto the runq is separated
1086      from its creation
1087   */
1088 #endif
1089
1090 #if defined(GRAN)
1091   tso->gran.pri = pri;
1092   tso->gran.magic = TSO_MAGIC; // debugging only
1093   tso->gran.sparkname   = 0;
1094   tso->gran.startedat   = CURRENT_TIME; 
1095   tso->gran.exported    = 0;
1096   tso->gran.basicblocks = 0;
1097   tso->gran.allocs      = 0;
1098   tso->gran.exectime    = 0;
1099   tso->gran.fetchtime   = 0;
1100   tso->gran.fetchcount  = 0;
1101   tso->gran.blocktime   = 0;
1102   tso->gran.blockcount  = 0;
1103   tso->gran.blockedat   = 0;
1104   tso->gran.globalsparks = 0;
1105   tso->gran.localsparks  = 0;
1106   if (RtsFlags.GranFlags.Light)
1107     tso->gran.clock  = Now; /* local clock */
1108   else
1109     tso->gran.clock  = 0;
1110
1111   IF_DEBUG(gran,printTSO(tso));
1112 #elif defined(PAR)
1113   tso->par.sparkname   = 0;
1114   tso->par.startedat   = CURRENT_TIME; 
1115   tso->par.exported    = 0;
1116   tso->par.basicblocks = 0;
1117   tso->par.allocs      = 0;
1118   tso->par.exectime    = 0;
1119   tso->par.fetchtime   = 0;
1120   tso->par.fetchcount  = 0;
1121   tso->par.blocktime   = 0;
1122   tso->par.blockcount  = 0;
1123   tso->par.blockedat   = 0;
1124   tso->par.globalsparks = 0;
1125   tso->par.localsparks  = 0;
1126 #endif
1127
1128 #if defined(GRAN)
1129   globalGranStats.tot_threads_created++;
1130   globalGranStats.threads_created_on_PE[CurrentProc]++;
1131   globalGranStats.tot_sq_len += spark_queue_len(CurrentProc);
1132   globalGranStats.tot_sq_probes++;
1133 #endif 
1134
1135   IF_DEBUG(scheduler,sched_belch("created thread %ld, stack size = %lx words", 
1136                                  tso->id, tso->stack_size));
1137   return tso;
1138 }
1139
1140 /* ---------------------------------------------------------------------------
1141  * scheduleThread()
1142  *
1143  * scheduleThread puts a thread on the head of the runnable queue.
1144  * This will usually be done immediately after a thread is created.
1145  * The caller of scheduleThread must create the thread using e.g.
1146  * createThread and push an appropriate closure
1147  * on this thread's stack before the scheduler is invoked.
1148  * ------------------------------------------------------------------------ */
1149
1150 void
1151 scheduleThread(StgTSO *tso)
1152 {
1153   ACQUIRE_LOCK(&sched_mutex);
1154
1155   /* Put the new thread on the head of the runnable queue.  The caller
1156    * better push an appropriate closure on this thread's stack
1157    * beforehand.  In the SMP case, the thread may start running as
1158    * soon as we release the scheduler lock below.
1159    */
1160   PUSH_ON_RUN_QUEUE(tso);
1161   THREAD_RUNNABLE();
1162
1163   IF_DEBUG(scheduler,printTSO(tso));
1164   RELEASE_LOCK(&sched_mutex);
1165 }
1166
1167 /* ---------------------------------------------------------------------------
1168  * startTasks()
1169  *
1170  * Start up Posix threads to run each of the scheduler tasks.
1171  * I believe the task ids are not needed in the system as defined.
1172  *  KH @ 25/10/99
1173  * ------------------------------------------------------------------------ */
1174
1175 #ifdef SMP
1176 static void *
1177 taskStart( void *arg STG_UNUSED )
1178 {
1179   schedule();
1180   return NULL;
1181 }
1182 #endif
1183
1184 /* ---------------------------------------------------------------------------
1185  * initScheduler()
1186  *
1187  * Initialise the scheduler.  This resets all the queues - if the
1188  * queues contained any threads, they'll be garbage collected at the
1189  * next pass.
1190  *
1191  * This now calls startTasks(), so should only be called once!  KH @ 25/10/99
1192  * ------------------------------------------------------------------------ */
1193
1194 #ifdef SMP
1195 static void
1196 term_handler(int sig STG_UNUSED)
1197 {
1198   stat_workerStop();
1199   ACQUIRE_LOCK(&term_mutex);
1200   await_death--;
1201   RELEASE_LOCK(&term_mutex);
1202   pthread_exit(NULL);
1203 }
1204 #endif
1205
1206 //@cindex initScheduler
1207 void 
1208 initScheduler(void)
1209 {
1210 #if defined(GRAN)
1211   nat i;
1212
1213   for (i=0; i<=MAX_PROC; i++) {
1214     run_queue_hds[i]      = END_TSO_QUEUE;
1215     run_queue_tls[i]      = END_TSO_QUEUE;
1216     blocked_queue_hds[i]  = END_TSO_QUEUE;
1217     blocked_queue_tls[i]  = END_TSO_QUEUE;
1218     ccalling_threadss[i]  = END_TSO_QUEUE;
1219   }
1220 #else
1221   run_queue_hd      = END_TSO_QUEUE;
1222   run_queue_tl      = END_TSO_QUEUE;
1223   blocked_queue_hd  = END_TSO_QUEUE;
1224   blocked_queue_tl  = END_TSO_QUEUE;
1225 #endif 
1226
1227   suspended_ccalling_threads  = END_TSO_QUEUE;
1228
1229   main_threads = NULL;
1230
1231   context_switch = 0;
1232   interrupted    = 0;
1233
1234   enteredCAFs = END_CAF_LIST;
1235
1236   /* Install the SIGHUP handler */
1237 #ifdef SMP
1238   {
1239     struct sigaction action,oact;
1240
1241     action.sa_handler = term_handler;
1242     sigemptyset(&action.sa_mask);
1243     action.sa_flags = 0;
1244     if (sigaction(SIGTERM, &action, &oact) != 0) {
1245       barf("can't install TERM handler");
1246     }
1247   }
1248 #endif
1249
1250 #ifdef SMP
1251   /* Allocate N Capabilities */
1252   {
1253     nat i;
1254     Capability *cap, *prev;
1255     cap  = NULL;
1256     prev = NULL;
1257     for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
1258       cap = stgMallocBytes(sizeof(Capability), "initScheduler:capabilities");
1259       cap->link = prev;
1260       prev = cap;
1261     }
1262     free_capabilities = cap;
1263     n_free_capabilities = RtsFlags.ParFlags.nNodes;
1264   }
1265   IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Allocated %d capabilities\n",
1266                              n_free_capabilities););
1267 #endif
1268
1269 #if defined(SMP) || defined(PAR)
1270   initSparkPools();
1271 #endif
1272 }
1273
1274 #ifdef SMP
1275 void
1276 startTasks( void )
1277 {
1278   nat i;
1279   int r;
1280   pthread_t tid;
1281   
1282   /* make some space for saving all the thread ids */
1283   task_ids = stgMallocBytes(RtsFlags.ParFlags.nNodes * sizeof(task_info),
1284                             "initScheduler:task_ids");
1285   
1286   /* and create all the threads */
1287   for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
1288     r = pthread_create(&tid,NULL,taskStart,NULL);
1289     if (r != 0) {
1290       barf("startTasks: Can't create new Posix thread");
1291     }
1292     task_ids[i].id = tid;
1293     task_ids[i].mut_time = 0.0;
1294     task_ids[i].mut_etime = 0.0;
1295     task_ids[i].gc_time = 0.0;
1296     task_ids[i].gc_etime = 0.0;
1297     task_ids[i].elapsedtimestart = elapsedtime();
1298     IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Started task: %ld\n",tid););
1299   }
1300 }
1301 #endif
1302
1303 void
1304 exitScheduler( void )
1305 {
1306 #ifdef SMP
1307   nat i;
1308
1309   /* Don't want to use pthread_cancel, since we'd have to install
1310    * these silly exception handlers (pthread_cleanup_{push,pop}) around
1311    * all our locks.
1312    */
1313 #if 0
1314   /* Cancel all our tasks */
1315   for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
1316     pthread_cancel(task_ids[i].id);
1317   }
1318   
1319   /* Wait for all the tasks to terminate */
1320   for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
1321     IF_DEBUG(scheduler,fprintf(stderr,"scheduler: waiting for task %ld\n", 
1322                                task_ids[i].id));
1323     pthread_join(task_ids[i].id, NULL);
1324   }
1325 #endif
1326
1327   /* Send 'em all a SIGHUP.  That should shut 'em up.
1328    */
1329   await_death = RtsFlags.ParFlags.nNodes;
1330   for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
1331     pthread_kill(task_ids[i].id,SIGTERM);
1332   }
1333   while (await_death > 0) {
1334     sched_yield();
1335   }
1336 #endif
1337 }
1338
1339 /* -----------------------------------------------------------------------------
1340    Managing the per-task allocation areas.
1341    
1342    Each capability comes with an allocation area.  These are
1343    fixed-length block lists into which allocation can be done.
1344
1345    ToDo: no support for two-space collection at the moment???
1346    -------------------------------------------------------------------------- */
1347
1348 /* -----------------------------------------------------------------------------
1349  * waitThread is the external interface for running a new computataion
1350  * and waiting for the result.
1351  *
1352  * In the non-SMP case, we create a new main thread, push it on the 
1353  * main-thread stack, and invoke the scheduler to run it.  The
1354  * scheduler will return when the top main thread on the stack has
1355  * completed or died, and fill in the necessary fields of the
1356  * main_thread structure.
1357  *
1358  * In the SMP case, we create a main thread as before, but we then
1359  * create a new condition variable and sleep on it.  When our new
1360  * main thread has completed, we'll be woken up and the status/result
1361  * will be in the main_thread struct.
1362  * -------------------------------------------------------------------------- */
1363
1364 SchedulerStatus
1365 waitThread(StgTSO *tso, /*out*/StgClosure **ret)
1366 {
1367   StgMainThread *m;
1368   SchedulerStatus stat;
1369
1370   ACQUIRE_LOCK(&sched_mutex);
1371   
1372   m = stgMallocBytes(sizeof(StgMainThread), "waitThread");
1373
1374   m->tso = tso;
1375   m->ret = ret;
1376   m->stat = NoStatus;
1377 #ifdef SMP
1378   pthread_cond_init(&m->wakeup, NULL);
1379 #endif
1380
1381   m->link = main_threads;
1382   main_threads = m;
1383
1384   IF_DEBUG(scheduler, fprintf(stderr, "scheduler: new main thread (%d)\n", 
1385                               m->tso->id));
1386
1387 #ifdef SMP
1388   do {
1389     pthread_cond_wait(&m->wakeup, &sched_mutex);
1390   } while (m->stat == NoStatus);
1391 #else
1392   schedule();
1393   ASSERT(m->stat != NoStatus);
1394 #endif
1395
1396   stat = m->stat;
1397
1398 #ifdef SMP
1399   pthread_cond_destroy(&m->wakeup);
1400 #endif
1401
1402   IF_DEBUG(scheduler, fprintf(stderr, "scheduler: main thread (%d) finished\n", 
1403                               m->tso->id));
1404   free(m);
1405
1406   RELEASE_LOCK(&sched_mutex);
1407
1408   return stat;
1409 }
1410
1411 //@node Run queue code, Garbage Collextion Routines, Suspend and Resume, Main scheduling code
1412 //@subsection Run queue code 
1413
1414 #if 0
1415 /* 
1416    NB: In GranSim we have many run queues; run_queue_hd is actually a macro
1417        unfolding to run_queue_hds[CurrentProc], thus CurrentProc is an
1418        implicit global variable that has to be correct when calling these
1419        fcts -- HWL 
1420 */
1421
1422 /* Put the new thread on the head of the runnable queue.
1423  * The caller of createThread better push an appropriate closure
1424  * on this thread's stack before the scheduler is invoked.
1425  */
1426 static /* inline */ void
1427 add_to_run_queue(tso)
1428 StgTSO* tso; 
1429 {
1430   ASSERT(tso!=run_queue_hd && tso!=run_queue_tl);
1431   tso->link = run_queue_hd;
1432   run_queue_hd = tso;
1433   if (run_queue_tl == END_TSO_QUEUE) {
1434     run_queue_tl = tso;
1435   }
1436 }
1437
1438 /* Put the new thread at the end of the runnable queue. */
1439 static /* inline */ void
1440 push_on_run_queue(tso)
1441 StgTSO* tso; 
1442 {
1443   ASSERT(get_itbl((StgClosure *)tso)->type == TSO);
1444   ASSERT(run_queue_hd!=NULL && run_queue_tl!=NULL);
1445   ASSERT(tso!=run_queue_hd && tso!=run_queue_tl);
1446   if (run_queue_hd == END_TSO_QUEUE) {
1447     run_queue_hd = tso;
1448   } else {
1449     run_queue_tl->link = tso;
1450   }
1451   run_queue_tl = tso;
1452 }
1453
1454 /* 
1455    Should be inlined because it's used very often in schedule.  The tso
1456    argument is actually only needed in GranSim, where we want to have the
1457    possibility to schedule *any* TSO on the run queue, irrespective of the
1458    actual ordering. Therefore, if tso is not the nil TSO then we traverse
1459    the run queue and dequeue the tso, adjusting the links in the queue. 
1460 */
1461 //@cindex take_off_run_queue
1462 static /* inline */ StgTSO*
1463 take_off_run_queue(StgTSO *tso) {
1464   StgTSO *t, *prev;
1465
1466   /* 
1467      qetlaHbogh Qu' ngaSbogh ghomDaQ {tso} yIteq!
1468
1469      if tso is specified, unlink that tso from the run_queue (doesn't have
1470      to be at the beginning of the queue); GranSim only 
1471   */
1472   if (tso!=END_TSO_QUEUE) {
1473     /* find tso in queue */
1474     for (t=run_queue_hd, prev=END_TSO_QUEUE; 
1475          t!=END_TSO_QUEUE && t!=tso;
1476          prev=t, t=t->link) 
1477       /* nothing */ ;
1478     ASSERT(t==tso);
1479     /* now actually dequeue the tso */
1480     if (prev!=END_TSO_QUEUE) {
1481       ASSERT(run_queue_hd!=t);
1482       prev->link = t->link;
1483     } else {
1484       /* t is at beginning of thread queue */
1485       ASSERT(run_queue_hd==t);
1486       run_queue_hd = t->link;
1487     }
1488     /* t is at end of thread queue */
1489     if (t->link==END_TSO_QUEUE) {
1490       ASSERT(t==run_queue_tl);
1491       run_queue_tl = prev;
1492     } else {
1493       ASSERT(run_queue_tl!=t);
1494     }
1495     t->link = END_TSO_QUEUE;
1496   } else {
1497     /* take tso from the beginning of the queue; std concurrent code */
1498     t = run_queue_hd;
1499     if (t != END_TSO_QUEUE) {
1500       run_queue_hd = t->link;
1501       t->link = END_TSO_QUEUE;
1502       if (run_queue_hd == END_TSO_QUEUE) {
1503         run_queue_tl = END_TSO_QUEUE;
1504       }
1505     }
1506   }
1507   return t;
1508 }
1509
1510 #endif /* 0 */
1511
1512 nat
1513 run_queue_len(void)
1514 {
1515   nat i;
1516   StgTSO *tso;
1517
1518   for (i=0, tso=run_queue_hd; 
1519        tso != END_TSO_QUEUE;
1520        i++, tso=tso->link)
1521     /* nothing */
1522
1523   return i;
1524 }
1525
1526
1527 //@node Garbage Collextion Routines, Blocking Queue Routines, Run queue code, Main scheduling code
1528 //@subsection Garbage Collextion Routines
1529
1530 /* ---------------------------------------------------------------------------
1531    Where are the roots that we know about?
1532
1533         - all the threads on the runnable queue
1534         - all the threads on the blocked queue
1535         - all the thread currently executing a _ccall_GC
1536         - all the "main threads"
1537      
1538    ------------------------------------------------------------------------ */
1539
1540 /* This has to be protected either by the scheduler monitor, or by the
1541         garbage collection monitor (probably the latter).
1542         KH @ 25/10/99
1543 */
1544
1545 static void GetRoots(void)
1546 {
1547   StgMainThread *m;
1548
1549 #if defined(GRAN)
1550   nat i;
1551
1552   for (i=0; i<=RtsFlags.GranFlags.proc; i++) {
1553     if ((run_queue_hds[i] != END_TSO_QUEUE) && ((run_queue_hds[i] != NULL)))
1554       run_queue_hds[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_hds[i]);
1555     if ((run_queue_tls[i] != END_TSO_QUEUE) && ((run_queue_tls[i] != NULL)))
1556       run_queue_tls[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_tls[i]);
1557     
1558     if ((blocked_queue_hds[i] != END_TSO_QUEUE) && ((blocked_queue_hds[i] != NULL)))
1559       blocked_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hds[i]);
1560     if ((blocked_queue_tls[i] != END_TSO_QUEUE) && ((blocked_queue_tls[i] != NULL)))
1561       blocked_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tls[i]);
1562     if ((ccalling_threadss[i] != END_TSO_QUEUE) && ((ccalling_threadss[i] != NULL)))
1563       ccalling_threadss[i] = (StgTSO *)MarkRoot((StgClosure *)ccalling_threadss[i]);
1564   }
1565
1566   markEventQueue();
1567 #elif defined(PAR)
1568   run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
1569   run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
1570   blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
1571   blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
1572 #else
1573   run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
1574   run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
1575
1576   blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
1577   blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
1578 #endif 
1579
1580   for (m = main_threads; m != NULL; m = m->link) {
1581     m->tso = (StgTSO *)MarkRoot((StgClosure *)m->tso);
1582   }
1583   suspended_ccalling_threads = 
1584     (StgTSO *)MarkRoot((StgClosure *)suspended_ccalling_threads);
1585
1586 #if defined(SMP) || defined(PAR) || defined(GRAN)
1587   markSparkQueue();
1588 #endif
1589 }
1590
1591 /* -----------------------------------------------------------------------------
1592    performGC
1593
1594    This is the interface to the garbage collector from Haskell land.
1595    We provide this so that external C code can allocate and garbage
1596    collect when called from Haskell via _ccall_GC.
1597
1598    It might be useful to provide an interface whereby the programmer
1599    can specify more roots (ToDo).
1600    
1601    This needs to be protected by the GC condition variable above.  KH.
1602    -------------------------------------------------------------------------- */
1603
1604 void (*extra_roots)(void);
1605
1606 void
1607 performGC(void)
1608 {
1609   GarbageCollect(GetRoots);
1610 }
1611
1612 static void
1613 AllRoots(void)
1614 {
1615   GetRoots();                   /* the scheduler's roots */
1616   extra_roots();                /* the user's roots */
1617 }
1618
1619 void
1620 performGCWithRoots(void (*get_roots)(void))
1621 {
1622   extra_roots = get_roots;
1623
1624   GarbageCollect(AllRoots);
1625 }
1626
1627 /* -----------------------------------------------------------------------------
1628    Stack overflow
1629
1630    If the thread has reached its maximum stack size,
1631    then bomb out.  Otherwise relocate the TSO into a larger chunk of
1632    memory and adjust its stack size appropriately.
1633    -------------------------------------------------------------------------- */
1634
1635 static StgTSO *
1636 threadStackOverflow(StgTSO *tso)
1637 {
1638   nat new_stack_size, new_tso_size, diff, stack_words;
1639   StgPtr new_sp;
1640   StgTSO *dest;
1641
1642   if (tso->stack_size >= tso->max_stack_size) {
1643 #if 0
1644     /* If we're debugging, just print out the top of the stack */
1645     printStackChunk(tso->sp, stg_min(tso->stack+tso->stack_size, 
1646                                      tso->sp+64));
1647 #endif
1648 #ifdef INTERPRETER
1649     fprintf(stderr, "fatal: stack overflow in Hugs; aborting\n" );
1650     exit(1);
1651 #else
1652     /* Send this thread the StackOverflow exception */
1653     raiseAsync(tso, (StgClosure *)&stackOverflow_closure);
1654 #endif
1655     return tso;
1656   }
1657
1658   /* Try to double the current stack size.  If that takes us over the
1659    * maximum stack size for this thread, then use the maximum instead.
1660    * Finally round up so the TSO ends up as a whole number of blocks.
1661    */
1662   new_stack_size = stg_min(tso->stack_size * 2, tso->max_stack_size);
1663   new_tso_size   = (nat)BLOCK_ROUND_UP(new_stack_size * sizeof(W_) + 
1664                                        TSO_STRUCT_SIZE)/sizeof(W_);
1665   new_tso_size = round_to_mblocks(new_tso_size);  /* Be MBLOCK-friendly */
1666   new_stack_size = new_tso_size - TSO_STRUCT_SIZEW;
1667
1668   IF_DEBUG(scheduler, fprintf(stderr,"scheduler: increasing stack size from %d words to %d.\n", tso->stack_size, new_stack_size));
1669
1670   dest = (StgTSO *)allocate(new_tso_size);
1671   TICK_ALLOC_TSO(new_tso_size-sizeofW(StgTSO),0);
1672
1673   /* copy the TSO block and the old stack into the new area */
1674   memcpy(dest,tso,TSO_STRUCT_SIZE);
1675   stack_words = tso->stack + tso->stack_size - tso->sp;
1676   new_sp = (P_)dest + new_tso_size - stack_words;
1677   memcpy(new_sp, tso->sp, stack_words * sizeof(W_));
1678
1679   /* relocate the stack pointers... */
1680   diff = (P_)new_sp - (P_)tso->sp; /* In *words* */
1681   dest->su    = (StgUpdateFrame *) ((P_)dest->su + diff);
1682   dest->sp    = new_sp;
1683   dest->splim = (P_)dest->splim + (nat)((P_)dest - (P_)tso);
1684   dest->stack_size = new_stack_size;
1685         
1686   /* and relocate the update frame list */
1687   relocate_TSO(tso, dest);
1688
1689   /* Mark the old one as dead so we don't try to scavenge it during
1690    * garbage collection (the TSO will likely be on a mutables list in
1691    * some generation, but it'll get collected soon enough).  It's
1692    * important to set the sp and su values to just beyond the end of
1693    * the stack, so we don't attempt to scavenge any part of the dead
1694    * TSO's stack.
1695    */
1696   tso->whatNext = ThreadKilled;
1697   tso->sp = (P_)&(tso->stack[tso->stack_size]);
1698   tso->su = (StgUpdateFrame *)tso->sp;
1699   tso->why_blocked = NotBlocked;
1700   dest->mut_link = NULL;
1701
1702   IF_DEBUG(sanity,checkTSO(tso));
1703 #if 0
1704   IF_DEBUG(scheduler,printTSO(dest));
1705 #endif
1706
1707 #if 0
1708   /* This will no longer work: KH */
1709   if (tso == MainTSO) { /* hack */
1710       MainTSO = dest;
1711   }
1712 #endif
1713   return dest;
1714 }
1715
1716 //@node Blocking Queue Routines, Exception Handling Routines, Garbage Collextion Routines, Main scheduling code
1717 //@subsection Blocking Queue Routines
1718
1719 /* ---------------------------------------------------------------------------
1720    Wake up a queue that was blocked on some resource.
1721    ------------------------------------------------------------------------ */
1722
1723 // ToDo: check push_on_run_queue vs. PUSH_ON_RUN_QUEUE
1724
1725 #if defined(GRAN)
1726 static inline void
1727 unblockCount ( StgBlockingQueueElement *bqe, StgClosure *node )
1728 {
1729 }
1730 #elif defined(PAR)
1731 static inline void
1732 unblockCount ( StgBlockingQueueElement *bqe, StgClosure *node )
1733 {
1734   /* write RESUME events to log file and
1735      update blocked and fetch time (depending on type of the orig closure) */
1736   if (RtsFlags.ParFlags.ParStats.Full) {
1737     DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC, 
1738                      GR_RESUMEQ, ((StgTSO *)bqe), ((StgTSO *)bqe)->block_info.closure,
1739                      0, 0 /* spark_queue_len(ADVISORY_POOL) */);
1740
1741     switch (get_itbl(node)->type) {
1742         case FETCH_ME_BQ:
1743           ((StgTSO *)bqe)->par.fetchtime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
1744           break;
1745         case RBH:
1746         case FETCH_ME:
1747         case BLACKHOLE_BQ:
1748           ((StgTSO *)bqe)->par.blocktime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
1749           break;
1750         default:
1751           barf("{unblockOneLocked}Daq Qagh: unexpected closure in blocking queue");
1752         }
1753       }
1754 }
1755 #endif
1756
1757 #if defined(GRAN)
1758 static StgBlockingQueueElement *
1759 unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
1760 {
1761     StgBlockingQueueElement *next;
1762     PEs node_loc, tso_loc;
1763
1764     node_loc = where_is(node); // should be lifted out of loop
1765     tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
1766     tso_loc = where_is(tso);
1767     if (IS_LOCAL_TO(PROCS(node),tso_loc)) { // TSO is local
1768       /* !fake_fetch => TSO is on CurrentProc is same as IS_LOCAL_TO */
1769       ASSERT(CurrentProc!=node_loc || tso_loc==CurrentProc);
1770       bq_processing_time += RtsFlags.GranFlags.Costs.lunblocktime;
1771       // insertThread(tso, node_loc);
1772       new_event(tso_loc, tso_loc,
1773                 CurrentTime[CurrentProc]+bq_processing_time,
1774                 ResumeThread,
1775                 tso, node, (rtsSpark*)NULL);
1776       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
1777       // len_local++;
1778       // len++;
1779     } else { // TSO is remote (actually should be FMBQ)
1780       bq_processing_time += RtsFlags.GranFlags.Costs.mpacktime;
1781       bq_processing_time += RtsFlags.GranFlags.Costs.gunblocktime;
1782       new_event(tso_loc, CurrentProc, 
1783                 CurrentTime[CurrentProc]+bq_processing_time+
1784                 RtsFlags.GranFlags.Costs.latency,
1785                 UnblockThread,
1786                 tso, node, (rtsSpark*)NULL);
1787       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
1788       bq_processing_time += RtsFlags.GranFlags.Costs.mtidytime;
1789       // len++;
1790     }      
1791     /* the thread-queue-overhead is accounted for in either Resume or UnblockThread */
1792     IF_GRAN_DEBUG(bq,
1793                   fprintf(stderr," %s TSO %d (%p) [PE %d] (blocked_on=%p) (next=%p) ,",
1794                           (node_loc==tso_loc ? "Local" : "Global"), 
1795                           tso->id, tso, CurrentProc, tso->blocked_on, tso->link))
1796     tso->blocked_on = NULL;
1797     IF_DEBUG(scheduler,belch("-- Waking up thread %ld (%p)", 
1798                              tso->id, tso));
1799   }
1800
1801   /* if this is the BQ of an RBH, we have to put back the info ripped out of
1802      the closure to make room for the anchor of the BQ */
1803   if (next!=END_BQ_QUEUE) {
1804     ASSERT(get_itbl(node)->type == RBH && get_itbl(next)->type == CONSTR);
1805     /*
1806     ASSERT((info_ptr==&RBH_Save_0_info) ||
1807            (info_ptr==&RBH_Save_1_info) ||
1808            (info_ptr==&RBH_Save_2_info));
1809     */
1810     /* cf. convertToRBH in RBH.c for writing the RBHSave closure */
1811     ((StgRBH *)node)->blocking_queue = ((StgRBHSave *)next)->payload[0];
1812     ((StgRBH *)node)->mut_link       = ((StgRBHSave *)next)->payload[1];
1813
1814     IF_GRAN_DEBUG(bq,
1815                   belch("## Filled in RBH_Save for %p (%s) at end of AwBQ",
1816                         node, info_type(node)));
1817   }
1818 }
1819 #elif defined(PAR)
1820 static StgBlockingQueueElement *
1821 unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
1822 {
1823     StgBlockingQueueElement *next;
1824
1825     switch (get_itbl(bqe)->type) {
1826     case TSO:
1827       ASSERT(((StgTSO *)bqe)->why_blocked != NotBlocked);
1828       /* if it's a TSO just push it onto the run_queue */
1829       next = bqe->link;
1830       // ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging?
1831       PUSH_ON_RUN_QUEUE((StgTSO *)bqe); 
1832       THREAD_RUNNABLE();
1833       unblockCount(bqe, node);
1834       /* reset blocking status after dumping event */
1835       ((StgTSO *)bqe)->why_blocked = NotBlocked;
1836       break;
1837
1838     case BLOCKED_FETCH:
1839       /* if it's a BLOCKED_FETCH put it on the PendingFetches list */
1840       next = bqe->link;
1841       bqe->link = PendingFetches;
1842       PendingFetches = bqe;
1843       break;
1844
1845 # if defined(DEBUG)
1846       /* can ignore this case in a non-debugging setup; 
1847          see comments on RBHSave closures above */
1848     case CONSTR:
1849       /* check that the closure is an RBHSave closure */
1850       ASSERT(get_itbl((StgClosure *)bqe) == &RBH_Save_0_info ||
1851              get_itbl((StgClosure *)bqe) == &RBH_Save_1_info ||
1852              get_itbl((StgClosure *)bqe) == &RBH_Save_2_info);
1853       break;
1854
1855     default:
1856       barf("{unblockOneLocked}Daq Qagh: Unexpected IP (%#lx; %s) in blocking queue at %#lx\n",
1857            get_itbl((StgClosure *)bqe), info_type((StgClosure *)bqe), 
1858            (StgClosure *)bqe);
1859 # endif
1860     }
1861   // IF_DEBUG(scheduler,sched_belch("waking up thread %ld", tso->id));
1862   return next;
1863 }
1864
1865 #else /* !GRAN && !PAR */
1866 static StgTSO *
1867 unblockOneLocked(StgTSO *tso)
1868 {
1869   StgTSO *next;
1870
1871   ASSERT(get_itbl(tso)->type == TSO);
1872   ASSERT(tso->why_blocked != NotBlocked);
1873   tso->why_blocked = NotBlocked;
1874   next = tso->link;
1875   PUSH_ON_RUN_QUEUE(tso);
1876   THREAD_RUNNABLE();
1877   IF_DEBUG(scheduler,sched_belch("waking up thread %ld", tso->id));
1878   return next;
1879 }
1880 #endif
1881
1882 #if defined(GRAN)
1883 inline StgTSO *
1884 unblockOne(StgTSO *tso, StgClosure *node)
1885 {
1886   ACQUIRE_LOCK(&sched_mutex);
1887   tso = unblockOneLocked(tso, node);
1888   RELEASE_LOCK(&sched_mutex);
1889   return tso;
1890 }
1891 #elif defined(PAR)
1892 inline StgTSO *
1893 unblockOne(StgTSO *tso, StgClosure *node)
1894 {
1895   ACQUIRE_LOCK(&sched_mutex);
1896   tso = unblockOneLocked(tso, node);
1897   RELEASE_LOCK(&sched_mutex);
1898   return tso;
1899 }
1900 #else
1901 inline StgTSO *
1902 unblockOne(StgTSO *tso)
1903 {
1904   ACQUIRE_LOCK(&sched_mutex);
1905   tso = unblockOneLocked(tso);
1906   RELEASE_LOCK(&sched_mutex);
1907   return tso;
1908 }
1909 #endif
1910
1911 #if defined(GRAN)
1912 void 
1913 awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
1914 {
1915   StgBlockingQueueElement *bqe, *next;
1916   StgTSO *tso;
1917   PEs node_loc, tso_loc;
1918   rtsTime bq_processing_time = 0;
1919   nat len = 0, len_local = 0;
1920
1921   IF_GRAN_DEBUG(bq, 
1922                 belch("## AwBQ for node %p on PE %d @ %ld by TSO %d (%p): ", \
1923                       node, CurrentProc, CurrentTime[CurrentProc], 
1924                       CurrentTSO->id, CurrentTSO));
1925
1926   node_loc = where_is(node);
1927
1928   ASSERT(get_itbl(q)->type == TSO ||   // q is either a TSO or an RBHSave
1929          get_itbl(q)->type == CONSTR); // closure (type constructor)
1930   ASSERT(is_unique(node));
1931
1932   /* FAKE FETCH: magically copy the node to the tso's proc;
1933      no Fetch necessary because in reality the node should not have been 
1934      moved to the other PE in the first place
1935   */
1936   if (CurrentProc!=node_loc) {
1937     IF_GRAN_DEBUG(bq, 
1938                   belch("## node %p is on PE %d but CurrentProc is %d (TSO %d); assuming fake fetch and adjusting bitmask (old: %#x)",
1939                         node, node_loc, CurrentProc, CurrentTSO->id, 
1940                         // CurrentTSO, where_is(CurrentTSO),
1941                         node->header.gran.procs));
1942     node->header.gran.procs = (node->header.gran.procs) | PE_NUMBER(CurrentProc);
1943     IF_GRAN_DEBUG(bq, 
1944                   belch("## new bitmask of node %p is %#x",
1945                         node, node->header.gran.procs));
1946     if (RtsFlags.GranFlags.GranSimStats.Global) {
1947       globalGranStats.tot_fake_fetches++;
1948     }
1949   }
1950
1951   bqe = q;
1952   // ToDo: check: ASSERT(CurrentProc==node_loc);
1953   while (get_itbl(bqe)->type==TSO) { // q != END_TSO_QUEUE) {
1954     //next = bqe->link;
1955     /* 
1956        bqe points to the current element in the queue
1957        next points to the next element in the queue
1958     */
1959     //tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
1960     //tso_loc = where_is(tso);
1961     bqe = unblockOneLocked(bqe, node);
1962   }
1963
1964   /* statistics gathering */
1965   /* ToDo: fix counters
1966   if (RtsFlags.GranFlags.GranSimStats.Global) {
1967     globalGranStats.tot_bq_processing_time += bq_processing_time;
1968     globalGranStats.tot_bq_len += len;      // total length of all bqs awakened
1969     globalGranStats.tot_bq_len_local += len_local;  // same for local TSOs only
1970     globalGranStats.tot_awbq++;             // total no. of bqs awakened
1971   }
1972   IF_GRAN_DEBUG(bq,
1973                 fprintf(stderr,"## BQ Stats of %p: [%d entries, %d local] %s\n",
1974                         node, len, len_local, (next!=END_TSO_QUEUE) ? "RBH" : ""));
1975   */
1976 }
1977 #elif defined(PAR)
1978 void 
1979 awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
1980 {
1981   StgBlockingQueueElement *bqe, *next;
1982
1983   ACQUIRE_LOCK(&sched_mutex);
1984
1985   IF_PAR_DEBUG(verbose, 
1986                belch("## AwBQ for node %p on [%x]: ",
1987                      node, mytid));
1988
1989   ASSERT(get_itbl(q)->type == TSO ||           
1990          get_itbl(q)->type == BLOCKED_FETCH || 
1991          get_itbl(q)->type == CONSTR); 
1992
1993   bqe = q;
1994   while (get_itbl(bqe)->type==TSO || 
1995          get_itbl(bqe)->type==BLOCKED_FETCH) {
1996     bqe = unblockOneLocked(bqe, node);
1997   }
1998   RELEASE_LOCK(&sched_mutex);
1999 }
2000
2001 #else   /* !GRAN && !PAR */
2002 void
2003 awakenBlockedQueue(StgTSO *tso)
2004 {
2005   ACQUIRE_LOCK(&sched_mutex);
2006   while (tso != END_TSO_QUEUE) {
2007     tso = unblockOneLocked(tso);
2008   }
2009   RELEASE_LOCK(&sched_mutex);
2010 }
2011 #endif
2012
2013 #if 0
2014 // ngoq ngo'
2015
2016 #if defined(GRAN)
2017 /* 
2018    Awakening a blocking queue in GranSim means checking for each of the
2019    TSOs in the queue whether they are local or not, issuing a ResumeThread
2020    or an UnblockThread event, respectively. The basic iteration over the
2021    blocking queue is the same as in the standard setup.  
2022 */
2023 void
2024 awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node)
2025 {
2026   StgBlockingQueueElement *bqe, *next;
2027   StgTSO *tso;
2028   PEs node_loc, tso_loc;
2029   rtsTime bq_processing_time = 0;
2030   nat len = 0, len_local = 0;
2031
2032   IF_GRAN_DEBUG(bq, 
2033                 belch("## AwBQ for node %p on PE %d @ %ld by TSO %d (%p): ", \
2034                       node, CurrentProc, CurrentTime[CurrentProc], 
2035                       CurrentTSO->id, CurrentTSO));
2036
2037   node_loc = where_is(node);
2038
2039   ASSERT(get_itbl(q)->type == TSO ||   // q is either a TSO or an RBHSave
2040          get_itbl(q)->type == CONSTR); // closure (type constructor)
2041   ASSERT(is_unique(node));
2042
2043   /* FAKE FETCH: magically copy the node to the tso's proc;
2044      no Fetch necessary because in reality the node should not have been 
2045      moved to the other PE in the first place
2046   */
2047   if (CurrentProc!=node_loc) {
2048     IF_GRAN_DEBUG(bq, 
2049                   belch("## node %p is on PE %d but CurrentProc is %d (TSO %d); assuming fake fetch and adjusting bitmask (old: %#x)",
2050                         node, node_loc, CurrentProc, CurrentTSO->id, 
2051                         // CurrentTSO, where_is(CurrentTSO),
2052                         node->header.gran.procs));
2053     node->header.gran.procs = (node->header.gran.procs) | PE_NUMBER(CurrentProc);
2054     IF_GRAN_DEBUG(bq, 
2055                   belch("## new bitmask of node %p is %#x",
2056                         node, node->header.gran.procs));
2057     if (RtsFlags.GranFlags.GranSimStats.Global) {
2058       globalGranStats.tot_fake_fetches++;
2059     }
2060   }
2061
2062   next = q;
2063   // ToDo: check: ASSERT(CurrentProc==node_loc);
2064   while (get_itbl(next)->type==TSO) { // q != END_TSO_QUEUE) {
2065     bqe = next;
2066     next = bqe->link;
2067     /* 
2068        bqe points to the current element in the queue
2069        next points to the next element in the queue
2070     */
2071     tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
2072     tso_loc = where_is(tso);
2073     if (IS_LOCAL_TO(PROCS(node),tso_loc)) { // TSO is local
2074       /* !fake_fetch => TSO is on CurrentProc is same as IS_LOCAL_TO */
2075       ASSERT(CurrentProc!=node_loc || tso_loc==CurrentProc);
2076       bq_processing_time += RtsFlags.GranFlags.Costs.lunblocktime;
2077       // insertThread(tso, node_loc);
2078       new_event(tso_loc, tso_loc,
2079                 CurrentTime[CurrentProc]+bq_processing_time,
2080                 ResumeThread,
2081                 tso, node, (rtsSpark*)NULL);
2082       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
2083       len_local++;
2084       len++;
2085     } else { // TSO is remote (actually should be FMBQ)
2086       bq_processing_time += RtsFlags.GranFlags.Costs.mpacktime;
2087       bq_processing_time += RtsFlags.GranFlags.Costs.gunblocktime;
2088       new_event(tso_loc, CurrentProc, 
2089                 CurrentTime[CurrentProc]+bq_processing_time+
2090                 RtsFlags.GranFlags.Costs.latency,
2091                 UnblockThread,
2092                 tso, node, (rtsSpark*)NULL);
2093       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
2094       bq_processing_time += RtsFlags.GranFlags.Costs.mtidytime;
2095       len++;
2096     }      
2097     /* the thread-queue-overhead is accounted for in either Resume or UnblockThread */
2098     IF_GRAN_DEBUG(bq,
2099                   fprintf(stderr," %s TSO %d (%p) [PE %d] (blocked_on=%p) (next=%p) ,",
2100                           (node_loc==tso_loc ? "Local" : "Global"), 
2101                           tso->id, tso, CurrentProc, tso->block_info.closure, tso->link))
2102     tso->block_info.closure = NULL;
2103     IF_DEBUG(scheduler,belch("-- Waking up thread %ld (%p)", 
2104                              tso->id, tso));
2105   }
2106
2107   /* if this is the BQ of an RBH, we have to put back the info ripped out of
2108      the closure to make room for the anchor of the BQ */
2109   if (next!=END_BQ_QUEUE) {
2110     ASSERT(get_itbl(node)->type == RBH && get_itbl(next)->type == CONSTR);
2111     /*
2112     ASSERT((info_ptr==&RBH_Save_0_info) ||
2113            (info_ptr==&RBH_Save_1_info) ||
2114            (info_ptr==&RBH_Save_2_info));
2115     */
2116     /* cf. convertToRBH in RBH.c for writing the RBHSave closure */
2117     ((StgRBH *)node)->blocking_queue = ((StgRBHSave *)next)->payload[0];
2118     ((StgRBH *)node)->mut_link       = ((StgRBHSave *)next)->payload[1];
2119
2120     IF_GRAN_DEBUG(bq,
2121                   belch("## Filled in RBH_Save for %p (%s) at end of AwBQ",
2122                         node, info_type(node)));
2123   }
2124
2125   /* statistics gathering */
2126   if (RtsFlags.GranFlags.GranSimStats.Global) {
2127     globalGranStats.tot_bq_processing_time += bq_processing_time;
2128     globalGranStats.tot_bq_len += len;      // total length of all bqs awakened
2129     globalGranStats.tot_bq_len_local += len_local;  // same for local TSOs only
2130     globalGranStats.tot_awbq++;             // total no. of bqs awakened
2131   }
2132   IF_GRAN_DEBUG(bq,
2133                 fprintf(stderr,"## BQ Stats of %p: [%d entries, %d local] %s\n",
2134                         node, len, len_local, (next!=END_TSO_QUEUE) ? "RBH" : ""));
2135 }
2136
2137 #elif defined(PAR)
2138
2139 /*
2140   Awakening a blocking queue in GUM has to check whether an entry in the
2141   queue is a normal TSO or a BLOCKED_FETCH. The later indicates that a TSO is
2142   waiting for the result of this computation on another PE. Thus, when
2143   finding a BLOCKED_FETCH we have to send off a message to that PE. 
2144   Actually, we defer sending off a message, by just putting the BLOCKED_FETCH
2145   onto the PendingFetches queue, which will be later traversed by
2146   processFetches, sending off a RESUME message for each BLOCKED_FETCH.
2147
2148   NB: There is no check for an RBHSave closure (type CONSTR) in the code 
2149       below. The reason is, if we awaken the BQ of an RBH closure (RBHSaves 
2150       only exist at the end of such BQs) we know that the closure has been
2151       unpacked successfully on the other PE, and we can discard the info
2152       contained in the RBHSave closure. The current closure will be turned 
2153       into a FetchMe closure anyway.
2154 */
2155 void 
2156 awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node)
2157 {
2158   StgBlockingQueueElement *bqe, *next;
2159
2160   IF_PAR_DEBUG(verbose, 
2161                belch("## AwBQ for node %p on [%x]: ",
2162                      node, mytid));
2163
2164   ASSERT(get_itbl(q)->type == TSO ||           
2165          get_itbl(q)->type == BLOCKED_FETCH || 
2166          get_itbl(q)->type == CONSTR); 
2167
2168   next = q;
2169   while (get_itbl(next)->type==TSO || 
2170          get_itbl(next)->type==BLOCKED_FETCH) {
2171     bqe = next;
2172     switch (get_itbl(bqe)->type) {
2173     case TSO:
2174       /* if it's a TSO just push it onto the run_queue */
2175       next = bqe->link;
2176 #if defined(DEBUG)
2177       ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging only
2178 #endif
2179       push_on_run_queue((StgTSO *)bqe); // HWL: was: PUSH_ON_RUN_QUEUE(tso);
2180
2181       /* write RESUME events to log file and
2182          update blocked and fetch time (depending on type of the orig closure) */
2183       if (RtsFlags.ParFlags.ParStats.Full) {
2184         DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC, 
2185                          GR_RESUMEQ, ((StgTSO *)bqe), ((StgTSO *)bqe)->block_info.closure,
2186                          0, spark_queue_len(ADVISORY_POOL));
2187
2188         switch (get_itbl(node)->type) {
2189         case FETCH_ME_BQ:
2190           ((StgTSO *)bqe)->par.fetchtime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
2191           break;
2192         case RBH:
2193         case FETCH_ME:
2194         case BLACKHOLE_BQ:
2195           ((StgTSO *)bqe)->par.blocktime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
2196           break;
2197         default:
2198           barf("{awaken_blocked_queue}Daq Qagh: unexpected closure %p (%s) with blocking queue",
2199                node, info_type(node));
2200         }
2201       }
2202       /* reset block_info.closure field after dumping event */
2203       ((StgTSO *)bqe)->block_info.closure = NULL;
2204
2205       /* rest of this branch is debugging only */
2206       IF_PAR_DEBUG(verbose,
2207                    fprintf(stderr," TSO %d (%p) [PE %lx] (block_info.closure=%p) (next=%p) ,",
2208                            ((StgTSO *)bqe)->id, (StgTSO *)bqe,
2209                            mytid, ((StgTSO *)bqe)->block_info.closure, ((StgTSO *)bqe)->link));
2210
2211       IF_DEBUG(scheduler,
2212                if (!RtsFlags.ParFlags.Debug.verbose)
2213                  belch("-- Waking up thread %ld (%p)", 
2214                        ((StgTSO *)bqe)->id, (StgTSO *)bqe));
2215       break;
2216
2217     case BLOCKED_FETCH:
2218       /* if it's a BLOCKED_FETCH put it on the PendingFetches list */
2219       next = bqe->link;
2220       bqe->link = PendingFetches;
2221       PendingFetches = bqe;
2222       // bqe.tso->block_info.closure = NULL;
2223
2224       /* rest of this branch is debugging only */
2225       IF_PAR_DEBUG(verbose,
2226                    fprintf(stderr," BLOCKED_FETCH (%p) on node %p [PE %lx] (next=%p) ,",
2227                            ((StgBlockedFetch *)bqe), 
2228                            ((StgBlockedFetch *)bqe)->node, 
2229                            mytid, ((StgBlockedFetch *)bqe)->link));
2230       break;
2231
2232 # if defined(DEBUG)
2233       /* can ignore this case in a non-debugging setup; 
2234          see comments on RBHSave closures above */
2235     case CONSTR:
2236       /* check that the closure is an RBHSave closure */
2237       ASSERT(get_itbl((StgClosure *)bqe) == &RBH_Save_0_info ||
2238              get_itbl((StgClosure *)bqe) == &RBH_Save_1_info ||
2239              get_itbl((StgClosure *)bqe) == &RBH_Save_2_info);
2240       break;
2241
2242     default:
2243       barf("{awaken_blocked_queue}Daq Qagh: Unexpected IP (%#lx; %s) in blocking queue at %#lx\n",
2244            get_itbl((StgClosure *)bqe), info_type((StgClosure *)bqe), 
2245            (StgClosure *)bqe);
2246 # endif
2247     }
2248   }
2249 }
2250
2251 #else /* !GRAN && !PAR */
2252
2253 void 
2254 awaken_blocked_queue(StgTSO *q) { awakenBlockedQueue(q); }
2255
2256 /*
2257 {
2258   StgTSO *tso;
2259
2260   while (q != END_TSO_QUEUE) {
2261     ASSERT(get_itbl(q)->type == TSO);
2262     tso = q;
2263     q = tso->link;
2264     push_on_run_queue(tso); // HWL: was: PUSH_ON_RUN_QUEUE(tso);
2265     //tso->block_info.closure = NULL;
2266     IF_DEBUG(scheduler, belch("-- Waking up thread %ld (%p)", tso->id, tso));
2267   }
2268 }
2269 */
2270 #endif /* GRAN */
2271 #endif /* 0 */
2272
2273 //@node Exception Handling Routines, Debugging Routines, Blocking Queue Routines, Main scheduling code
2274 //@subsection Exception Handling Routines
2275
2276 /* ---------------------------------------------------------------------------
2277    Interrupt execution
2278    - usually called inside a signal handler so it mustn't do anything fancy.   
2279    ------------------------------------------------------------------------ */
2280
2281 void
2282 interruptStgRts(void)
2283 {
2284     interrupted    = 1;
2285     context_switch = 1;
2286 }
2287
2288 /* -----------------------------------------------------------------------------
2289    Unblock a thread
2290
2291    This is for use when we raise an exception in another thread, which
2292    may be blocked.
2293    This has nothing to do with the UnblockThread event in GranSim. -- HWL
2294    -------------------------------------------------------------------------- */
2295
2296 static void
2297 unblockThread(StgTSO *tso)
2298 {
2299   StgTSO *t, **last;
2300
2301   ACQUIRE_LOCK(&sched_mutex);
2302   switch (tso->why_blocked) {
2303
2304   case NotBlocked:
2305     return;  /* not blocked */
2306
2307   case BlockedOnMVar:
2308     ASSERT(get_itbl(tso->block_info.closure)->type == MVAR);
2309     {
2310       StgTSO *last_tso = END_TSO_QUEUE;
2311       StgMVar *mvar = (StgMVar *)(tso->block_info.closure);
2312
2313       last = &mvar->head;
2314       for (t = mvar->head; t != END_TSO_QUEUE; 
2315            last = &t->link, last_tso = t, t = t->link) {
2316         if (t == tso) {
2317           *last = tso->link;
2318           if (mvar->tail == tso) {
2319             mvar->tail = last_tso;
2320           }
2321           goto done;
2322         }
2323       }
2324       barf("unblockThread (MVAR): TSO not found");
2325     }
2326
2327   case BlockedOnBlackHole:
2328     ASSERT(get_itbl(tso->block_info.closure)->type == BLACKHOLE_BQ);
2329     {
2330       StgBlockingQueue *bq = (StgBlockingQueue *)(tso->block_info.closure);
2331
2332       last = &bq->blocking_queue;
2333       for (t = bq->blocking_queue; t != END_TSO_QUEUE; 
2334            last = &t->link, t = t->link) {
2335         if (t == tso) {
2336           *last = tso->link;
2337           goto done;
2338         }
2339       }
2340       barf("unblockThread (BLACKHOLE): TSO not found");
2341     }
2342
2343   case BlockedOnException:
2344     {
2345       StgTSO *target  = tso->block_info.tso;
2346
2347       ASSERT(get_itbl(target)->type == TSO);
2348       ASSERT(target->blocked_exceptions != NULL);
2349
2350       last = &target->blocked_exceptions;
2351       for (t = target->blocked_exceptions; t != END_TSO_QUEUE; 
2352            last = &t->link, t = t->link) {
2353         ASSERT(get_itbl(t)->type == TSO);
2354         if (t == tso) {
2355           *last = tso->link;
2356           goto done;
2357         }
2358       }
2359       barf("unblockThread (Exception): TSO not found");
2360     }
2361
2362   case BlockedOnDelay:
2363   case BlockedOnRead:
2364   case BlockedOnWrite:
2365     {
2366       StgTSO *prev = NULL;
2367       for (t = blocked_queue_hd; t != END_TSO_QUEUE; 
2368            prev = t, t = t->link) {
2369         if (t == tso) {
2370           if (prev == NULL) {
2371             blocked_queue_hd = t->link;
2372             if (blocked_queue_tl == t) {
2373               blocked_queue_tl = END_TSO_QUEUE;
2374             }
2375           } else {
2376             prev->link = t->link;
2377             if (blocked_queue_tl == t) {
2378               blocked_queue_tl = prev;
2379             }
2380           }
2381           goto done;
2382         }
2383       }
2384       barf("unblockThread (I/O): TSO not found");
2385     }
2386
2387   default:
2388     barf("unblockThread");
2389   }
2390
2391  done:
2392   tso->link = END_TSO_QUEUE;
2393   tso->why_blocked = NotBlocked;
2394   tso->block_info.closure = NULL;
2395   PUSH_ON_RUN_QUEUE(tso);
2396   RELEASE_LOCK(&sched_mutex);
2397 }
2398
2399 /* -----------------------------------------------------------------------------
2400  * raiseAsync()
2401  *
2402  * The following function implements the magic for raising an
2403  * asynchronous exception in an existing thread.
2404  *
2405  * We first remove the thread from any queue on which it might be
2406  * blocked.  The possible blockages are MVARs and BLACKHOLE_BQs.
2407  *
2408  * We strip the stack down to the innermost CATCH_FRAME, building
2409  * thunks in the heap for all the active computations, so they can 
2410  * be restarted if necessary.  When we reach a CATCH_FRAME, we build
2411  * an application of the handler to the exception, and push it on
2412  * the top of the stack.
2413  * 
2414  * How exactly do we save all the active computations?  We create an
2415  * AP_UPD for every UpdateFrame on the stack.  Entering one of these
2416  * AP_UPDs pushes everything from the corresponding update frame
2417  * upwards onto the stack.  (Actually, it pushes everything up to the
2418  * next update frame plus a pointer to the next AP_UPD object.
2419  * Entering the next AP_UPD object pushes more onto the stack until we
2420  * reach the last AP_UPD object - at which point the stack should look
2421  * exactly as it did when we killed the TSO and we can continue
2422  * execution by entering the closure on top of the stack.
2423  *
2424  * We can also kill a thread entirely - this happens if either (a) the 
2425  * exception passed to raiseAsync is NULL, or (b) there's no
2426  * CATCH_FRAME on the stack.  In either case, we strip the entire
2427  * stack and replace the thread with a zombie.
2428  *
2429  * -------------------------------------------------------------------------- */
2430  
2431 void 
2432 deleteThread(StgTSO *tso)
2433 {
2434   raiseAsync(tso,NULL);
2435 }
2436
2437 void
2438 raiseAsync(StgTSO *tso, StgClosure *exception)
2439 {
2440   StgUpdateFrame* su = tso->su;
2441   StgPtr          sp = tso->sp;
2442   
2443   /* Thread already dead? */
2444   if (tso->whatNext == ThreadComplete || tso->whatNext == ThreadKilled) {
2445     return;
2446   }
2447
2448   IF_DEBUG(scheduler, sched_belch("raising exception in thread %ld.", tso->id));
2449
2450   /* Remove it from any blocking queues */
2451   unblockThread(tso);
2452
2453   /* The stack freezing code assumes there's a closure pointer on
2454    * the top of the stack.  This isn't always the case with compiled
2455    * code, so we have to push a dummy closure on the top which just
2456    * returns to the next return address on the stack.
2457    */
2458   if ( LOOKS_LIKE_GHC_INFO((void*)*sp) ) {
2459     *(--sp) = (W_)&dummy_ret_closure;
2460   }
2461
2462   while (1) {
2463     int words = ((P_)su - (P_)sp) - 1;
2464     nat i;
2465     StgAP_UPD * ap;
2466
2467     /* If we find a CATCH_FRAME, and we've got an exception to raise,
2468      * then build PAP(handler,exception), and leave it on top of
2469      * the stack ready to enter.
2470      */
2471     if (get_itbl(su)->type == CATCH_FRAME && exception != NULL) {
2472       StgCatchFrame *cf = (StgCatchFrame *)su;
2473       /* we've got an exception to raise, so let's pass it to the
2474        * handler in this frame.
2475        */
2476       ap = (StgAP_UPD *)allocate(sizeofW(StgPAP) + 1);
2477       TICK_ALLOC_UPD_PAP(2,0);
2478       SET_HDR(ap,&PAP_info,cf->header.prof.ccs);
2479               
2480       ap->n_args = 1;
2481       ap->fun = cf->handler;
2482       ap->payload[0] = (P_)exception;
2483
2484       /* sp currently points to the word above the CATCH_FRAME on the stack.
2485        */
2486       sp += sizeofW(StgCatchFrame);
2487       tso->su = cf->link;
2488
2489       /* Restore the blocked/unblocked state for asynchronous exceptions
2490        * at the CATCH_FRAME.  
2491        *
2492        * If exceptions were unblocked at the catch, arrange that they
2493        * are unblocked again after executing the handler by pushing an
2494        * unblockAsyncExceptions_ret stack frame.
2495        */
2496       if (!cf->exceptions_blocked) {
2497         *(sp--) = (W_)&unblockAsyncExceptionszh_ret_info;
2498       }
2499       
2500       /* Ensure that async exceptions are blocked when running the handler.
2501        */
2502       if (tso->blocked_exceptions == NULL) {
2503         tso->blocked_exceptions = END_TSO_QUEUE;
2504       }
2505       
2506       /* Put the newly-built PAP on top of the stack, ready to execute
2507        * when the thread restarts.
2508        */
2509       sp[0] = (W_)ap;
2510       tso->sp = sp;
2511       tso->whatNext = ThreadEnterGHC;
2512       return;
2513     }
2514
2515     /* First build an AP_UPD consisting of the stack chunk above the
2516      * current update frame, with the top word on the stack as the
2517      * fun field.
2518      */
2519     ap = (StgAP_UPD *)allocate(AP_sizeW(words));
2520     
2521     ASSERT(words >= 0);
2522     
2523     ap->n_args = words;
2524     ap->fun    = (StgClosure *)sp[0];
2525     sp++;
2526     for(i=0; i < (nat)words; ++i) {
2527       ap->payload[i] = (P_)*sp++;
2528     }
2529     
2530     switch (get_itbl(su)->type) {
2531       
2532     case UPDATE_FRAME:
2533       {
2534         SET_HDR(ap,&AP_UPD_info,su->header.prof.ccs /* ToDo */); 
2535         TICK_ALLOC_UP_THK(words+1,0);
2536         
2537         IF_DEBUG(scheduler,
2538                  fprintf(stderr,  "scheduler: Updating ");
2539                  printPtr((P_)su->updatee); 
2540                  fprintf(stderr,  " with ");
2541                  printObj((StgClosure *)ap);
2542                  );
2543         
2544         /* Replace the updatee with an indirection - happily
2545          * this will also wake up any threads currently
2546          * waiting on the result.
2547          */
2548         UPD_IND_NOLOCK(su->updatee,ap);  /* revert the black hole */
2549         su = su->link;
2550         sp += sizeofW(StgUpdateFrame) -1;
2551         sp[0] = (W_)ap; /* push onto stack */
2552         break;
2553       }
2554       
2555     case CATCH_FRAME:
2556       {
2557         StgCatchFrame *cf = (StgCatchFrame *)su;
2558         StgClosure* o;
2559         
2560         /* We want a PAP, not an AP_UPD.  Fortunately, the
2561          * layout's the same.
2562          */
2563         SET_HDR(ap,&PAP_info,su->header.prof.ccs /* ToDo */);
2564         TICK_ALLOC_UPD_PAP(words+1,0);
2565         
2566         /* now build o = FUN(catch,ap,handler) */
2567         o = (StgClosure *)allocate(sizeofW(StgClosure)+2);
2568         TICK_ALLOC_FUN(2,0);
2569         SET_HDR(o,&catch_info,su->header.prof.ccs /* ToDo */);
2570         o->payload[0] = (StgClosure *)ap;
2571         o->payload[1] = cf->handler;
2572         
2573         IF_DEBUG(scheduler,
2574                  fprintf(stderr,  "scheduler: Built ");
2575                  printObj((StgClosure *)o);
2576                  );
2577         
2578         /* pop the old handler and put o on the stack */
2579         su = cf->link;
2580         sp += sizeofW(StgCatchFrame) - 1;
2581         sp[0] = (W_)o;
2582         break;
2583       }
2584       
2585     case SEQ_FRAME:
2586       {
2587         StgSeqFrame *sf = (StgSeqFrame *)su;
2588         StgClosure* o;
2589         
2590         SET_HDR(ap,&PAP_info,su->header.prof.ccs /* ToDo */);
2591         TICK_ALLOC_UPD_PAP(words+1,0);
2592         
2593         /* now build o = FUN(seq,ap) */
2594         o = (StgClosure *)allocate(sizeofW(StgClosure)+1);
2595         TICK_ALLOC_SE_THK(1,0);
2596         SET_HDR(o,&seq_info,su->header.prof.ccs /* ToDo */);
2597         payloadCPtr(o,0) = (StgClosure *)ap;
2598         
2599         IF_DEBUG(scheduler,
2600                  fprintf(stderr,  "scheduler: Built ");
2601                  printObj((StgClosure *)o);
2602                  );
2603         
2604         /* pop the old handler and put o on the stack */
2605         su = sf->link;
2606         sp += sizeofW(StgSeqFrame) - 1;
2607         sp[0] = (W_)o;
2608         break;
2609       }
2610       
2611     case STOP_FRAME:
2612       /* We've stripped the entire stack, the thread is now dead. */
2613       sp += sizeofW(StgStopFrame) - 1;
2614       sp[0] = (W_)exception;    /* save the exception */
2615       tso->whatNext = ThreadKilled;
2616       tso->su = (StgUpdateFrame *)(sp+1);
2617       tso->sp = sp;
2618       return;
2619       
2620     default:
2621       barf("raiseAsync");
2622     }
2623   }
2624   barf("raiseAsync");
2625 }
2626
2627 //@node Debugging Routines, Index, Exception Handling Routines, Main scheduling code
2628 //@subsection Debugging Routines
2629
2630 /* -----------------------------------------------------------------------------
2631    Debugging: why is a thread blocked
2632    -------------------------------------------------------------------------- */
2633
2634 #ifdef DEBUG
2635
2636 void printThreadBlockage(StgTSO *tso)
2637 {
2638   switch (tso->why_blocked) {
2639   case BlockedOnRead:
2640     fprintf(stderr,"blocked on read from fd %d", tso->block_info.fd);
2641     break;
2642   case BlockedOnWrite:
2643     fprintf(stderr,"blocked on write to fd %d", tso->block_info.fd);
2644     break;
2645   case BlockedOnDelay:
2646     fprintf(stderr,"blocked on delay of %d ms", tso->block_info.delay);
2647     break;
2648   case BlockedOnMVar:
2649     fprintf(stderr,"blocked on an MVar");
2650     break;
2651   case BlockedOnException:
2652     fprintf(stderr,"blocked on delivering an exception to thread %d",
2653             tso->block_info.tso->id);
2654     break;
2655   case BlockedOnBlackHole:
2656     fprintf(stderr,"blocked on a black hole");
2657     break;
2658   case NotBlocked:
2659     fprintf(stderr,"not blocked");
2660     break;
2661 #if defined(PAR)
2662   case BlockedOnGA:
2663     fprintf(stderr,"blocked on global address");
2664     break;
2665 #endif
2666   }
2667 }
2668
2669 /* 
2670    Print a whole blocking queue attached to node (debugging only).
2671 */
2672 //@cindex print_bq
2673 # if defined(PAR)
2674 void 
2675 print_bq (StgClosure *node)
2676 {
2677   StgBlockingQueueElement *bqe;
2678   StgTSO *tso;
2679   rtsBool end;
2680
2681   fprintf(stderr,"## BQ of closure %p (%s): ",
2682           node, info_type(node));
2683
2684   /* should cover all closures that may have a blocking queue */
2685   ASSERT(get_itbl(node)->type == BLACKHOLE_BQ ||
2686          get_itbl(node)->type == FETCH_ME_BQ ||
2687          get_itbl(node)->type == RBH);
2688     
2689   ASSERT(node!=(StgClosure*)NULL);         // sanity check
2690   /* 
2691      NB: In a parallel setup a BQ of an RBH must end with an RBH_Save closure;
2692   */
2693   for (bqe = ((StgBlockingQueue*)node)->blocking_queue, end = (bqe==END_BQ_QUEUE);
2694        !end; // iterate until bqe points to a CONSTR
2695        end = (get_itbl(bqe)->type == CONSTR) || (bqe->link==END_BQ_QUEUE), bqe = end ? END_BQ_QUEUE : bqe->link) {
2696     ASSERT(bqe != END_BQ_QUEUE);             // sanity check
2697     ASSERT(bqe != (StgTSO*)NULL);            // sanity check
2698     /* types of closures that may appear in a blocking queue */
2699     ASSERT(get_itbl(bqe)->type == TSO ||           
2700            get_itbl(bqe)->type == BLOCKED_FETCH || 
2701            get_itbl(bqe)->type == CONSTR); 
2702     /* only BQs of an RBH end with an RBH_Save closure */
2703     ASSERT(get_itbl(bqe)->type != CONSTR || get_itbl(node)->type == RBH);
2704
2705     switch (get_itbl(bqe)->type) {
2706     case TSO:
2707       fprintf(stderr," TSO %d (%x),",
2708               ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
2709       break;
2710     case BLOCKED_FETCH:
2711       fprintf(stderr," BF (node=%p, ga=((%x, %d, %x)),",
2712               ((StgBlockedFetch *)bqe)->node, 
2713               ((StgBlockedFetch *)bqe)->ga.payload.gc.gtid,
2714               ((StgBlockedFetch *)bqe)->ga.payload.gc.slot,
2715               ((StgBlockedFetch *)bqe)->ga.weight);
2716       break;
2717     case CONSTR:
2718       fprintf(stderr," %s (IP %p),",
2719               (get_itbl(bqe) == &RBH_Save_0_info ? "RBH_Save_0" :
2720                get_itbl(bqe) == &RBH_Save_1_info ? "RBH_Save_1" :
2721                get_itbl(bqe) == &RBH_Save_2_info ? "RBH_Save_2" :
2722                "RBH_Save_?"), get_itbl(bqe));
2723       break;
2724     default:
2725       barf("Unexpected closure type %s in blocking queue of %p (%s)",
2726            info_type(bqe), node, info_type(node));
2727       break;
2728     }
2729   } /* for */
2730   fputc('\n', stderr);
2731 }
2732 # elif defined(GRAN)
2733 void 
2734 print_bq (StgClosure *node)
2735 {
2736   StgBlockingQueueElement *bqe;
2737   StgTSO *tso;
2738   PEs node_loc, tso_loc;
2739   rtsBool end;
2740
2741   /* should cover all closures that may have a blocking queue */
2742   ASSERT(get_itbl(node)->type == BLACKHOLE_BQ ||
2743          get_itbl(node)->type == FETCH_ME_BQ ||
2744          get_itbl(node)->type == RBH);
2745     
2746   ASSERT(node!=(StgClosure*)NULL);         // sanity check
2747   node_loc = where_is(node);
2748
2749   fprintf(stderr,"## BQ of closure %p (%s) on [PE %d]: ",
2750           node, info_type(node), node_loc);
2751
2752   /* 
2753      NB: In a parallel setup a BQ of an RBH must end with an RBH_Save closure;
2754   */
2755   for (bqe = ((StgBlockingQueue*)node)->blocking_queue, end = (bqe==END_BQ_QUEUE);
2756        !end; // iterate until bqe points to a CONSTR
2757        end = (get_itbl(bqe)->type == CONSTR) || (bqe->link==END_BQ_QUEUE), bqe = end ? END_BQ_QUEUE : bqe->link) {
2758     ASSERT(bqe != END_BQ_QUEUE);             // sanity check
2759     ASSERT(bqe != (StgTSO*)NULL);            // sanity check
2760     /* types of closures that may appear in a blocking queue */
2761     ASSERT(get_itbl(bqe)->type == TSO ||           
2762            get_itbl(bqe)->type == CONSTR); 
2763     /* only BQs of an RBH end with an RBH_Save closure */
2764     ASSERT(get_itbl(bqe)->type != CONSTR || get_itbl(node)->type == RBH);
2765
2766     tso_loc = where_is((StgClosure *)bqe);
2767     switch (get_itbl(bqe)->type) {
2768     case TSO:
2769       fprintf(stderr," TSO %d (%x) on [PE %d],",
2770               ((StgTSO *)bqe)->id, ((StgTSO *)bqe), tso_loc);
2771       break;
2772     case CONSTR:
2773       fprintf(stderr," %s (IP %p),",
2774               (get_itbl(bqe) == &RBH_Save_0_info ? "RBH_Save_0" :
2775                get_itbl(bqe) == &RBH_Save_1_info ? "RBH_Save_1" :
2776                get_itbl(bqe) == &RBH_Save_2_info ? "RBH_Save_2" :
2777                "RBH_Save_?"), get_itbl(bqe));
2778       break;
2779     default:
2780       barf("Unexpected closure type %s in blocking queue of %p (%s)",
2781            info_type(bqe), node, info_type(node));
2782       break;
2783     }
2784   } /* for */
2785   fputc('\n', stderr);
2786 }
2787 #else
2788 /* 
2789    Nice and easy: only TSOs on the blocking queue
2790 */
2791 void 
2792 print_bq (StgClosure *node)
2793 {
2794   StgTSO *tso;
2795
2796   ASSERT(node!=(StgClosure*)NULL);         // sanity check
2797   for (tso = ((StgBlockingQueue*)node)->blocking_queue;
2798        tso != END_TSO_QUEUE; 
2799        tso=tso->link) {
2800     ASSERT(tso!=(StgTSO*)NULL && tso!=END_TSO_QUEUE);   // sanity check
2801     ASSERT(get_itbl(tso)->type == TSO);  // guess what, sanity check
2802     fprintf(stderr," TSO %d (%p),", tso->id, tso);
2803   }
2804   fputc('\n', stderr);
2805 }
2806 # endif
2807
2808 /* A debugging function used all over the place in GranSim and GUM.
2809    Dummy function in other setups.
2810 */
2811
2812 static void
2813 sched_belch(char *s, ...)
2814 {
2815   va_list ap;
2816   va_start(ap,s);
2817 #ifdef SMP
2818   fprintf(stderr, "scheduler (task %ld): ", pthread_self());
2819 #else
2820   fprintf(stderr, "scheduler: ");
2821 #endif
2822   vfprintf(stderr, s, ap);
2823   fprintf(stderr, "\n");
2824 }
2825
2826 #endif /* DEBUG */
2827
2828 //@node Index,  , Debugging Routines, Main scheduling code
2829 //@subsection Index
2830
2831 //@index
2832 //* MainRegTable::  @cindex\s-+MainRegTable
2833 //* StgMainThread::  @cindex\s-+StgMainThread
2834 //* awaken_blocked_queue::  @cindex\s-+awaken_blocked_queue
2835 //* blocked_queue_hd::  @cindex\s-+blocked_queue_hd
2836 //* blocked_queue_tl::  @cindex\s-+blocked_queue_tl
2837 //* context_switch::  @cindex\s-+context_switch
2838 //* createThread::  @cindex\s-+createThread
2839 //* free_capabilities::  @cindex\s-+free_capabilities
2840 //* gc_pending_cond::  @cindex\s-+gc_pending_cond
2841 //* initScheduler::  @cindex\s-+initScheduler
2842 //* interrupted::  @cindex\s-+interrupted
2843 //* n_free_capabilities::  @cindex\s-+n_free_capabilities
2844 //* next_thread_id::  @cindex\s-+next_thread_id
2845 //* print_bq::  @cindex\s-+print_bq
2846 //* run_queue_hd::  @cindex\s-+run_queue_hd
2847 //* run_queue_tl::  @cindex\s-+run_queue_tl
2848 //* sched_mutex::  @cindex\s-+sched_mutex
2849 //* schedule::  @cindex\s-+schedule
2850 //* take_off_run_queue::  @cindex\s-+take_off_run_queue
2851 //* task_ids::  @cindex\s-+task_ids
2852 //* term_mutex::  @cindex\s-+term_mutex
2853 //* thread_ready_cond::  @cindex\s-+thread_ready_cond
2854 //@end index