1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team 2001-2005
5 * The task manager subsystem. Tasks execute STG code, with this
6 * module providing the API which the Scheduler uses to control their
7 * creation and destruction.
9 * -------------------------------------------------------------------------*/
13 #include "OSThreads.h"
15 #include "Capability.h"
27 // Task lists and global counters.
28 // Locks required: sched_mutex.
29 Task *all_tasks = NULL;
30 static Task *task_free_list = NULL; // singly-linked
32 static nat tasksRunning;
33 static nat workerCount;
35 /* -----------------------------------------------------------------------------
36 * Remembering the current thread's Task
37 * -------------------------------------------------------------------------- */
39 // A thread-local-storage key that we can use to get access to the
40 // current thread's Task structure.
41 #if defined(THREADED_RTS)
42 ThreadLocalKey currentTaskKey;
47 /* -----------------------------------------------------------------------------
48 * Rest of the Task API
49 * -------------------------------------------------------------------------- */
52 initTaskManager (void)
54 static int initialized = 0;
61 #if defined(THREADED_RTS)
62 newThreadLocalKey(¤tTaskKey);
69 stopTaskManager (void)
71 debugTrace(DEBUG_sched,
72 "stopping task manager, %d tasks still running",
79 freeTaskManager (void)
83 debugTrace(DEBUG_sched, "freeing task manager");
85 ACQUIRE_LOCK(&sched_mutex);
86 for (task = task_free_list; task != NULL; task = next) {
87 #if defined(THREADED_RTS)
88 closeCondition(&task->cond);
89 closeMutex(&task->lock);
94 task_free_list = NULL;
95 RELEASE_LOCK(&sched_mutex);
102 #if defined(THREADED_RTS)
103 Ticks currentElapsedTime, currentUserTime;
107 task = stgMallocBytes(sizeof(Task), "newTask");
110 task->stopped = rtsFalse;
111 task->suspended_tso = NULL;
113 task->stat = NoStatus;
116 #if defined(THREADED_RTS)
117 initCondition(&task->cond);
118 initMutex(&task->lock);
119 task->wakeup = rtsFalse;
122 #if defined(THREADED_RTS)
123 currentUserTime = getThreadCPUTime();
124 currentElapsedTime = getProcessElapsedTime();
129 task->muttimestart = currentUserTime;
130 task->elapsedtimestart = currentElapsedTime;
135 task->return_link = NULL;
137 task->all_link = all_tasks;
151 ASSERT_LOCK_HELD(&sched_mutex);
152 if (task_free_list == NULL) {
155 task = task_free_list;
156 task_free_list = task->next;
159 task->stopped = rtsFalse;
161 #if defined(THREADED_RTS)
162 task->id = osThreadId();
164 ASSERT(task->cap == NULL);
170 debugTrace(DEBUG_sched, "new task (taskCount: %d)", taskCount);
175 boundTaskExiting (Task *task)
177 task->stopped = rtsTrue;
180 #if defined(THREADED_RTS)
181 ASSERT(osThreadId() == task->id);
183 ASSERT(myTask() == task);
184 setMyTask(task->prev_stack);
188 // sadly, we need a lock around the free task list. Todo: eliminate.
189 ACQUIRE_LOCK(&sched_mutex);
190 task->next = task_free_list;
191 task_free_list = task;
192 RELEASE_LOCK(&sched_mutex);
194 debugTrace(DEBUG_sched, "task exiting");
198 #define TASK_ID(t) (t)->id
200 #define TASK_ID(t) (t)
204 discardTask (Task *task)
206 ASSERT_LOCK_HELD(&sched_mutex);
207 if (!task->stopped) {
208 debugTrace(DEBUG_sched, "discarding task %ld", (long)TASK_ID(task));
211 task->stopped = rtsTrue;
213 task->next = task_free_list;
214 task_free_list = task;
219 taskTimeStamp (Task *task USED_IF_THREADS)
221 #if defined(THREADED_RTS)
222 Ticks currentElapsedTime, currentUserTime, elapsedGCTime;
224 currentUserTime = getThreadCPUTime();
225 currentElapsedTime = getProcessElapsedTime();
227 // XXX this is wrong; we want elapsed GC time since the
229 elapsedGCTime = stat_getElapsedGCTime();
232 currentUserTime - task->muttimestart - task->gc_time;
234 currentElapsedTime - task->elapsedtimestart - elapsedGCTime;
236 if (task->mut_time < 0) { task->mut_time = 0; }
237 if (task->mut_etime < 0) { task->mut_etime = 0; }
242 workerTaskStop (Task *task)
244 #if defined(THREADED_RTS)
247 ASSERT(task->id == id);
248 ASSERT(myTask() == task);
252 task->stopped = rtsTrue;
257 resetTaskManagerAfterFork (void)
263 #if defined(THREADED_RTS)
266 startWorkerTask (Capability *cap,
267 void OSThreadProcAttr (*taskStart)(Task *task))
275 // A worker always gets a fresh Task structure.
280 // The lock here is to synchronise with taskStart(), to make sure
281 // that we have finished setting up the Task structure before the
282 // worker thread reads it.
283 ACQUIRE_LOCK(&task->lock);
287 // Give the capability directly to the worker; we can't let anyone
288 // else get in, because the new worker Task has nowhere to go to
289 // sleep so that it could be woken up again.
290 ASSERT_LOCK_HELD(&cap->lock);
291 cap->running_task = task;
293 r = createOSThread(&tid, (OSThreadProc *)taskStart, task);
295 sysErrorBelch("failed to create OS thread");
296 stg_exit(EXIT_FAILURE);
299 debugTrace(DEBUG_sched, "new worker task (taskCount: %d)", taskCount);
303 // ok, finished with the Task struct.
304 RELEASE_LOCK(&task->lock);
307 #endif /* THREADED_RTS */
311 static void *taskId(Task *task)
314 return (void *)task->id;
320 void printAllTasks(void);
326 for (task = all_tasks; task != NULL; task = task->all_link) {
327 debugBelch("task %p is %s, ", taskId(task), task->stopped ? "stopped" : "alive");
328 if (!task->stopped) {
330 debugBelch("on capability %d, ", task->cap->no);
333 debugBelch("bound to thread %lu", (unsigned long)task->tso->id);
335 debugBelch("worker");