takeMVar/putMVar were missing some write barriers when modifying a TSO
[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 /* Interrupted flag.
110  * Locks required  : none (makes one transition from false->true)
111  */
112 extern rtsBool RTS_VAR(interrupted);
113
114 /* Shutdown flag.
115  * Locks required  : none (makes one transition from false->true)
116  */
117 extern rtsBool shutting_down_scheduler;
118
119 /* 
120  * flag that tracks whether we have done any execution in this time slice.
121  */
122 #define ACTIVITY_YES      0 /* there has been activity in the current slice */
123 #define ACTIVITY_MAYBE_NO 1 /* no activity in the current slice */
124 #define ACTIVITY_INACTIVE 2 /* a complete slice has passed with no activity */
125 #define ACTIVITY_DONE_GC  3 /* like 2, but we've done a GC too */
126
127 /* Recent activity flag.
128  * Locks required  : Transition from MAYBE_NO to INACTIVE
129  * happens in the timer signal, so it is atomic.  Trnasition from
130  * INACTIVE to DONE_GC happens under sched_mutex.  No lock required
131  * to set it to ACTIVITY_YES.
132  */
133 extern nat recent_activity;
134
135 /* Thread queues.
136  * Locks required  : sched_mutex
137  *
138  * In GranSim we have one run/blocked_queue per PE.
139  */
140 #if defined(GRAN)
141 // run_queue_hds defined in GranSim.h
142 #else
143 extern  StgTSO *RTS_VAR(blackhole_queue);
144 #if !defined(THREADED_RTS)
145 extern  StgTSO *RTS_VAR(blocked_queue_hd), *RTS_VAR(blocked_queue_tl);
146 extern  StgTSO *RTS_VAR(sleeping_queue);
147 #endif
148 #endif
149
150 /* Linked list of all threads.
151  * Locks required  : sched_mutex
152  */
153 extern  StgTSO *RTS_VAR(all_threads);
154
155 /* Set to rtsTrue if there are threads on the blackhole_queue, and
156  * it is possible that one or more of them may be available to run.
157  * This flag is set to rtsFalse after we've checked the queue, and
158  * set to rtsTrue just before we run some Haskell code.  It is used
159  * to decide whether we should yield the Capability or not.
160  * Locks required  : none (see scheduleCheckBlackHoles()).
161  */
162 extern rtsBool blackholes_need_checking;
163
164 #if defined(THREADED_RTS)
165 extern Mutex RTS_VAR(sched_mutex);
166 #endif
167
168 StgBool isThreadBound(StgTSO *tso);
169
170 SchedulerStatus rts_mainLazyIO(HaskellObj p, /*out*/HaskellObj *ret);
171
172 /* Called by shutdown_handler(). */
173 void interruptStgRts (void);
174
175 nat  run_queue_len (void);
176
177 void resurrectThreads (StgTSO *);
178
179 void printAllThreads(void);
180
181 /* debugging only 
182  */
183 #ifdef DEBUG
184 void print_bq (StgClosure *node);
185 #endif
186 #if defined(PAR)
187 void print_bqe (StgBlockingQueueElement *bqe);
188 #endif
189
190 void labelThread(StgPtr tso, char *label);
191
192 /* -----------------------------------------------------------------------------
193  * Some convenient macros/inline functions...
194  */
195
196 #if !IN_STG_CODE
197
198 /* END_TSO_QUEUE and friends now defined in includes/StgMiscClosures.h */
199
200 /* Add a thread to the end of the run queue.
201  * NOTE: tso->link should be END_TSO_QUEUE before calling this macro.
202  * ASSUMES: cap->running_task is the current task.
203  */
204 STATIC_INLINE void
205 appendToRunQueue (Capability *cap, StgTSO *tso)
206 {
207     ASSERT(tso->link == END_TSO_QUEUE);
208     if (cap->run_queue_hd == END_TSO_QUEUE) {
209         cap->run_queue_hd = tso;
210     } else {
211         cap->run_queue_tl->link = tso;
212     }
213     cap->run_queue_tl = tso;
214 }
215
216 /* Push a thread on the beginning of the run queue.  Used for
217  * newly awakened threads, so they get run as soon as possible.
218  * ASSUMES: cap->running_task is the current task.
219  */
220 STATIC_INLINE void
221 pushOnRunQueue (Capability *cap, StgTSO *tso)
222 {
223     tso->link = cap->run_queue_hd;
224     cap->run_queue_hd = tso;
225     if (cap->run_queue_tl == END_TSO_QUEUE) {
226         cap->run_queue_tl = tso;
227     }
228 }
229
230 /* Pop the first thread off the runnable queue.
231  */
232 STATIC_INLINE StgTSO *
233 popRunQueue (Capability *cap)
234
235     StgTSO *t = cap->run_queue_hd;
236     ASSERT(t != END_TSO_QUEUE);
237     cap->run_queue_hd = t->link;
238     t->link = END_TSO_QUEUE;
239     if (cap->run_queue_hd == END_TSO_QUEUE) {
240         cap->run_queue_tl = END_TSO_QUEUE;
241     }
242     return t;
243 }
244
245 /* Add a thread to the end of the blocked queue.
246  */
247 #if !defined(THREADED_RTS)
248 STATIC_INLINE void
249 appendToBlockedQueue(StgTSO *tso)
250 {
251     ASSERT(tso->link == END_TSO_QUEUE);
252     if (blocked_queue_hd == END_TSO_QUEUE) {
253         blocked_queue_hd = tso;
254     } else {
255         blocked_queue_tl->link = tso;
256     }
257     blocked_queue_tl = tso;
258 }
259 #endif
260
261 /* Check whether various thread queues are empty
262  */
263 STATIC_INLINE rtsBool
264 emptyQueue (StgTSO *q)
265 {
266     return (q == END_TSO_QUEUE);
267 }
268
269 STATIC_INLINE rtsBool
270 emptyRunQueue(Capability *cap)
271 {
272     return emptyQueue(cap->run_queue_hd);
273 }
274
275 #if !defined(THREADED_RTS)
276 #define EMPTY_BLOCKED_QUEUE()  (emptyQueue(blocked_queue_hd))
277 #define EMPTY_SLEEPING_QUEUE() (emptyQueue(sleeping_queue))
278 #endif
279
280 STATIC_INLINE rtsBool
281 emptyThreadQueues(Capability *cap)
282 {
283     return emptyRunQueue(cap)
284 #if !defined(THREADED_RTS)
285         && EMPTY_BLOCKED_QUEUE() && EMPTY_SLEEPING_QUEUE()
286 #endif
287     ;
288 }
289
290 #ifdef DEBUG
291 void sched_belch(char *s, ...)
292    GNU_ATTRIBUTE(format (printf, 1, 2));
293 #endif
294
295 #endif /* !IN_STG_CODE */
296
297 STATIC_INLINE void
298 dirtyTSO (StgTSO *tso)
299 {
300     tso->flags |= TSO_DIRTY;
301 }
302
303 #endif /* SCHEDULE_H */
304