Fold testsuite.git into ghc.git (re #8545)
[ghc.git] / rts / Task.h
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team 2001-2005
4 *
5 * Tasks
6 *
7 * For details on the high-level design, see
8 * http://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler
9 *
10 * -------------------------------------------------------------------------*/
11
12 #ifndef TASK_H
13 #define TASK_H
14
15 #include "GetTime.h"
16
17 #include "BeginPrivate.h"
18
19 /*
20 Definition of a Task
21 --------------------
22
23 A task is an OSThread that runs Haskell code. Every OSThread that
24 runs inside the RTS, whether as a worker created by the RTS or via
25 an in-call from C to Haskell, has an associated Task. The first
26 time an OS thread calls into Haskell it is allocated a Task, which
27 remains until the RTS is shut down.
28
29 There is a one-to-one relationship between OSThreads and Tasks.
30 The Task for an OSThread is kept in thread-local storage, and can
31 be retrieved at any time using myTask().
32
33 In the THREADED_RTS build, multiple Tasks may all be running
34 Haskell code simultaneously. A task relinquishes its Capability
35 when it is asked to evaluate an external (C) call.
36
37 Ownership of Task
38 -----------------
39
40 The OS thread named in the Task structure has exclusive access to
41 the structure, as long as it is the running_task of its Capability.
42 That is, if (task->cap->running_task == task), then task->id owns
43 the Task. Otherwise the Task is owned by the owner of the parent
44 data structure on which it is sleeping; for example, if the task is
45 sleeping on spare_workers field of a Capability, then the owner of the
46 Capability has access to the Task.
47
48 When a task is migrated from sleeping on one Capability to another,
49 its task->cap field must be modified. When the task wakes up, it
50 will read the new value of task->cap to find out which Capability
51 it belongs to. Hence some synchronisation is required on
52 task->cap, and this is why we have task->lock.
53
54 If the Task is not currently owned by task->id, then the thread is
55 either
56
57 (a) waiting on the condition task->cond. The Task is either
58 (1) a bound Task, the TSO will be on a queue somewhere
59 (2) a worker task, on the spare_workers queue of task->cap.
60
61 (b) making a foreign call. The InCall will be on the
62 suspended_ccalls list.
63
64 We re-establish ownership in each case by respectively
65
66 (a) the task is currently blocked in yieldCapability().
67 This call will return when we have ownership of the Task and
68 a Capability. The Capability we get might not be the same
69 as the one we had when we called yieldCapability().
70
71 (b) we must call resumeThread(task), which will safely establish
72 ownership of the Task and a Capability.
73 */
74
75 // The InCall structure represents either a single in-call from C to
76 // Haskell, or a worker thread.
77 typedef struct InCall_ {
78 StgTSO * tso; // the bound TSO (or NULL for a worker)
79
80 StgTSO * suspended_tso; // the TSO is stashed here when we
81 // make a foreign call (NULL otherwise);
82
83 Capability *suspended_cap; // The capability that the
84 // suspended_tso is on, because
85 // we can't read this from the TSO
86 // without owning a Capability in the
87 // first place.
88
89 SchedulerStatus stat; // return status
90 StgClosure ** ret; // return value
91
92 struct Task_ *task;
93
94 // When a Haskell thread makes a foreign call that re-enters
95 // Haskell, we end up with another Task associated with the
96 // current thread. We have to remember the whole stack of InCalls
97 // associated with the current Task so that we can correctly
98 // save & restore the InCall on entry to and exit from Haskell.
99 struct InCall_ *prev_stack;
100
101 // Links InCalls onto suspended_ccalls, spare_incalls
102 struct InCall_ *prev;
103 struct InCall_ *next;
104 } InCall;
105
106 typedef struct Task_ {
107 #if defined(THREADED_RTS)
108 OSThreadId id; // The OS Thread ID of this task
109
110 Condition cond; // used for sleeping & waking up this task
111 Mutex lock; // lock for the condition variable
112
113 // this flag tells the task whether it should wait on task->cond
114 // or just continue immediately. It's a workaround for the fact
115 // that signalling a condition variable doesn't do anything if the
116 // thread is already running, but we want it to be sticky.
117 rtsBool wakeup;
118 #endif
119
120 // This points to the Capability that the Task "belongs" to. If
121 // the Task owns a Capability, then task->cap points to it. If
122 // the task does not own a Capability, then either (a) if the task
123 // is a worker, then task->cap points to the Capability it belongs
124 // to, or (b) it is returning from a foreign call, then task->cap
125 // points to the Capability with the returning_worker queue that this
126 // this Task is on.
127 //
128 // When a task goes to sleep, it may be migrated to a different
129 // Capability. Hence, we always check task->cap on wakeup. To
130 // syncrhonise between the migrater and the migratee, task->lock
131 // must be held when modifying task->cap.
132 struct Capability_ *cap;
133
134 // The current top-of-stack InCall
135 struct InCall_ *incall;
136
137 nat n_spare_incalls;
138 struct InCall_ *spare_incalls;
139
140 rtsBool worker; // == rtsTrue if this is a worker Task
141 rtsBool stopped; // this task has stopped or exited Haskell
142
143 // So that we can detect when a finalizer illegally calls back into Haskell
144 rtsBool running_finalizers;
145
146 // Links tasks on the returning_tasks queue of a Capability, and
147 // on spare_workers.
148 struct Task_ *next;
149
150 // Links tasks on the all_tasks list
151 struct Task_ *all_next;
152 struct Task_ *all_prev;
153
154 } Task;
155
156 INLINE_HEADER rtsBool
157 isBoundTask (Task *task)
158 {
159 return (task->incall->tso != NULL);
160 }
161
162 // Linked list of all tasks.
163 //
164 extern Task *all_tasks;
165
166 // Start and stop the task manager.
167 // Requires: sched_mutex.
168 //
169 void initTaskManager (void);
170 nat freeTaskManager (void);
171
172 // Create a new Task for a bound thread
173 // Requires: sched_mutex.
174 //
175 Task *newBoundTask (void);
176
177 // The current task is a bound task that is exiting.
178 // Requires: sched_mutex.
179 //
180 void boundTaskExiting (Task *task);
181
182 // Notify the task manager that a task has stopped. This is used
183 // mainly for stats-gathering purposes.
184 // Requires: sched_mutex.
185 //
186 #if defined(THREADED_RTS)
187 // In the non-threaded RTS, tasks never stop.
188 void workerTaskStop (Task *task);
189 #endif
190
191 // Put the task back on the free list, mark it stopped. Used by
192 // forkProcess().
193 //
194 void discardTasksExcept (Task *keep);
195
196 // Get the Task associated with the current OS thread (or NULL if none).
197 //
198 INLINE_HEADER Task *myTask (void);
199
200 #if defined(THREADED_RTS)
201
202 // Workers are attached to the supplied Capability. This Capability
203 // should not currently have a running_task, because the new task
204 // will become the running_task for that Capability.
205 // Requires: sched_mutex.
206 //
207 void startWorkerTask (Capability *cap);
208
209 // Interrupts a worker task that is performing an FFI call. The thread
210 // should not be destroyed.
211 //
212 void interruptWorkerTask (Task *task);
213
214 #endif /* THREADED_RTS */
215
216 // For stats
217 extern nat taskCount;
218 extern nat workerCount;
219 extern nat peakWorkerCount;
220
221 // -----------------------------------------------------------------------------
222 // INLINE functions... private from here on down:
223
224 // A thread-local-storage key that we can use to get access to the
225 // current thread's Task structure.
226 #if defined(THREADED_RTS)
227 #if ((defined(linux_HOST_OS) && \
228 (defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH))) || \
229 (defined(mingw32_HOST_OS) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4)) && \
230 (!defined(llvm_CC_FLAVOR))
231 #define MYTASK_USE_TLV
232 extern __thread Task *my_task;
233 #else
234 extern ThreadLocalKey currentTaskKey;
235 #endif
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) && !defined(MYTASK_USE_TLV)
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) && !defined(MYTASK_USE_TLV)
260 setThreadLocalVar(&currentTaskKey,task);
261 #else
262 my_task = task;
263 #endif
264 }
265
266 // Tasks are identified by their OS thread ID, which can be serialised
267 // to StgWord64, as defined below.
268 typedef StgWord64 TaskId;
269
270 // Get a unique serialisable representation for a task id.
271 //
272 // It's only unique within the process. For example if they are emitted in a
273 // log file then it is suitable to work out which log entries are releated.
274 //
275 // This is needed because OSThreadId is an opaque type
276 // and in practice on some platforms it is a pointer type.
277 //
278 #if defined(THREADED_RTS)
279 INLINE_HEADER TaskId serialiseTaskId (OSThreadId taskID) {
280 #if defined(freebsd_HOST_OS) || defined(darwin_HOST_OS)
281 // Here OSThreadId is a pthread_t and pthread_t is a pointer, but within
282 // the process we can still use that pointer value as a unique id.
283 return (TaskId) (size_t) taskID;
284 #else
285 // On Windows, Linux and others it's an integral type to start with.
286 return (TaskId) taskID;
287 #endif
288 }
289 #endif
290
291 //
292 // Get a serialisable Id for the Task's OS thread
293 // Needed mainly for logging since the OSThreadId is an opaque type
294 INLINE_HEADER TaskId
295 serialisableTaskId (Task *task
296 #if !defined(THREADED_RTS)
297 STG_UNUSED
298 #endif
299 )
300 {
301 #if defined(THREADED_RTS)
302 return serialiseTaskId(task->id);
303 #else
304 return (TaskId) (size_t) task;
305 #endif
306 }
307
308 #include "EndPrivate.h"
309
310 #endif /* TASK_H */