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 * -------------------------------------------------------------------------*/
12 #if defined(RTS_SUPPORTS_THREADS) /* to the end */
14 #include "OSThreads.h"
20 #include "Capability.h"
26 #define INIT_TASK_TABLE_SIZE 16
29 static nat taskTableSize;
31 HashTable *taskHash; // maps OSThreadID to TaskInfo*
34 static nat tasksRunning;
35 static nat workerCount;
37 #define DEFAULT_MAX_WORKERS 64
38 nat maxWorkers; // we won't create more workers than this
41 initTaskManager (void)
43 static int initialized = 0;
46 taskTableSize = INIT_TASK_TABLE_SIZE;
47 taskTable = stgMallocBytes( taskTableSize * sizeof(TaskInfo),
54 taskHash = allocHashTable();
56 maxWorkers = DEFAULT_MAX_WORKERS;
63 expandTaskTable (void)
66 taskTable = stgReallocBytes(taskTable, taskTableSize * sizeof(TaskInfo),
71 stopTaskManager (void)
75 IF_DEBUG(scheduler, sched_belch("stopping task manager, %d tasks still running", tasksRunning));
76 for (i = 1000; i > 0; i--) {
77 if (tasksRunning == 0) {
78 IF_DEBUG(scheduler, sched_belch("all tasks stopped"));
81 IF_DEBUG(scheduler, sched_belch("yielding"));
85 IF_DEBUG(scheduler, sched_belch("%d tasks still running, exiting anyway", tasksRunning));
91 /* Send 'em all a SIGHUP. That should shut 'em up. */
92 awaitDeath = taskCount==0 ? 0 : taskCount-1;
93 for (i = 0; i < taskCount; i++) {
94 /* don't cancel the thread running this piece of code. */
95 if ( taskTable[i].id != tid ) {
96 pthread_kill(taskTable[i].id,SIGTERM);
99 while (awaitDeath > 0) {
107 startTasks (nat num, void (*taskStart)(void))
110 for (i = 0; i < num; i++) {
111 if (!startTask(taskStart)) {
119 newTask (OSThreadId id, rtsBool is_worker)
121 long currentElapsedTime, currentUserTime, elapsedGCTime;
124 if (taskCount >= taskTableSize) {
128 insertHashTable( taskHash, id, &(taskTable[taskCount]) );
130 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
132 task_info = &taskTable[taskCount];
135 task_info->is_worker = is_worker;
136 task_info->stopped = rtsFalse;
137 task_info->mut_time = 0.0;
138 task_info->mut_etime = 0.0;
139 task_info->gc_time = 0.0;
140 task_info->gc_etime = 0.0;
141 task_info->muttimestart = currentUserTime;
142 task_info->elapsedtimestart = currentElapsedTime;
148 IF_DEBUG(scheduler,sched_belch("startTask: new task %ld (total_count: %d; waiting: %d)\n", id, taskCount, rts_n_waiting_tasks););
154 startTask (void (*taskStart)(void))
159 r = createOSThread(&tid,taskStart);
161 barf("startTask: Can't create new task");
163 newTask (tid, rtsTrue);
168 threadIsTask (OSThreadId id)
172 task_info = lookupHashTable(taskHash, id);
173 if (task_info != NULL) {
174 if (task_info->stopped) {
175 task_info->stopped = rtsFalse;
180 return newTask(id, rtsFalse);
184 taskOfId (OSThreadId id)
186 return lookupHashTable(taskHash, id);
193 long currentElapsedTime, currentUserTime, elapsedGCTime;
197 task_info = taskOfId(id);
198 if (task_info == NULL) {
199 debugBelch("taskStop: not a task");
202 ASSERT(task_info->id == id);
204 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
206 task_info->mut_time =
207 currentUserTime - task_info->muttimestart - task_info->gc_time;
208 task_info->mut_etime =
209 currentElapsedTime - task_info->elapsedtimestart - elapsedGCTime;
211 if (task_info->mut_time < 0.0) { task_info->mut_time = 0.0; }
212 if (task_info->mut_etime < 0.0) { task_info->mut_etime = 0.0; }
214 task_info->stopped = rtsTrue;
219 resetTaskManagerAfterFork (void)
221 rts_n_waiting_tasks = 0;
226 maybeStartNewWorker (void (*taskStart)(void))
229 * If more than one worker thread is known to be blocked waiting
230 * on thread_ready_cond, don't create a new one.
232 if ( rts_n_waiting_tasks > 0) {
233 IF_DEBUG(scheduler,sched_belch(
234 "startTask: %d tasks waiting, not creating new one",
235 rts_n_waiting_tasks););
236 // the task will run as soon as a capability is available,
237 // so there's no need to wake it.
241 /* If the task limit has been reached, just return. */
242 if (maxWorkers > 0 && workerCount >= maxWorkers) {
243 IF_DEBUG(scheduler,sched_belch("startTask: worker limit (%d) reached, not creating new one",maxWorkers));
247 return startTask(taskStart);
250 #endif /* RTS_SUPPORTS_THREADS */