d11162e47dcf091ad5b3949e97d480641db58bad
[ghc-hetmet.git] / ghc / rts / Schedule.h
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 1998-2005
4  *
5  * Prototypes for functions in Schedule.c 
6  * (RTS internal scheduler interface)
7  *
8  * -------------------------------------------------------------------------*/
9
10 #ifndef SCHEDULE_H
11 #define SCHEDULE_H
12
13 #include "OSThreads.h"
14 #include "Capability.h"
15
16 /* initScheduler(), exitScheduler()
17  * Called from STG :  no
18  * Locks assumed   :  none
19  */
20 void initScheduler (void);
21 void exitScheduler (void);
22
23 // Place a new thread on the run queue of the specified Capability
24 void scheduleThread (Capability *cap, StgTSO *tso);
25
26 /* awakenBlockedQueue()
27  *
28  * Takes a pointer to the beginning of a blocked TSO queue, and
29  * wakes up the entire queue.
30  * Called from STG :  yes
31  * Locks assumed   :  none
32  */
33 #if defined(GRAN)
34 void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
35 #elif defined(PAR)
36 void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
37 #else
38 void awakenBlockedQueue (Capability *cap, StgTSO *tso);
39 #endif
40
41 /* unblockOne()
42  *
43  * Put the specified thread on the run queue of the given Capability.
44  * Called from STG :  yes
45  * Locks assumed   :  we own the Capability.
46  */
47 StgTSO * unblockOne(Capability *cap, StgTSO *tso);
48
49 /* raiseAsync()
50  *
51  * Raises an exception asynchronously in the specified thread.
52  *
53  * Called from STG :  yes
54  * Locks assumed   :  none
55  */
56 void raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception);
57
58 /* suspendComputation()
59  *
60  * A variant of raiseAsync(), this strips the stack of the specified
61  * thread down to the stop_here point, leaving a current closure on
62  * top of the stack at [stop_here - 1].
63  */
64 void suspendComputation(Capability *cap, StgTSO *tso, StgPtr stop_here);
65
66 /* raiseExceptionHelper */
67 StgWord raiseExceptionHelper (StgRegTable *reg, StgTSO *tso, StgClosure *exception);
68
69 /* findRetryFrameHelper */
70 StgWord findRetryFrameHelper (StgTSO *tso);
71
72 /* GetRoots(evac_fn f)
73  *
74  * Call f() for each root known to the scheduler.
75  *
76  * Called from STG :  NO
77  * Locks assumed   :  ????
78  */
79 void GetRoots(evac_fn);
80
81 /* workerStart()
82  * 
83  * Entry point for a new worker task.
84  * Called from STG :  NO
85  * Locks assumed   :  none
86  */
87 void workerStart(Task *task);
88
89 #if defined(GRAN)
90 void    awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node);
91 void    unlink_from_bq(StgTSO* tso, StgClosure* node);
92 void    initThread(StgTSO *tso, nat stack_size, StgInt pri);
93 #elif defined(PAR)
94 nat     run_queue_len(void);
95 void    awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node);
96 void    initThread(StgTSO *tso, nat stack_size);
97 #else
98 char   *info_type(StgClosure *closure);    // dummy
99 char   *info_type_by_ip(StgInfoTable *ip); // dummy
100 void    awaken_blocked_queue(StgTSO *q);
101 void    initThread(StgTSO *tso, nat stack_size);
102 #endif
103
104 /* Context switch flag.
105  * Locks required  : none (conflicts are harmless)
106  */
107 extern int RTS_VAR(context_switch);
108
109 /* The state of the scheduler.  This is used to control the sequence
110  * of events during shutdown, and when the runtime is interrupted
111  * using ^C.
112  */
113 #define SCHED_RUNNING       0  /* running as normal */
114 #define SCHED_INTERRUPTING  1  /* ^C detected, before threads are deleted */
115 #define SCHED_INTERRUPTED   2  /* ^C detected, after threads deleted */
116 #define SCHED_SHUTTING_DOWN 3  /* final shutdown */
117
118 extern rtsBool RTS_VAR(sched_state);
119
120 /* 
121  * flag that tracks whether we have done any execution in this time slice.
122  */
123 #define ACTIVITY_YES      0 /* there has been activity in the current slice */
124 #define ACTIVITY_MAYBE_NO 1 /* no activity in the current slice */
125 #define ACTIVITY_INACTIVE 2 /* a complete slice has passed with no activity */
126 #define ACTIVITY_DONE_GC  3 /* like 2, but we've done a GC too */
127
128 /* Recent activity flag.
129  * Locks required  : Transition from MAYBE_NO to INACTIVE
130  * happens in the timer signal, so it is atomic.  Trnasition from
131  * INACTIVE to DONE_GC happens under sched_mutex.  No lock required
132  * to set it to ACTIVITY_YES.
133  */
134 extern nat recent_activity;
135
136 /* Thread queues.
137  * Locks required  : sched_mutex
138  *
139  * In GranSim we have one run/blocked_queue per PE.
140  */
141 #if defined(GRAN)
142 // run_queue_hds defined in GranSim.h
143 #else
144 extern  StgTSO *RTS_VAR(blackhole_queue);
145 #if !defined(THREADED_RTS)
146 extern  StgTSO *RTS_VAR(blocked_queue_hd), *RTS_VAR(blocked_queue_tl);
147 extern  StgTSO *RTS_VAR(sleeping_queue);
148 #endif
149 #endif
150
151 /* Linked list of all threads.
152  * Locks required  : sched_mutex
153  */
154 extern  StgTSO *RTS_VAR(all_threads);
155
156 /* Set to rtsTrue if there are threads on the blackhole_queue, and
157  * it is possible that one or more of them may be available to run.
158  * This flag is set to rtsFalse after we've checked the queue, and
159  * set to rtsTrue just before we run some Haskell code.  It is used
160  * to decide whether we should yield the Capability or not.
161  * Locks required  : none (see scheduleCheckBlackHoles()).
162  */
163 extern rtsBool blackholes_need_checking;
164
165 #if defined(THREADED_RTS)
166 extern Mutex RTS_VAR(sched_mutex);
167 #endif
168
169 StgBool isThreadBound(StgTSO *tso);
170
171 SchedulerStatus rts_mainLazyIO(HaskellObj p, /*out*/HaskellObj *ret);
172
173 /* Called by shutdown_handler(). */
174 void interruptStgRts (void);
175
176 nat  run_queue_len (void);
177
178 void resurrectThreads (StgTSO *);
179
180 void printAllThreads(void);
181
182 /* debugging only 
183  */
184 #ifdef DEBUG
185 void print_bq (StgClosure *node);
186 #endif
187 #if defined(PAR)
188 void print_bqe (StgBlockingQueueElement *bqe);
189 #endif
190
191 void labelThread(StgPtr tso, char *label);
192
193 /* -----------------------------------------------------------------------------
194  * Some convenient macros/inline functions...
195  */
196
197 #if !IN_STG_CODE
198
199 /* END_TSO_QUEUE and friends now defined in includes/StgMiscClosures.h */
200
201 /* Add a thread to the end of the run queue.
202  * NOTE: tso->link should be END_TSO_QUEUE before calling this macro.
203  * ASSUMES: cap->running_task is the current task.
204  */
205 STATIC_INLINE void
206 appendToRunQueue (Capability *cap, StgTSO *tso)
207 {
208     ASSERT(tso->link == END_TSO_QUEUE);
209     if (cap->run_queue_hd == END_TSO_QUEUE) {
210         cap->run_queue_hd = tso;
211     } else {
212         cap->run_queue_tl->link = tso;
213     }
214     cap->run_queue_tl = tso;
215 }
216
217 /* Push a thread on the beginning of the run queue.  Used for
218  * newly awakened threads, so they get run as soon as possible.
219  * ASSUMES: cap->running_task is the current task.
220  */
221 STATIC_INLINE void
222 pushOnRunQueue (Capability *cap, StgTSO *tso)
223 {
224     tso->link = cap->run_queue_hd;
225     cap->run_queue_hd = tso;
226     if (cap->run_queue_tl == END_TSO_QUEUE) {
227         cap->run_queue_tl = tso;
228     }
229 }
230
231 /* Pop the first thread off the runnable queue.
232  */
233 STATIC_INLINE StgTSO *
234 popRunQueue (Capability *cap)
235
236     StgTSO *t = cap->run_queue_hd;
237     ASSERT(t != END_TSO_QUEUE);
238     cap->run_queue_hd = t->link;
239     t->link = END_TSO_QUEUE;
240     if (cap->run_queue_hd == END_TSO_QUEUE) {
241         cap->run_queue_tl = END_TSO_QUEUE;
242     }
243     return t;
244 }
245
246 /* Add a thread to the end of the blocked queue.
247  */
248 #if !defined(THREADED_RTS)
249 STATIC_INLINE void
250 appendToBlockedQueue(StgTSO *tso)
251 {
252     ASSERT(tso->link == END_TSO_QUEUE);
253     if (blocked_queue_hd == END_TSO_QUEUE) {
254         blocked_queue_hd = tso;
255     } else {
256         blocked_queue_tl->link = tso;
257     }
258     blocked_queue_tl = tso;
259 }
260 #endif
261
262 #if defined(THREADED_RTS)
263 STATIC_INLINE void
264 appendToWakeupQueue (Capability *cap, StgTSO *tso)
265 {
266     ASSERT(tso->link == END_TSO_QUEUE);
267     if (cap->wakeup_queue_hd == END_TSO_QUEUE) {
268         cap->wakeup_queue_hd = tso;
269     } else {
270         cap->wakeup_queue_tl->link = tso;
271     }
272     cap->wakeup_queue_tl = tso;
273 }
274 #endif
275
276 /* Check whether various thread queues are empty
277  */
278 STATIC_INLINE rtsBool
279 emptyQueue (StgTSO *q)
280 {
281     return (q == END_TSO_QUEUE);
282 }
283
284 STATIC_INLINE rtsBool
285 emptyRunQueue(Capability *cap)
286 {
287     return emptyQueue(cap->run_queue_hd);
288 }
289
290 #if defined(THREADED_RTS)
291 STATIC_INLINE rtsBool
292 emptyWakeupQueue(Capability *cap)
293 {
294     return emptyQueue(cap->wakeup_queue_hd);
295 }
296 #endif
297
298 #if !defined(THREADED_RTS)
299 #define EMPTY_BLOCKED_QUEUE()  (emptyQueue(blocked_queue_hd))
300 #define EMPTY_SLEEPING_QUEUE() (emptyQueue(sleeping_queue))
301 #endif
302
303 STATIC_INLINE rtsBool
304 emptyThreadQueues(Capability *cap)
305 {
306     return emptyRunQueue(cap)
307 #if !defined(THREADED_RTS)
308         && EMPTY_BLOCKED_QUEUE() && EMPTY_SLEEPING_QUEUE()
309 #endif
310     ;
311 }
312
313 #ifdef DEBUG
314 void sched_belch(char *s, ...)
315    GNU_ATTRIBUTE(format (printf, 1, 2));
316 #endif
317
318 #endif /* !IN_STG_CODE */
319
320 STATIC_INLINE void
321 dirtyTSO (StgTSO *tso)
322 {
323     tso->flags |= TSO_DIRTY;
324 }
325
326 #endif /* SCHEDULE_H */
327