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