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"
26 // Task lists and global counters.
27 // Locks required: sched_mutex.
28 Task *all_tasks = NULL;
29 static Task *task_free_list = NULL; // singly-linked
31 static nat tasksRunning;
32 static nat workerCount;
34 /* -----------------------------------------------------------------------------
35 * Remembering the current thread's Task
36 * -------------------------------------------------------------------------- */
38 // A thread-local-storage key that we can use to get access to the
39 // current thread's Task structure.
40 #if defined(THREADED_RTS)
41 ThreadLocalKey currentTaskKey;
46 /* -----------------------------------------------------------------------------
47 * Rest of the Task API
48 * -------------------------------------------------------------------------- */
51 initTaskManager (void)
53 static int initialized = 0;
60 #if defined(THREADED_RTS)
61 newThreadLocalKey(¤tTaskKey);
68 stopTaskManager (void)
72 debugTrace(DEBUG_sched,
73 "stopping task manager, %d tasks still running",
76 ACQUIRE_LOCK(&sched_mutex);
77 for (task = task_free_list; task != NULL; task = next) {
79 #if defined(THREADED_RTS)
80 closeCondition(&task->cond);
81 closeMutex(&task->lock);
85 task_free_list = NULL;
86 RELEASE_LOCK(&sched_mutex);
93 #if defined(THREADED_RTS)
94 Ticks currentElapsedTime, currentUserTime;
98 task = stgMallocBytes(sizeof(Task), "newTask");
101 task->stopped = rtsFalse;
102 task->suspended_tso = NULL;
104 task->stat = NoStatus;
107 #if defined(THREADED_RTS)
108 initCondition(&task->cond);
109 initMutex(&task->lock);
110 task->wakeup = rtsFalse;
113 #if defined(THREADED_RTS)
114 currentUserTime = getThreadCPUTime();
115 currentElapsedTime = getProcessElapsedTime();
120 task->muttimestart = currentUserTime;
121 task->elapsedtimestart = currentElapsedTime;
126 task->return_link = NULL;
128 task->all_link = all_tasks;
142 ASSERT_LOCK_HELD(&sched_mutex);
143 if (task_free_list == NULL) {
146 task = task_free_list;
147 task_free_list = task->next;
150 task->stopped = rtsFalse;
152 #if defined(THREADED_RTS)
153 task->id = osThreadId();
155 ASSERT(task->cap == NULL);
161 debugTrace(DEBUG_sched, "new task (taskCount: %d)", taskCount);
166 boundTaskExiting (Task *task)
168 task->stopped = rtsTrue;
171 #if defined(THREADED_RTS)
172 ASSERT(osThreadId() == task->id);
174 ASSERT(myTask() == task);
175 setMyTask(task->prev_stack);
179 // sadly, we need a lock around the free task list. Todo: eliminate.
180 ACQUIRE_LOCK(&sched_mutex);
181 task->next = task_free_list;
182 task_free_list = task;
183 RELEASE_LOCK(&sched_mutex);
185 debugTrace(DEBUG_sched, "task exiting");
189 #define TASK_ID(t) (t)->id
191 #define TASK_ID(t) (t)
195 discardTask (Task *task)
197 ASSERT_LOCK_HELD(&sched_mutex);
198 if (!task->stopped) {
199 debugTrace(DEBUG_sched, "discarding task %ld", (long)TASK_ID(task));
202 task->stopped = rtsTrue;
204 task->next = task_free_list;
205 task_free_list = task;
210 taskTimeStamp (Task *task USED_IF_THREADS)
212 #if defined(THREADED_RTS)
213 Ticks currentElapsedTime, currentUserTime, elapsedGCTime;
215 currentUserTime = getThreadCPUTime();
216 currentElapsedTime = getProcessElapsedTime();
218 // XXX this is wrong; we want elapsed GC time since the
220 elapsedGCTime = stat_getElapsedGCTime();
223 currentUserTime - task->muttimestart - task->gc_time;
225 currentElapsedTime - task->elapsedtimestart - elapsedGCTime;
227 if (task->mut_time < 0) { task->mut_time = 0; }
228 if (task->mut_etime < 0) { task->mut_etime = 0; }
233 workerTaskStop (Task *task)
235 #if defined(THREADED_RTS)
238 ASSERT(task->id == id);
239 ASSERT(myTask() == task);
243 task->stopped = rtsTrue;
248 resetTaskManagerAfterFork (void)
254 #if defined(THREADED_RTS)
257 startWorkerTask (Capability *cap,
258 void OSThreadProcAttr (*taskStart)(Task *task))
266 // A worker always gets a fresh Task structure.
271 // The lock here is to synchronise with taskStart(), to make sure
272 // that we have finished setting up the Task structure before the
273 // worker thread reads it.
274 ACQUIRE_LOCK(&task->lock);
278 // Give the capability directly to the worker; we can't let anyone
279 // else get in, because the new worker Task has nowhere to go to
280 // sleep so that it could be woken up again.
281 ASSERT_LOCK_HELD(&cap->lock);
282 cap->running_task = task;
284 r = createOSThread(&tid, (OSThreadProc *)taskStart, task);
286 sysErrorBelch("failed to create OS thread");
287 stg_exit(EXIT_FAILURE);
290 debugTrace(DEBUG_sched, "new worker task (taskCount: %d)", taskCount);
294 // ok, finished with the Task struct.
295 RELEASE_LOCK(&task->lock);
298 #endif /* THREADED_RTS */
302 static void *taskId(Task *task)
305 return (void *)task->id;
311 void printAllTasks(void);
317 for (task = all_tasks; task != NULL; task = task->all_link) {
318 debugBelch("task %p is %s, ", taskId(task), task->stopped ? "stopped" : "alive");
319 if (!task->stopped) {
321 debugBelch("on capability %d, ", task->cap->no);
324 debugBelch("bound to thread %lu", (unsigned long)task->tso->id);
326 debugBelch("worker");