[project @ 2000-01-14 11:45:21 by hwloidl]
[ghc-hetmet.git] / ghc / rts / Schedule.c
1 /* ---------------------------------------------------------------------------
2  * $Id: Schedule.c,v 1.42 2000/01/14 11:45:21 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   nat i;
1549
1550 #if defined(GRAN)
1551   for (i=0; i<=RtsFlags.GranFlags.proc; i++) {
1552     if ((run_queue_hds[i] != END_TSO_QUEUE) && ((run_queue_hds[i] != NULL)))
1553       run_queue_hds[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_hds[i]);
1554     if ((run_queue_tls[i] != END_TSO_QUEUE) && ((run_queue_tls[i] != NULL)))
1555       run_queue_tls[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_tls[i]);
1556     
1557     if ((blocked_queue_hds[i] != END_TSO_QUEUE) && ((blocked_queue_hds[i] != NULL)))
1558       blocked_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hds[i]);
1559     if ((blocked_queue_tls[i] != END_TSO_QUEUE) && ((blocked_queue_tls[i] != NULL)))
1560       blocked_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tls[i]);
1561     if ((ccalling_threadss[i] != END_TSO_QUEUE) && ((ccalling_threadss[i] != NULL)))
1562       ccalling_threadss[i] = (StgTSO *)MarkRoot((StgClosure *)ccalling_threadss[i]);
1563   }
1564
1565   markEventQueue();
1566 #elif defined(PAR)
1567   run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
1568   run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
1569   blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
1570   blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
1571 #else
1572   run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
1573   run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
1574
1575   blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
1576   blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
1577 #endif 
1578
1579   for (m = main_threads; m != NULL; m = m->link) {
1580     m->tso = (StgTSO *)MarkRoot((StgClosure *)m->tso);
1581   }
1582   suspended_ccalling_threads = 
1583     (StgTSO *)MarkRoot((StgClosure *)suspended_ccalling_threads);
1584
1585 #if defined(SMP) || defined(PAR) || defined(GRAN)
1586   markSparkQueue();
1587 #endif
1588 }
1589
1590 /* -----------------------------------------------------------------------------
1591    performGC
1592
1593    This is the interface to the garbage collector from Haskell land.
1594    We provide this so that external C code can allocate and garbage
1595    collect when called from Haskell via _ccall_GC.
1596
1597    It might be useful to provide an interface whereby the programmer
1598    can specify more roots (ToDo).
1599    
1600    This needs to be protected by the GC condition variable above.  KH.
1601    -------------------------------------------------------------------------- */
1602
1603 void (*extra_roots)(void);
1604
1605 void
1606 performGC(void)
1607 {
1608   GarbageCollect(GetRoots);
1609 }
1610
1611 static void
1612 AllRoots(void)
1613 {
1614   GetRoots();                   /* the scheduler's roots */
1615   extra_roots();                /* the user's roots */
1616 }
1617
1618 void
1619 performGCWithRoots(void (*get_roots)(void))
1620 {
1621   extra_roots = get_roots;
1622
1623   GarbageCollect(AllRoots);
1624 }
1625
1626 /* -----------------------------------------------------------------------------
1627    Stack overflow
1628
1629    If the thread has reached its maximum stack size,
1630    then bomb out.  Otherwise relocate the TSO into a larger chunk of
1631    memory and adjust its stack size appropriately.
1632    -------------------------------------------------------------------------- */
1633
1634 static StgTSO *
1635 threadStackOverflow(StgTSO *tso)
1636 {
1637   nat new_stack_size, new_tso_size, diff, stack_words;
1638   StgPtr new_sp;
1639   StgTSO *dest;
1640
1641   if (tso->stack_size >= tso->max_stack_size) {
1642 #if 0
1643     /* If we're debugging, just print out the top of the stack */
1644     printStackChunk(tso->sp, stg_min(tso->stack+tso->stack_size, 
1645                                      tso->sp+64));
1646 #endif
1647 #ifdef INTERPRETER
1648     fprintf(stderr, "fatal: stack overflow in Hugs; aborting\n" );
1649     exit(1);
1650 #else
1651     /* Send this thread the StackOverflow exception */
1652     raiseAsync(tso, (StgClosure *)&stackOverflow_closure);
1653 #endif
1654     return tso;
1655   }
1656
1657   /* Try to double the current stack size.  If that takes us over the
1658    * maximum stack size for this thread, then use the maximum instead.
1659    * Finally round up so the TSO ends up as a whole number of blocks.
1660    */
1661   new_stack_size = stg_min(tso->stack_size * 2, tso->max_stack_size);
1662   new_tso_size   = (nat)BLOCK_ROUND_UP(new_stack_size * sizeof(W_) + 
1663                                        TSO_STRUCT_SIZE)/sizeof(W_);
1664   new_tso_size = round_to_mblocks(new_tso_size);  /* Be MBLOCK-friendly */
1665   new_stack_size = new_tso_size - TSO_STRUCT_SIZEW;
1666
1667   IF_DEBUG(scheduler, fprintf(stderr,"scheduler: increasing stack size from %d words to %d.\n", tso->stack_size, new_stack_size));
1668
1669   dest = (StgTSO *)allocate(new_tso_size);
1670   TICK_ALLOC_TSO(new_tso_size-sizeofW(StgTSO),0);
1671
1672   /* copy the TSO block and the old stack into the new area */
1673   memcpy(dest,tso,TSO_STRUCT_SIZE);
1674   stack_words = tso->stack + tso->stack_size - tso->sp;
1675   new_sp = (P_)dest + new_tso_size - stack_words;
1676   memcpy(new_sp, tso->sp, stack_words * sizeof(W_));
1677
1678   /* relocate the stack pointers... */
1679   diff = (P_)new_sp - (P_)tso->sp; /* In *words* */
1680   dest->su    = (StgUpdateFrame *) ((P_)dest->su + diff);
1681   dest->sp    = new_sp;
1682   dest->splim = (P_)dest->splim + (nat)((P_)dest - (P_)tso);
1683   dest->stack_size = new_stack_size;
1684         
1685   /* and relocate the update frame list */
1686   relocate_TSO(tso, dest);
1687
1688   /* Mark the old one as dead so we don't try to scavenge it during
1689    * garbage collection (the TSO will likely be on a mutables list in
1690    * some generation, but it'll get collected soon enough).  It's
1691    * important to set the sp and su values to just beyond the end of
1692    * the stack, so we don't attempt to scavenge any part of the dead
1693    * TSO's stack.
1694    */
1695   tso->whatNext = ThreadKilled;
1696   tso->sp = (P_)&(tso->stack[tso->stack_size]);
1697   tso->su = (StgUpdateFrame *)tso->sp;
1698   tso->why_blocked = NotBlocked;
1699   dest->mut_link = NULL;
1700
1701   IF_DEBUG(sanity,checkTSO(tso));
1702 #if 0
1703   IF_DEBUG(scheduler,printTSO(dest));
1704 #endif
1705
1706 #if 0
1707   /* This will no longer work: KH */
1708   if (tso == MainTSO) { /* hack */
1709       MainTSO = dest;
1710   }
1711 #endif
1712   return dest;
1713 }
1714
1715 //@node Blocking Queue Routines, Exception Handling Routines, Garbage Collextion Routines, Main scheduling code
1716 //@subsection Blocking Queue Routines
1717
1718 /* ---------------------------------------------------------------------------
1719    Wake up a queue that was blocked on some resource.
1720    ------------------------------------------------------------------------ */
1721
1722 // ToDo: check push_on_run_queue vs. PUSH_ON_RUN_QUEUE
1723
1724 #if defined(GRAN)
1725 static inline void
1726 unblockCount ( StgBlockingQueueElement *bqe, StgClosure *node )
1727 {
1728 }
1729 #elif defined(PAR)
1730 static inline void
1731 unblockCount ( StgBlockingQueueElement *bqe, StgClosure *node )
1732 {
1733   /* write RESUME events to log file and
1734      update blocked and fetch time (depending on type of the orig closure) */
1735   if (RtsFlags.ParFlags.ParStats.Full) {
1736     DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC, 
1737                      GR_RESUMEQ, ((StgTSO *)bqe), ((StgTSO *)bqe)->block_info.closure,
1738                      0, 0 /* spark_queue_len(ADVISORY_POOL) */);
1739
1740     switch (get_itbl(node)->type) {
1741         case FETCH_ME_BQ:
1742           ((StgTSO *)bqe)->par.fetchtime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
1743           break;
1744         case RBH:
1745         case FETCH_ME:
1746         case BLACKHOLE_BQ:
1747           ((StgTSO *)bqe)->par.blocktime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
1748           break;
1749         default:
1750           barf("{unblockOneLocked}Daq Qagh: unexpected closure in blocking queue");
1751         }
1752       }
1753 }
1754 #endif
1755
1756 #if defined(GRAN)
1757 static StgBlockingQueueElement *
1758 unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
1759 {
1760     StgBlockingQueueElement *next;
1761     PEs node_loc, tso_loc;
1762
1763     node_loc = where_is(node); // should be lifted out of loop
1764     tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
1765     tso_loc = where_is(tso);
1766     if (IS_LOCAL_TO(PROCS(node),tso_loc)) { // TSO is local
1767       /* !fake_fetch => TSO is on CurrentProc is same as IS_LOCAL_TO */
1768       ASSERT(CurrentProc!=node_loc || tso_loc==CurrentProc);
1769       bq_processing_time += RtsFlags.GranFlags.Costs.lunblocktime;
1770       // insertThread(tso, node_loc);
1771       new_event(tso_loc, tso_loc,
1772                 CurrentTime[CurrentProc]+bq_processing_time,
1773                 ResumeThread,
1774                 tso, node, (rtsSpark*)NULL);
1775       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
1776       // len_local++;
1777       // len++;
1778     } else { // TSO is remote (actually should be FMBQ)
1779       bq_processing_time += RtsFlags.GranFlags.Costs.mpacktime;
1780       bq_processing_time += RtsFlags.GranFlags.Costs.gunblocktime;
1781       new_event(tso_loc, CurrentProc, 
1782                 CurrentTime[CurrentProc]+bq_processing_time+
1783                 RtsFlags.GranFlags.Costs.latency,
1784                 UnblockThread,
1785                 tso, node, (rtsSpark*)NULL);
1786       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
1787       bq_processing_time += RtsFlags.GranFlags.Costs.mtidytime;
1788       // len++;
1789     }      
1790     /* the thread-queue-overhead is accounted for in either Resume or UnblockThread */
1791     IF_GRAN_DEBUG(bq,
1792                   fprintf(stderr," %s TSO %d (%p) [PE %d] (blocked_on=%p) (next=%p) ,",
1793                           (node_loc==tso_loc ? "Local" : "Global"), 
1794                           tso->id, tso, CurrentProc, tso->blocked_on, tso->link))
1795     tso->blocked_on = NULL;
1796     IF_DEBUG(scheduler,belch("-- Waking up thread %ld (%p)", 
1797                              tso->id, tso));
1798   }
1799
1800   /* if this is the BQ of an RBH, we have to put back the info ripped out of
1801      the closure to make room for the anchor of the BQ */
1802   if (next!=END_BQ_QUEUE) {
1803     ASSERT(get_itbl(node)->type == RBH && get_itbl(next)->type == CONSTR);
1804     /*
1805     ASSERT((info_ptr==&RBH_Save_0_info) ||
1806            (info_ptr==&RBH_Save_1_info) ||
1807            (info_ptr==&RBH_Save_2_info));
1808     */
1809     /* cf. convertToRBH in RBH.c for writing the RBHSave closure */
1810     ((StgRBH *)node)->blocking_queue = ((StgRBHSave *)next)->payload[0];
1811     ((StgRBH *)node)->mut_link       = ((StgRBHSave *)next)->payload[1];
1812
1813     IF_GRAN_DEBUG(bq,
1814                   belch("## Filled in RBH_Save for %p (%s) at end of AwBQ",
1815                         node, info_type(node)));
1816   }
1817 }
1818 #elif defined(PAR)
1819 static StgBlockingQueueElement *
1820 unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
1821 {
1822     StgBlockingQueueElement *next;
1823
1824     switch (get_itbl(bqe)->type) {
1825     case TSO:
1826       ASSERT(((StgTSO *)bqe)->why_blocked != NotBlocked);
1827       /* if it's a TSO just push it onto the run_queue */
1828       next = bqe->link;
1829       // ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging?
1830       PUSH_ON_RUN_QUEUE((StgTSO *)bqe); 
1831       THREAD_RUNNABLE();
1832       unblockCount(bqe, node);
1833       /* reset blocking status after dumping event */
1834       ((StgTSO *)bqe)->why_blocked = NotBlocked;
1835       break;
1836
1837     case BLOCKED_FETCH:
1838       /* if it's a BLOCKED_FETCH put it on the PendingFetches list */
1839       next = bqe->link;
1840       bqe->link = PendingFetches;
1841       PendingFetches = bqe;
1842       break;
1843
1844 # if defined(DEBUG)
1845       /* can ignore this case in a non-debugging setup; 
1846          see comments on RBHSave closures above */
1847     case CONSTR:
1848       /* check that the closure is an RBHSave closure */
1849       ASSERT(get_itbl((StgClosure *)bqe) == &RBH_Save_0_info ||
1850              get_itbl((StgClosure *)bqe) == &RBH_Save_1_info ||
1851              get_itbl((StgClosure *)bqe) == &RBH_Save_2_info);
1852       break;
1853
1854     default:
1855       barf("{unblockOneLocked}Daq Qagh: Unexpected IP (%#lx; %s) in blocking queue at %#lx\n",
1856            get_itbl((StgClosure *)bqe), info_type((StgClosure *)bqe), 
1857            (StgClosure *)bqe);
1858 # endif
1859     }
1860   // IF_DEBUG(scheduler,sched_belch("waking up thread %ld", tso->id));
1861   return next;
1862 }
1863
1864 #else /* !GRAN && !PAR */
1865 static StgTSO *
1866 unblockOneLocked(StgTSO *tso)
1867 {
1868   StgTSO *next;
1869
1870   ASSERT(get_itbl(tso)->type == TSO);
1871   ASSERT(tso->why_blocked != NotBlocked);
1872   tso->why_blocked = NotBlocked;
1873   next = tso->link;
1874   PUSH_ON_RUN_QUEUE(tso);
1875   THREAD_RUNNABLE();
1876   IF_DEBUG(scheduler,sched_belch("waking up thread %ld", tso->id));
1877   return next;
1878 }
1879 #endif
1880
1881 #if defined(GRAN)
1882 inline StgTSO *
1883 unblockOne(StgTSO *tso, StgClosure *node)
1884 {
1885   ACQUIRE_LOCK(&sched_mutex);
1886   tso = unblockOneLocked(tso, node);
1887   RELEASE_LOCK(&sched_mutex);
1888   return tso;
1889 }
1890 #elif defined(PAR)
1891 inline StgTSO *
1892 unblockOne(StgTSO *tso, StgClosure *node)
1893 {
1894   ACQUIRE_LOCK(&sched_mutex);
1895   tso = unblockOneLocked(tso, node);
1896   RELEASE_LOCK(&sched_mutex);
1897   return tso;
1898 }
1899 #else
1900 inline StgTSO *
1901 unblockOne(StgTSO *tso)
1902 {
1903   ACQUIRE_LOCK(&sched_mutex);
1904   tso = unblockOneLocked(tso);
1905   RELEASE_LOCK(&sched_mutex);
1906   return tso;
1907 }
1908 #endif
1909
1910 #if defined(GRAN)
1911 void 
1912 awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
1913 {
1914   StgBlockingQueueElement *bqe, *next;
1915   StgTSO *tso;
1916   PEs node_loc, tso_loc;
1917   rtsTime bq_processing_time = 0;
1918   nat len = 0, len_local = 0;
1919
1920   IF_GRAN_DEBUG(bq, 
1921                 belch("## AwBQ for node %p on PE %d @ %ld by TSO %d (%p): ", \
1922                       node, CurrentProc, CurrentTime[CurrentProc], 
1923                       CurrentTSO->id, CurrentTSO));
1924
1925   node_loc = where_is(node);
1926
1927   ASSERT(get_itbl(q)->type == TSO ||   // q is either a TSO or an RBHSave
1928          get_itbl(q)->type == CONSTR); // closure (type constructor)
1929   ASSERT(is_unique(node));
1930
1931   /* FAKE FETCH: magically copy the node to the tso's proc;
1932      no Fetch necessary because in reality the node should not have been 
1933      moved to the other PE in the first place
1934   */
1935   if (CurrentProc!=node_loc) {
1936     IF_GRAN_DEBUG(bq, 
1937                   belch("## node %p is on PE %d but CurrentProc is %d (TSO %d); assuming fake fetch and adjusting bitmask (old: %#x)",
1938                         node, node_loc, CurrentProc, CurrentTSO->id, 
1939                         // CurrentTSO, where_is(CurrentTSO),
1940                         node->header.gran.procs));
1941     node->header.gran.procs = (node->header.gran.procs) | PE_NUMBER(CurrentProc);
1942     IF_GRAN_DEBUG(bq, 
1943                   belch("## new bitmask of node %p is %#x",
1944                         node, node->header.gran.procs));
1945     if (RtsFlags.GranFlags.GranSimStats.Global) {
1946       globalGranStats.tot_fake_fetches++;
1947     }
1948   }
1949
1950   bqe = q;
1951   // ToDo: check: ASSERT(CurrentProc==node_loc);
1952   while (get_itbl(bqe)->type==TSO) { // q != END_TSO_QUEUE) {
1953     //next = bqe->link;
1954     /* 
1955        bqe points to the current element in the queue
1956        next points to the next element in the queue
1957     */
1958     //tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
1959     //tso_loc = where_is(tso);
1960     bqe = unblockOneLocked(bqe, node);
1961   }
1962
1963   /* statistics gathering */
1964   /* ToDo: fix counters
1965   if (RtsFlags.GranFlags.GranSimStats.Global) {
1966     globalGranStats.tot_bq_processing_time += bq_processing_time;
1967     globalGranStats.tot_bq_len += len;      // total length of all bqs awakened
1968     globalGranStats.tot_bq_len_local += len_local;  // same for local TSOs only
1969     globalGranStats.tot_awbq++;             // total no. of bqs awakened
1970   }
1971   IF_GRAN_DEBUG(bq,
1972                 fprintf(stderr,"## BQ Stats of %p: [%d entries, %d local] %s\n",
1973                         node, len, len_local, (next!=END_TSO_QUEUE) ? "RBH" : ""));
1974   */
1975 }
1976 #elif defined(PAR)
1977 void 
1978 awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node)
1979 {
1980   StgBlockingQueueElement *bqe, *next;
1981
1982   ACQUIRE_LOCK(&sched_mutex);
1983
1984   IF_PAR_DEBUG(verbose, 
1985                belch("## AwBQ for node %p on [%x]: ",
1986                      node, mytid));
1987
1988   ASSERT(get_itbl(q)->type == TSO ||           
1989          get_itbl(q)->type == BLOCKED_FETCH || 
1990          get_itbl(q)->type == CONSTR); 
1991
1992   bqe = q;
1993   while (get_itbl(bqe)->type==TSO || 
1994          get_itbl(bqe)->type==BLOCKED_FETCH) {
1995     bqe = unblockOneLocked(bqe, node);
1996   }
1997   RELEASE_LOCK(&sched_mutex);
1998 }
1999
2000 #else   /* !GRAN && !PAR */
2001 void
2002 awakenBlockedQueue(StgTSO *tso)
2003 {
2004   ACQUIRE_LOCK(&sched_mutex);
2005   while (tso != END_TSO_QUEUE) {
2006     tso = unblockOneLocked(tso);
2007   }
2008   RELEASE_LOCK(&sched_mutex);
2009 }
2010 #endif
2011
2012 #if 0
2013 // ngoq ngo'
2014
2015 #if defined(GRAN)
2016 /* 
2017    Awakening a blocking queue in GranSim means checking for each of the
2018    TSOs in the queue whether they are local or not, issuing a ResumeThread
2019    or an UnblockThread event, respectively. The basic iteration over the
2020    blocking queue is the same as in the standard setup.  
2021 */
2022 void
2023 awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node)
2024 {
2025   StgBlockingQueueElement *bqe, *next;
2026   StgTSO *tso;
2027   PEs node_loc, tso_loc;
2028   rtsTime bq_processing_time = 0;
2029   nat len = 0, len_local = 0;
2030
2031   IF_GRAN_DEBUG(bq, 
2032                 belch("## AwBQ for node %p on PE %d @ %ld by TSO %d (%p): ", \
2033                       node, CurrentProc, CurrentTime[CurrentProc], 
2034                       CurrentTSO->id, CurrentTSO));
2035
2036   node_loc = where_is(node);
2037
2038   ASSERT(get_itbl(q)->type == TSO ||   // q is either a TSO or an RBHSave
2039          get_itbl(q)->type == CONSTR); // closure (type constructor)
2040   ASSERT(is_unique(node));
2041
2042   /* FAKE FETCH: magically copy the node to the tso's proc;
2043      no Fetch necessary because in reality the node should not have been 
2044      moved to the other PE in the first place
2045   */
2046   if (CurrentProc!=node_loc) {
2047     IF_GRAN_DEBUG(bq, 
2048                   belch("## node %p is on PE %d but CurrentProc is %d (TSO %d); assuming fake fetch and adjusting bitmask (old: %#x)",
2049                         node, node_loc, CurrentProc, CurrentTSO->id, 
2050                         // CurrentTSO, where_is(CurrentTSO),
2051                         node->header.gran.procs));
2052     node->header.gran.procs = (node->header.gran.procs) | PE_NUMBER(CurrentProc);
2053     IF_GRAN_DEBUG(bq, 
2054                   belch("## new bitmask of node %p is %#x",
2055                         node, node->header.gran.procs));
2056     if (RtsFlags.GranFlags.GranSimStats.Global) {
2057       globalGranStats.tot_fake_fetches++;
2058     }
2059   }
2060
2061   next = q;
2062   // ToDo: check: ASSERT(CurrentProc==node_loc);
2063   while (get_itbl(next)->type==TSO) { // q != END_TSO_QUEUE) {
2064     bqe = next;
2065     next = bqe->link;
2066     /* 
2067        bqe points to the current element in the queue
2068        next points to the next element in the queue
2069     */
2070     tso = (StgTSO *)bqe;  // wastes an assignment to get the type right
2071     tso_loc = where_is(tso);
2072     if (IS_LOCAL_TO(PROCS(node),tso_loc)) { // TSO is local
2073       /* !fake_fetch => TSO is on CurrentProc is same as IS_LOCAL_TO */
2074       ASSERT(CurrentProc!=node_loc || tso_loc==CurrentProc);
2075       bq_processing_time += RtsFlags.GranFlags.Costs.lunblocktime;
2076       // insertThread(tso, node_loc);
2077       new_event(tso_loc, tso_loc,
2078                 CurrentTime[CurrentProc]+bq_processing_time,
2079                 ResumeThread,
2080                 tso, node, (rtsSpark*)NULL);
2081       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
2082       len_local++;
2083       len++;
2084     } else { // TSO is remote (actually should be FMBQ)
2085       bq_processing_time += RtsFlags.GranFlags.Costs.mpacktime;
2086       bq_processing_time += RtsFlags.GranFlags.Costs.gunblocktime;
2087       new_event(tso_loc, CurrentProc, 
2088                 CurrentTime[CurrentProc]+bq_processing_time+
2089                 RtsFlags.GranFlags.Costs.latency,
2090                 UnblockThread,
2091                 tso, node, (rtsSpark*)NULL);
2092       tso->link = END_TSO_QUEUE; // overwrite link just to be sure 
2093       bq_processing_time += RtsFlags.GranFlags.Costs.mtidytime;
2094       len++;
2095     }      
2096     /* the thread-queue-overhead is accounted for in either Resume or UnblockThread */
2097     IF_GRAN_DEBUG(bq,
2098                   fprintf(stderr," %s TSO %d (%p) [PE %d] (blocked_on=%p) (next=%p) ,",
2099                           (node_loc==tso_loc ? "Local" : "Global"), 
2100                           tso->id, tso, CurrentProc, tso->block_info.closure, tso->link))
2101     tso->block_info.closure = NULL;
2102     IF_DEBUG(scheduler,belch("-- Waking up thread %ld (%p)", 
2103                              tso->id, tso));
2104   }
2105
2106   /* if this is the BQ of an RBH, we have to put back the info ripped out of
2107      the closure to make room for the anchor of the BQ */
2108   if (next!=END_BQ_QUEUE) {
2109     ASSERT(get_itbl(node)->type == RBH && get_itbl(next)->type == CONSTR);
2110     /*
2111     ASSERT((info_ptr==&RBH_Save_0_info) ||
2112            (info_ptr==&RBH_Save_1_info) ||
2113            (info_ptr==&RBH_Save_2_info));
2114     */
2115     /* cf. convertToRBH in RBH.c for writing the RBHSave closure */
2116     ((StgRBH *)node)->blocking_queue = ((StgRBHSave *)next)->payload[0];
2117     ((StgRBH *)node)->mut_link       = ((StgRBHSave *)next)->payload[1];
2118
2119     IF_GRAN_DEBUG(bq,
2120                   belch("## Filled in RBH_Save for %p (%s) at end of AwBQ",
2121                         node, info_type(node)));
2122   }
2123
2124   /* statistics gathering */
2125   if (RtsFlags.GranFlags.GranSimStats.Global) {
2126     globalGranStats.tot_bq_processing_time += bq_processing_time;
2127     globalGranStats.tot_bq_len += len;      // total length of all bqs awakened
2128     globalGranStats.tot_bq_len_local += len_local;  // same for local TSOs only
2129     globalGranStats.tot_awbq++;             // total no. of bqs awakened
2130   }
2131   IF_GRAN_DEBUG(bq,
2132                 fprintf(stderr,"## BQ Stats of %p: [%d entries, %d local] %s\n",
2133                         node, len, len_local, (next!=END_TSO_QUEUE) ? "RBH" : ""));
2134 }
2135
2136 #elif defined(PAR)
2137
2138 /*
2139   Awakening a blocking queue in GUM has to check whether an entry in the
2140   queue is a normal TSO or a BLOCKED_FETCH. The later indicates that a TSO is
2141   waiting for the result of this computation on another PE. Thus, when
2142   finding a BLOCKED_FETCH we have to send off a message to that PE. 
2143   Actually, we defer sending off a message, by just putting the BLOCKED_FETCH
2144   onto the PendingFetches queue, which will be later traversed by
2145   processFetches, sending off a RESUME message for each BLOCKED_FETCH.
2146
2147   NB: There is no check for an RBHSave closure (type CONSTR) in the code 
2148       below. The reason is, if we awaken the BQ of an RBH closure (RBHSaves 
2149       only exist at the end of such BQs) we know that the closure has been
2150       unpacked successfully on the other PE, and we can discard the info
2151       contained in the RBHSave closure. The current closure will be turned 
2152       into a FetchMe closure anyway.
2153 */
2154 void 
2155 awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node)
2156 {
2157   StgBlockingQueueElement *bqe, *next;
2158
2159   IF_PAR_DEBUG(verbose, 
2160                belch("## AwBQ for node %p on [%x]: ",
2161                      node, mytid));
2162
2163   ASSERT(get_itbl(q)->type == TSO ||           
2164          get_itbl(q)->type == BLOCKED_FETCH || 
2165          get_itbl(q)->type == CONSTR); 
2166
2167   next = q;
2168   while (get_itbl(next)->type==TSO || 
2169          get_itbl(next)->type==BLOCKED_FETCH) {
2170     bqe = next;
2171     switch (get_itbl(bqe)->type) {
2172     case TSO:
2173       /* if it's a TSO just push it onto the run_queue */
2174       next = bqe->link;
2175 #if defined(DEBUG)
2176       ((StgTSO *)bqe)->link = END_TSO_QUEUE; // debugging only
2177 #endif
2178       push_on_run_queue((StgTSO *)bqe); // HWL: was: PUSH_ON_RUN_QUEUE(tso);
2179
2180       /* write RESUME events to log file and
2181          update blocked and fetch time (depending on type of the orig closure) */
2182       if (RtsFlags.ParFlags.ParStats.Full) {
2183         DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC, 
2184                          GR_RESUMEQ, ((StgTSO *)bqe), ((StgTSO *)bqe)->block_info.closure,
2185                          0, spark_queue_len(ADVISORY_POOL));
2186
2187         switch (get_itbl(node)->type) {
2188         case FETCH_ME_BQ:
2189           ((StgTSO *)bqe)->par.fetchtime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
2190           break;
2191         case RBH:
2192         case FETCH_ME:
2193         case BLACKHOLE_BQ:
2194           ((StgTSO *)bqe)->par.blocktime += CURRENT_TIME-((StgTSO *)bqe)->par.blockedat;
2195           break;
2196         default:
2197           barf("{awaken_blocked_queue}Daq Qagh: unexpected closure %p (%s) with blocking queue",
2198                node, info_type(node));
2199         }
2200       }
2201       /* reset block_info.closure field after dumping event */
2202       ((StgTSO *)bqe)->block_info.closure = NULL;
2203
2204       /* rest of this branch is debugging only */
2205       IF_PAR_DEBUG(verbose,
2206                    fprintf(stderr," TSO %d (%p) [PE %lx] (block_info.closure=%p) (next=%p) ,",
2207                            ((StgTSO *)bqe)->id, (StgTSO *)bqe,
2208                            mytid, ((StgTSO *)bqe)->block_info.closure, ((StgTSO *)bqe)->link));
2209
2210       IF_DEBUG(scheduler,
2211                if (!RtsFlags.ParFlags.Debug.verbose)
2212                  belch("-- Waking up thread %ld (%p)", 
2213                        ((StgTSO *)bqe)->id, (StgTSO *)bqe));
2214       break;
2215
2216     case BLOCKED_FETCH:
2217       /* if it's a BLOCKED_FETCH put it on the PendingFetches list */
2218       next = bqe->link;
2219       bqe->link = PendingFetches;
2220       PendingFetches = bqe;
2221       // bqe.tso->block_info.closure = NULL;
2222
2223       /* rest of this branch is debugging only */
2224       IF_PAR_DEBUG(verbose,
2225                    fprintf(stderr," BLOCKED_FETCH (%p) on node %p [PE %lx] (next=%p) ,",
2226                            ((StgBlockedFetch *)bqe), 
2227                            ((StgBlockedFetch *)bqe)->node, 
2228                            mytid, ((StgBlockedFetch *)bqe)->link));
2229       break;
2230
2231 # if defined(DEBUG)
2232       /* can ignore this case in a non-debugging setup; 
2233          see comments on RBHSave closures above */
2234     case CONSTR:
2235       /* check that the closure is an RBHSave closure */
2236       ASSERT(get_itbl((StgClosure *)bqe) == &RBH_Save_0_info ||
2237              get_itbl((StgClosure *)bqe) == &RBH_Save_1_info ||
2238              get_itbl((StgClosure *)bqe) == &RBH_Save_2_info);
2239       break;
2240
2241     default:
2242       barf("{awaken_blocked_queue}Daq Qagh: Unexpected IP (%#lx; %s) in blocking queue at %#lx\n",
2243            get_itbl((StgClosure *)bqe), info_type((StgClosure *)bqe), 
2244            (StgClosure *)bqe);
2245 # endif
2246     }
2247   }
2248 }
2249
2250 #else /* !GRAN && !PAR */
2251
2252 void 
2253 awaken_blocked_queue(StgTSO *q) { awakenBlockedQueue(q); }
2254
2255 /*
2256 {
2257   StgTSO *tso;
2258
2259   while (q != END_TSO_QUEUE) {
2260     ASSERT(get_itbl(q)->type == TSO);
2261     tso = q;
2262     q = tso->link;
2263     push_on_run_queue(tso); // HWL: was: PUSH_ON_RUN_QUEUE(tso);
2264     //tso->block_info.closure = NULL;
2265     IF_DEBUG(scheduler, belch("-- Waking up thread %ld (%p)", tso->id, tso));
2266   }
2267 }
2268 */
2269 #endif /* GRAN */
2270 #endif /* 0 */
2271
2272 //@node Exception Handling Routines, Debugging Routines, Blocking Queue Routines, Main scheduling code
2273 //@subsection Exception Handling Routines
2274
2275 /* ---------------------------------------------------------------------------
2276    Interrupt execution
2277    - usually called inside a signal handler so it mustn't do anything fancy.   
2278    ------------------------------------------------------------------------ */
2279
2280 void
2281 interruptStgRts(void)
2282 {
2283     interrupted    = 1;
2284     context_switch = 1;
2285 }
2286
2287 /* -----------------------------------------------------------------------------
2288    Unblock a thread
2289
2290    This is for use when we raise an exception in another thread, which
2291    may be blocked.
2292    This has nothing to do with the UnblockThread event in GranSim. -- HWL
2293    -------------------------------------------------------------------------- */
2294
2295 static void
2296 unblockThread(StgTSO *tso)
2297 {
2298   StgTSO *t, **last;
2299
2300   ACQUIRE_LOCK(&sched_mutex);
2301   switch (tso->why_blocked) {
2302
2303   case NotBlocked:
2304     return;  /* not blocked */
2305
2306   case BlockedOnMVar:
2307     ASSERT(get_itbl(tso->block_info.closure)->type == MVAR);
2308     {
2309       StgTSO *last_tso = END_TSO_QUEUE;
2310       StgMVar *mvar = (StgMVar *)(tso->block_info.closure);
2311
2312       last = &mvar->head;
2313       for (t = mvar->head; t != END_TSO_QUEUE; 
2314            last = &t->link, last_tso = t, t = t->link) {
2315         if (t == tso) {
2316           *last = tso->link;
2317           if (mvar->tail == tso) {
2318             mvar->tail = last_tso;
2319           }
2320           goto done;
2321         }
2322       }
2323       barf("unblockThread (MVAR): TSO not found");
2324     }
2325
2326   case BlockedOnBlackHole:
2327     ASSERT(get_itbl(tso->block_info.closure)->type == BLACKHOLE_BQ);
2328     {
2329       StgBlockingQueue *bq = (StgBlockingQueue *)(tso->block_info.closure);
2330
2331       last = &bq->blocking_queue;
2332       for (t = bq->blocking_queue; t != END_TSO_QUEUE; 
2333            last = &t->link, t = t->link) {
2334         if (t == tso) {
2335           *last = tso->link;
2336           goto done;
2337         }
2338       }
2339       barf("unblockThread (BLACKHOLE): TSO not found");
2340     }
2341
2342   case BlockedOnException:
2343     {
2344       StgTSO *target  = tso->block_info.tso;
2345
2346       ASSERT(get_itbl(target)->type == TSO);
2347       ASSERT(target->blocked_exceptions != NULL);
2348
2349       last = &target->blocked_exceptions;
2350       for (t = target->blocked_exceptions; t != END_TSO_QUEUE; 
2351            last = &t->link, t = t->link) {
2352         ASSERT(get_itbl(t)->type == TSO);
2353         if (t == tso) {
2354           *last = tso->link;
2355           goto done;
2356         }
2357       }
2358       barf("unblockThread (Exception): TSO not found");
2359     }
2360
2361   case BlockedOnDelay:
2362   case BlockedOnRead:
2363   case BlockedOnWrite:
2364     {
2365       StgTSO *prev = NULL;
2366       for (t = blocked_queue_hd; t != END_TSO_QUEUE; 
2367            prev = t, t = t->link) {
2368         if (t == tso) {
2369           if (prev == NULL) {
2370             blocked_queue_hd = t->link;
2371             if (blocked_queue_tl == t) {
2372               blocked_queue_tl = END_TSO_QUEUE;
2373             }
2374           } else {
2375             prev->link = t->link;
2376             if (blocked_queue_tl == t) {
2377               blocked_queue_tl = prev;
2378             }
2379           }
2380           goto done;
2381         }
2382       }
2383       barf("unblockThread (I/O): TSO not found");
2384     }
2385
2386   default:
2387     barf("unblockThread");
2388   }
2389
2390  done:
2391   tso->link = END_TSO_QUEUE;
2392   tso->why_blocked = NotBlocked;
2393   tso->block_info.closure = NULL;
2394   PUSH_ON_RUN_QUEUE(tso);
2395   RELEASE_LOCK(&sched_mutex);
2396 }
2397
2398 /* -----------------------------------------------------------------------------
2399  * raiseAsync()
2400  *
2401  * The following function implements the magic for raising an
2402  * asynchronous exception in an existing thread.
2403  *
2404  * We first remove the thread from any queue on which it might be
2405  * blocked.  The possible blockages are MVARs and BLACKHOLE_BQs.
2406  *
2407  * We strip the stack down to the innermost CATCH_FRAME, building
2408  * thunks in the heap for all the active computations, so they can 
2409  * be restarted if necessary.  When we reach a CATCH_FRAME, we build
2410  * an application of the handler to the exception, and push it on
2411  * the top of the stack.
2412  * 
2413  * How exactly do we save all the active computations?  We create an
2414  * AP_UPD for every UpdateFrame on the stack.  Entering one of these
2415  * AP_UPDs pushes everything from the corresponding update frame
2416  * upwards onto the stack.  (Actually, it pushes everything up to the
2417  * next update frame plus a pointer to the next AP_UPD object.
2418  * Entering the next AP_UPD object pushes more onto the stack until we
2419  * reach the last AP_UPD object - at which point the stack should look
2420  * exactly as it did when we killed the TSO and we can continue
2421  * execution by entering the closure on top of the stack.
2422  *
2423  * We can also kill a thread entirely - this happens if either (a) the 
2424  * exception passed to raiseAsync is NULL, or (b) there's no
2425  * CATCH_FRAME on the stack.  In either case, we strip the entire
2426  * stack and replace the thread with a zombie.
2427  *
2428  * -------------------------------------------------------------------------- */
2429  
2430 void 
2431 deleteThread(StgTSO *tso)
2432 {
2433   raiseAsync(tso,NULL);
2434 }
2435
2436 void
2437 raiseAsync(StgTSO *tso, StgClosure *exception)
2438 {
2439   StgUpdateFrame* su = tso->su;
2440   StgPtr          sp = tso->sp;
2441   
2442   /* Thread already dead? */
2443   if (tso->whatNext == ThreadComplete || tso->whatNext == ThreadKilled) {
2444     return;
2445   }
2446
2447   IF_DEBUG(scheduler, sched_belch("raising exception in thread %ld.", tso->id));
2448
2449   /* Remove it from any blocking queues */
2450   unblockThread(tso);
2451
2452   /* The stack freezing code assumes there's a closure pointer on
2453    * the top of the stack.  This isn't always the case with compiled
2454    * code, so we have to push a dummy closure on the top which just
2455    * returns to the next return address on the stack.
2456    */
2457   if ( LOOKS_LIKE_GHC_INFO((void*)*sp) ) {
2458     *(--sp) = (W_)&dummy_ret_closure;
2459   }
2460
2461   while (1) {
2462     int words = ((P_)su - (P_)sp) - 1;
2463     nat i;
2464     StgAP_UPD * ap;
2465
2466     /* If we find a CATCH_FRAME, and we've got an exception to raise,
2467      * then build PAP(handler,exception), and leave it on top of
2468      * the stack ready to enter.
2469      */
2470     if (get_itbl(su)->type == CATCH_FRAME && exception != NULL) {
2471       StgCatchFrame *cf = (StgCatchFrame *)su;
2472       /* we've got an exception to raise, so let's pass it to the
2473        * handler in this frame.
2474        */
2475       ap = (StgAP_UPD *)allocate(sizeofW(StgPAP) + 1);
2476       TICK_ALLOC_UPD_PAP(2,0);
2477       SET_HDR(ap,&PAP_info,cf->header.prof.ccs);
2478               
2479       ap->n_args = 1;
2480       ap->fun = cf->handler;
2481       ap->payload[0] = (P_)exception;
2482
2483       /* sp currently points to the word above the CATCH_FRAME on the stack.
2484        */
2485       sp += sizeofW(StgCatchFrame);
2486       tso->su = cf->link;
2487
2488       /* Restore the blocked/unblocked state for asynchronous exceptions
2489        * at the CATCH_FRAME.  
2490        *
2491        * If exceptions were unblocked at the catch, arrange that they
2492        * are unblocked again after executing the handler by pushing an
2493        * unblockAsyncExceptions_ret stack frame.
2494        */
2495       if (!cf->exceptions_blocked) {
2496         *(sp--) = (W_)&unblockAsyncExceptionszh_ret_info;
2497       }
2498       
2499       /* Ensure that async exceptions are blocked when running the handler.
2500        */
2501       if (tso->blocked_exceptions == NULL) {
2502         tso->blocked_exceptions = END_TSO_QUEUE;
2503       }
2504       
2505       /* Put the newly-built PAP on top of the stack, ready to execute
2506        * when the thread restarts.
2507        */
2508       sp[0] = (W_)ap;
2509       tso->sp = sp;
2510       tso->whatNext = ThreadEnterGHC;
2511       return;
2512     }
2513
2514     /* First build an AP_UPD consisting of the stack chunk above the
2515      * current update frame, with the top word on the stack as the
2516      * fun field.
2517      */
2518     ap = (StgAP_UPD *)allocate(AP_sizeW(words));
2519     
2520     ASSERT(words >= 0);
2521     
2522     ap->n_args = words;
2523     ap->fun    = (StgClosure *)sp[0];
2524     sp++;
2525     for(i=0; i < (nat)words; ++i) {
2526       ap->payload[i] = (P_)*sp++;
2527     }
2528     
2529     switch (get_itbl(su)->type) {
2530       
2531     case UPDATE_FRAME:
2532       {
2533         SET_HDR(ap,&AP_UPD_info,su->header.prof.ccs /* ToDo */); 
2534         TICK_ALLOC_UP_THK(words+1,0);
2535         
2536         IF_DEBUG(scheduler,
2537                  fprintf(stderr,  "scheduler: Updating ");
2538                  printPtr((P_)su->updatee); 
2539                  fprintf(stderr,  " with ");
2540                  printObj((StgClosure *)ap);
2541                  );
2542         
2543         /* Replace the updatee with an indirection - happily
2544          * this will also wake up any threads currently
2545          * waiting on the result.
2546          */
2547         UPD_IND_NOLOCK(su->updatee,ap);  /* revert the black hole */
2548         su = su->link;
2549         sp += sizeofW(StgUpdateFrame) -1;
2550         sp[0] = (W_)ap; /* push onto stack */
2551         break;
2552       }
2553       
2554     case CATCH_FRAME:
2555       {
2556         StgCatchFrame *cf = (StgCatchFrame *)su;
2557         StgClosure* o;
2558         
2559         /* We want a PAP, not an AP_UPD.  Fortunately, the
2560          * layout's the same.
2561          */
2562         SET_HDR(ap,&PAP_info,su->header.prof.ccs /* ToDo */);
2563         TICK_ALLOC_UPD_PAP(words+1,0);
2564         
2565         /* now build o = FUN(catch,ap,handler) */
2566         o = (StgClosure *)allocate(sizeofW(StgClosure)+2);
2567         TICK_ALLOC_FUN(2,0);
2568         SET_HDR(o,&catch_info,su->header.prof.ccs /* ToDo */);
2569         o->payload[0] = (StgClosure *)ap;
2570         o->payload[1] = cf->handler;
2571         
2572         IF_DEBUG(scheduler,
2573                  fprintf(stderr,  "scheduler: Built ");
2574                  printObj((StgClosure *)o);
2575                  );
2576         
2577         /* pop the old handler and put o on the stack */
2578         su = cf->link;
2579         sp += sizeofW(StgCatchFrame) - 1;
2580         sp[0] = (W_)o;
2581         break;
2582       }
2583       
2584     case SEQ_FRAME:
2585       {
2586         StgSeqFrame *sf = (StgSeqFrame *)su;
2587         StgClosure* o;
2588         
2589         SET_HDR(ap,&PAP_info,su->header.prof.ccs /* ToDo */);
2590         TICK_ALLOC_UPD_PAP(words+1,0);
2591         
2592         /* now build o = FUN(seq,ap) */
2593         o = (StgClosure *)allocate(sizeofW(StgClosure)+1);
2594         TICK_ALLOC_SE_THK(1,0);
2595         SET_HDR(o,&seq_info,su->header.prof.ccs /* ToDo */);
2596         payloadCPtr(o,0) = (StgClosure *)ap;
2597         
2598         IF_DEBUG(scheduler,
2599                  fprintf(stderr,  "scheduler: Built ");
2600                  printObj((StgClosure *)o);
2601                  );
2602         
2603         /* pop the old handler and put o on the stack */
2604         su = sf->link;
2605         sp += sizeofW(StgSeqFrame) - 1;
2606         sp[0] = (W_)o;
2607         break;
2608       }
2609       
2610     case STOP_FRAME:
2611       /* We've stripped the entire stack, the thread is now dead. */
2612       sp += sizeofW(StgStopFrame) - 1;
2613       sp[0] = (W_)exception;    /* save the exception */
2614       tso->whatNext = ThreadKilled;
2615       tso->su = (StgUpdateFrame *)(sp+1);
2616       tso->sp = sp;
2617       return;
2618       
2619     default:
2620       barf("raiseAsync");
2621     }
2622   }
2623   barf("raiseAsync");
2624 }
2625
2626 //@node Debugging Routines, Index, Exception Handling Routines, Main scheduling code
2627 //@subsection Debugging Routines
2628
2629 /* -----------------------------------------------------------------------------
2630    Debugging: why is a thread blocked
2631    -------------------------------------------------------------------------- */
2632
2633 #ifdef DEBUG
2634
2635 void printThreadBlockage(StgTSO *tso)
2636 {
2637   switch (tso->why_blocked) {
2638   case BlockedOnRead:
2639     fprintf(stderr,"blocked on read from fd %d", tso->block_info.fd);
2640     break;
2641   case BlockedOnWrite:
2642     fprintf(stderr,"blocked on write to fd %d", tso->block_info.fd);
2643     break;
2644   case BlockedOnDelay:
2645     fprintf(stderr,"blocked on delay of %d ms", tso->block_info.delay);
2646     break;
2647   case BlockedOnMVar:
2648     fprintf(stderr,"blocked on an MVar");
2649     break;
2650   case BlockedOnException:
2651     fprintf(stderr,"blocked on delivering an exception to thread %d",
2652             tso->block_info.tso->id);
2653     break;
2654   case BlockedOnBlackHole:
2655     fprintf(stderr,"blocked on a black hole");
2656     break;
2657   case NotBlocked:
2658     fprintf(stderr,"not blocked");
2659     break;
2660 #if defined(PAR)
2661   case BlockedOnGA:
2662     fprintf(stderr,"blocked on global address");
2663     break;
2664 #endif
2665   }
2666 }
2667
2668 /* 
2669    Print a whole blocking queue attached to node (debugging only).
2670 */
2671 //@cindex print_bq
2672 # if defined(PAR)
2673 void 
2674 print_bq (StgClosure *node)
2675 {
2676   StgBlockingQueueElement *bqe;
2677   StgTSO *tso;
2678   rtsBool end;
2679
2680   fprintf(stderr,"## BQ of closure %p (%s): ",
2681           node, info_type(node));
2682
2683   /* should cover all closures that may have a blocking queue */
2684   ASSERT(get_itbl(node)->type == BLACKHOLE_BQ ||
2685          get_itbl(node)->type == FETCH_ME_BQ ||
2686          get_itbl(node)->type == RBH);
2687     
2688   ASSERT(node!=(StgClosure*)NULL);         // sanity check
2689   /* 
2690      NB: In a parallel setup a BQ of an RBH must end with an RBH_Save closure;
2691   */
2692   for (bqe = ((StgBlockingQueue*)node)->blocking_queue, end = (bqe==END_BQ_QUEUE);
2693        !end; // iterate until bqe points to a CONSTR
2694        end = (get_itbl(bqe)->type == CONSTR) || (bqe->link==END_BQ_QUEUE), bqe = end ? END_BQ_QUEUE : bqe->link) {
2695     ASSERT(bqe != END_BQ_QUEUE);             // sanity check
2696     ASSERT(bqe != (StgTSO*)NULL);            // sanity check
2697     /* types of closures that may appear in a blocking queue */
2698     ASSERT(get_itbl(bqe)->type == TSO ||           
2699            get_itbl(bqe)->type == BLOCKED_FETCH || 
2700            get_itbl(bqe)->type == CONSTR); 
2701     /* only BQs of an RBH end with an RBH_Save closure */
2702     ASSERT(get_itbl(bqe)->type != CONSTR || get_itbl(node)->type == RBH);
2703
2704     switch (get_itbl(bqe)->type) {
2705     case TSO:
2706       fprintf(stderr," TSO %d (%x),",
2707               ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
2708       break;
2709     case BLOCKED_FETCH:
2710       fprintf(stderr," BF (node=%p, ga=((%x, %d, %x)),",
2711               ((StgBlockedFetch *)bqe)->node, 
2712               ((StgBlockedFetch *)bqe)->ga.payload.gc.gtid,
2713               ((StgBlockedFetch *)bqe)->ga.payload.gc.slot,
2714               ((StgBlockedFetch *)bqe)->ga.weight);
2715       break;
2716     case CONSTR:
2717       fprintf(stderr," %s (IP %p),",
2718               (get_itbl(bqe) == &RBH_Save_0_info ? "RBH_Save_0" :
2719                get_itbl(bqe) == &RBH_Save_1_info ? "RBH_Save_1" :
2720                get_itbl(bqe) == &RBH_Save_2_info ? "RBH_Save_2" :
2721                "RBH_Save_?"), get_itbl(bqe));
2722       break;
2723     default:
2724       barf("Unexpected closure type %s in blocking queue of %p (%s)",
2725            info_type(bqe), node, info_type(node));
2726       break;
2727     }
2728   } /* for */
2729   fputc('\n', stderr);
2730 }
2731 # elif defined(GRAN)
2732 void 
2733 print_bq (StgClosure *node)
2734 {
2735   StgBlockingQueueElement *bqe;
2736   StgTSO *tso;
2737   PEs node_loc, tso_loc;
2738   rtsBool end;
2739
2740   /* should cover all closures that may have a blocking queue */
2741   ASSERT(get_itbl(node)->type == BLACKHOLE_BQ ||
2742          get_itbl(node)->type == FETCH_ME_BQ ||
2743          get_itbl(node)->type == RBH);
2744     
2745   ASSERT(node!=(StgClosure*)NULL);         // sanity check
2746   node_loc = where_is(node);
2747
2748   fprintf(stderr,"## BQ of closure %p (%s) on [PE %d]: ",
2749           node, info_type(node), node_loc);
2750
2751   /* 
2752      NB: In a parallel setup a BQ of an RBH must end with an RBH_Save closure;
2753   */
2754   for (bqe = ((StgBlockingQueue*)node)->blocking_queue, end = (bqe==END_BQ_QUEUE);
2755        !end; // iterate until bqe points to a CONSTR
2756        end = (get_itbl(bqe)->type == CONSTR) || (bqe->link==END_BQ_QUEUE), bqe = end ? END_BQ_QUEUE : bqe->link) {
2757     ASSERT(bqe != END_BQ_QUEUE);             // sanity check
2758     ASSERT(bqe != (StgTSO*)NULL);            // sanity check
2759     /* types of closures that may appear in a blocking queue */
2760     ASSERT(get_itbl(bqe)->type == TSO ||           
2761            get_itbl(bqe)->type == CONSTR); 
2762     /* only BQs of an RBH end with an RBH_Save closure */
2763     ASSERT(get_itbl(bqe)->type != CONSTR || get_itbl(node)->type == RBH);
2764
2765     tso_loc = where_is((StgClosure *)bqe);
2766     switch (get_itbl(bqe)->type) {
2767     case TSO:
2768       fprintf(stderr," TSO %d (%x) on [PE %d],",
2769               ((StgTSO *)bqe)->id, ((StgTSO *)bqe), tso_loc);
2770       break;
2771     case CONSTR:
2772       fprintf(stderr," %s (IP %p),",
2773               (get_itbl(bqe) == &RBH_Save_0_info ? "RBH_Save_0" :
2774                get_itbl(bqe) == &RBH_Save_1_info ? "RBH_Save_1" :
2775                get_itbl(bqe) == &RBH_Save_2_info ? "RBH_Save_2" :
2776                "RBH_Save_?"), get_itbl(bqe));
2777       break;
2778     default:
2779       barf("Unexpected closure type %s in blocking queue of %p (%s)",
2780            info_type(bqe), node, info_type(node));
2781       break;
2782     }
2783   } /* for */
2784   fputc('\n', stderr);
2785 }
2786 #else
2787 /* 
2788    Nice and easy: only TSOs on the blocking queue
2789 */
2790 void 
2791 print_bq (StgClosure *node)
2792 {
2793   StgTSO *tso;
2794
2795   ASSERT(node!=(StgClosure*)NULL);         // sanity check
2796   for (tso = ((StgBlockingQueue*)node)->blocking_queue;
2797        tso != END_TSO_QUEUE; 
2798        tso=tso->link) {
2799     ASSERT(tso!=(StgTSO*)NULL && tso!=END_TSO_QUEUE);   // sanity check
2800     ASSERT(get_itbl(tso)->type == TSO);  // guess what, sanity check
2801     fprintf(stderr," TSO %d (%x),", tso->id, tso);
2802   }
2803   fputc('\n', stderr);
2804 }
2805 # endif
2806
2807 /* A debugging function used all over the place in GranSim and GUM.
2808    Dummy function in other setups.
2809 */
2810 # if !defined(GRAN) && !defined(PAR)
2811 char *
2812 info_type(StgClosure *closure){ 
2813   return "petaQ";
2814 }
2815
2816 char *
2817 info_type_by_ip(StgInfoTable *ip){ 
2818   return "petaQ";
2819 }
2820 #endif
2821
2822 static void
2823 sched_belch(char *s, ...)
2824 {
2825   va_list ap;
2826   va_start(ap,s);
2827 #ifdef SMP
2828   fprintf(stderr, "scheduler (task %ld): ", pthread_self());
2829 #else
2830   fprintf(stderr, "scheduler: ");
2831 #endif
2832   vfprintf(stderr, s, ap);
2833   fprintf(stderr, "\n");
2834 }
2835
2836 #endif /* DEBUG */
2837
2838 //@node Index,  , Debugging Routines, Main scheduling code
2839 //@subsection Index
2840
2841 //@index
2842 //* MainRegTable::  @cindex\s-+MainRegTable
2843 //* StgMainThread::  @cindex\s-+StgMainThread
2844 //* awaken_blocked_queue::  @cindex\s-+awaken_blocked_queue
2845 //* blocked_queue_hd::  @cindex\s-+blocked_queue_hd
2846 //* blocked_queue_tl::  @cindex\s-+blocked_queue_tl
2847 //* context_switch::  @cindex\s-+context_switch
2848 //* createThread::  @cindex\s-+createThread
2849 //* free_capabilities::  @cindex\s-+free_capabilities
2850 //* gc_pending_cond::  @cindex\s-+gc_pending_cond
2851 //* initScheduler::  @cindex\s-+initScheduler
2852 //* interrupted::  @cindex\s-+interrupted
2853 //* n_free_capabilities::  @cindex\s-+n_free_capabilities
2854 //* next_thread_id::  @cindex\s-+next_thread_id
2855 //* print_bq::  @cindex\s-+print_bq
2856 //* run_queue_hd::  @cindex\s-+run_queue_hd
2857 //* run_queue_tl::  @cindex\s-+run_queue_tl
2858 //* sched_mutex::  @cindex\s-+sched_mutex
2859 //* schedule::  @cindex\s-+schedule
2860 //* take_off_run_queue::  @cindex\s-+take_off_run_queue
2861 //* task_ids::  @cindex\s-+task_ids
2862 //* term_mutex::  @cindex\s-+term_mutex
2863 //* thread_ready_cond::  @cindex\s-+thread_ready_cond
2864 //@end index