make the smp way RTS-only, normal libraries now work with -smp
[ghc-hetmet.git] / ghc / rts / Task.h
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 2001-2005
4  *
5  * Tasks
6  *
7  * -------------------------------------------------------------------------*/
8
9 #ifndef TASK_H
10 #define TASK_H
11
12 #include "GetTime.h"
13
14 /* 
15    Definition of a Task
16    --------------------
17  
18    A task is an OSThread that runs Haskell code.  Every OSThread
19    created by the RTS for the purposes of running Haskell code is a
20    Task, and OS threads that enter the Haskell RTS for the purposes of
21    making a call-in are also Tasks.
22    
23    The relationship between the number of tasks and capabilities, and
24    the runtime build (-threaded, -smp etc.) is summarised by the
25    following table:
26
27      build        Tasks   Capabilities
28      ---------------------------------
29      normal         1          1
30      -threaded      N          1
31      -smp           N          N
32
33    The non-threaded build has a single Task and a single global
34    Capability.
35    
36    The 'threaded' build has multiple Tasks, but a single Capability.
37    At any one time only one task executing STG code, other tasks are
38    either busy executing code outside the RTS (e.g., a C call) or
39    waiting for their turn to (again) evaluate some STG code. A task
40    relinquishes its RTS token when it is asked to evaluate an external
41    (C) call.
42    
43    The SMP build allows multiple tasks and mulitple Capabilities.
44    Multiple Tasks may all be running Haskell code simultaneously.
45
46    In general, there may be multiple Tasks for an OS thread.  This
47    happens if one Task makes a foreign call from Haskell, and
48    subsequently calls back in to create a new bound thread.
49
50    A particular Task structure can belong to more than one OS thread
51    over its lifetime.  This is to avoid creating an unbounded number
52    of Task structures.  The stats just accumulate.
53
54    Ownership of Task
55    -----------------
56
57    The OS thread named in the Task structure has exclusive access to
58    the structure, as long as it is the running_task of its Capability.
59    That is, if (task->cap->running_task == task), then task->id owns
60    the Task.  Otherwise the Task is owned by the owner of the parent
61    data structure on which it is sleeping; for example, if the task is
62    sleeping on spare_workers field of a Capability, then the owner of the
63    Capability has access to the Task.
64
65    When a task is migrated from sleeping on one Capability to another,
66    its task->cap field must be modified.  When the task wakes up, it
67    will read the new value of task->cap to find out which Capability
68    it belongs to.  Hence some synchronisation is required on
69    task->cap, and this is why we have task->lock.
70
71    If the Task is not currently owned by task->id, then the thread is
72    either
73
74       (a) waiting on the condition task->cond.  The Task is either
75          (1) a bound Task, the TSO will be on a queue somewhere
76          (2) a worker task, on the spare_workers queue of task->cap.
77
78      (b) making a foreign call.  The Task will be on the
79          suspended_ccalling_tasks list.
80
81    We re-establish ownership in each case by respectively
82
83       (a) the task is currently blocked in yieldCapability().
84           This call will return when we have ownership of the Task and
85           a Capability.  The Capability we get might not be the same
86           as the one we had when we called yieldCapability().
87           
88       (b) we must call resumeThread(task), which will safely establish
89           ownership of the Task and a Capability.
90 */
91
92 typedef struct Task_ {
93 #if defined(THREADED_RTS)
94     OSThreadId id;              // The OS Thread ID of this task
95 #endif
96
97     // This points to the Capability that the Task "belongs" to.  If
98     // the Task owns a Capability, then task->cap points to it.  If
99     // the task does not own a Capability, then either (a) if the task
100     // is a worker, then task->cap points to the Capability it belongs
101     // to, or (b) it is returning from a foreign call, then task->cap
102     // points to the Capability with the returning_worker queue that this
103     // this Task is on.
104     //
105     // When a task goes to sleep, it may be migrated to a different
106     // Capability.  Hence, we always check task->cap on wakeup.  To
107     // syncrhonise between the migrater and the migratee, task->lock
108     // must be held when modifying task->cap.
109     struct Capability_ *cap;
110
111     rtsBool    stopped;         // this task has stopped or exited Haskell
112     StgTSO *   suspended_tso;   // the TSO is stashed here when we
113                                 // make a foreign call (NULL otherwise);
114
115     // The following 3 fields are used by bound threads:
116     StgTSO *   tso;             // the bound TSO (or NULL)
117     SchedulerStatus  stat;      // return status
118     StgClosure **    ret;       // return value
119
120 #if defined(THREADED_RTS)
121     Condition cond;             // used for sleeping & waking up this task
122     Mutex lock;                 // lock for the condition variable
123
124     // this flag tells the task whether it should wait on task->cond
125     // or just continue immediately.  It's a workaround for the fact
126     // that signalling a condition variable doesn't do anything if the
127     // thread is already running, but we want it to be sticky.
128     rtsBool wakeup;
129 #endif
130
131     // Stats that we collect about this task
132     // ToDo: we probably want to put this in a separate TaskStats
133     // structure, so we can share it between multiple Tasks.  We don't
134     // really want separate stats for each call in a nested chain of
135     // foreign->haskell->foreign->haskell calls, but we'll get a
136     // separate Task for each of the haskell calls.
137     Ticks       elapsedtimestart;
138     Ticks       muttimestart;
139     Ticks       mut_time;
140     Ticks       mut_etime;
141     Ticks       gc_time;
142     Ticks       gc_etime;
143
144     // Links tasks onto various lists. (ToDo: do we need double
145     // linking now?)
146     struct Task_ *prev;
147     struct Task_ *next;
148
149     // Links tasks on the returning_tasks queue of a Capability.
150     struct Task_ *return_link;
151
152     // Links tasks on the all_tasks list
153     struct Task_ *all_link;
154
155     // When a Haskell thread makes a foreign call that re-enters
156     // Haskell, we end up with another Task associated with the
157     // current thread.  We have to remember the whole stack of Tasks
158     // associated with the current thread so that we can correctly
159     // save & restore the thread-local current task pointer.
160     struct Task_ *prev_stack;
161 } Task;
162
163 INLINE_HEADER rtsBool
164 isBoundTask (Task *task) 
165 {
166     return (task->tso != NULL);
167 }
168
169
170 // Linked list of all tasks.
171 //
172 extern Task *all_tasks;
173
174 // Start and stop the task manager.
175 // Requires: sched_mutex.
176 //
177 void initTaskManager (void);
178 void stopTaskManager (void);
179
180 // Create a new Task for a bound thread
181 // Requires: sched_mutex.
182 //
183 Task *newBoundTask (void);
184
185 // The current task is a bound task that is exiting.
186 // Requires: sched_mutex.
187 //
188 void boundTaskExiting (Task *task);
189
190 // This must be called when a new Task is associated with the current
191 // thread.  It sets up the thread-local current task pointer so that
192 // myTask() can work.
193 INLINE_HEADER void taskEnter (Task *task);
194
195 // Notify the task manager that a task has stopped.  This is used
196 // mainly for stats-gathering purposes.
197 // Requires: sched_mutex.
198 //
199 void taskStop (Task *task);
200
201 // Put the task back on the free list, mark it stopped.  Used by
202 // forkProcess().
203 //
204 void discardTask (Task *task);
205
206 // Get the Task associated with the current OS thread (or NULL if none).
207 //
208 INLINE_HEADER Task *myTask (void);
209
210 // After a fork, the tasks are not carried into the child process, so
211 // we must tell the task manager.
212 // Requires: sched_mutex.
213 //
214 void resetTaskManagerAfterFork (void);
215
216 #if defined(THREADED_RTS)
217
218 // Workers are attached to the supplied Capability.  This Capability
219 // should not currently have a running_task, because the new task
220 // will become the running_task for that Capability.
221 // Requires: sched_mutex.
222 //
223 void startWorkerTask  (struct Capability_ *cap, 
224                        void OSThreadProcAttr (*taskStart)(Task *task));
225
226 #endif /* THREADED_RTS */
227
228 // -----------------------------------------------------------------------------
229 // INLINE functions... private from here on down:
230
231 // A thread-local-storage key that we can use to get access to the
232 // current thread's Task structure.
233 #if defined(THREADED_RTS)
234 extern ThreadLocalKey currentTaskKey;
235 #else
236 extern Task *my_task;
237 #endif
238
239 //
240 // myTask() uses thread-local storage to find the Task associated with
241 // the current OS thread.  If the current OS thread has multiple
242 // Tasks, because it has re-entered the RTS, then the task->prev_stack
243 // field is used to store the previous Task.
244 //
245 INLINE_HEADER Task *
246 myTask (void)
247 {
248 #if defined(THREADED_RTS)
249     return getThreadLocalVar(&currentTaskKey);
250 #else
251     return my_task;
252 #endif
253 }
254
255 INLINE_HEADER void
256 setMyTask (Task *task)
257 {
258 #if defined(THREADED_RTS)
259     setThreadLocalVar(&currentTaskKey,task);
260 #else
261     my_task = task;
262 #endif
263 }
264
265 // This must be called when a new Task is associated with the current
266 // thread.  It sets up the thread-local current task pointer so that
267 // myTask() can work.
268 INLINE_HEADER void
269 taskEnter (Task *task)
270 {
271     // save the current value, just in case this Task has been created
272     // as a result of re-entering the RTS (defaults to NULL):
273     task->prev_stack = myTask();
274     setMyTask(task);
275 }
276
277 #endif /* TASK_H */