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