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