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