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 // maps OSThreadID to TaskInfo*
35 static nat tasksRunning;
36 static nat workerCount;
38 #define DEFAULT_MAX_WORKERS 64
39 nat maxWorkers; // we won't create more workers than this
42 initTaskManager (void)
44 static int initialized = 0;
48 taskTableSize = stg_max(INIT_TASK_TABLE_SIZE,
49 RtsFlags.ParFlags.nNodes * 2);
51 taskTableSize = INIT_TASK_TABLE_SIZE;
53 taskTable = stgMallocBytes( taskTableSize * sizeof(TaskInfo),
60 taskHash = allocHashTable();
62 maxWorkers = DEFAULT_MAX_WORKERS;
69 expandTaskTable (void)
74 taskTable = stgReallocBytes(taskTable, taskTableSize * sizeof(TaskInfo),
77 /* Have to update the hash table now... */
78 for (i = 0; i < taskCount; i++) {
79 removeHashTable( taskHash, taskTable[i].id, NULL );
80 insertHashTable( taskHash, taskTable[i].id, &taskTable[i] );
85 stopTaskManager (void)
87 IF_DEBUG(scheduler, sched_belch("stopping task manager, %d tasks still running", tasksRunning));
92 startTasks (nat num, void (*taskStart)(void))
95 for (i = 0; i < num; i++) {
96 if (!startTask(taskStart)) {
104 newTask (OSThreadId id, rtsBool is_worker)
106 long currentElapsedTime, currentUserTime, elapsedGCTime;
109 if (taskCount >= taskTableSize) {
113 insertHashTable( taskHash, id, &(taskTable[taskCount]) );
115 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
117 task_info = &taskTable[taskCount];
120 task_info->is_worker = is_worker;
121 task_info->stopped = rtsFalse;
122 task_info->mut_time = 0.0;
123 task_info->mut_etime = 0.0;
124 task_info->gc_time = 0.0;
125 task_info->gc_etime = 0.0;
126 task_info->muttimestart = currentUserTime;
127 task_info->elapsedtimestart = currentElapsedTime;
133 IF_DEBUG(scheduler,sched_belch("startTask: new task %ld (total_count: %d; waiting: %d)\n", id, taskCount, rts_n_waiting_tasks););
139 startTask (void (*taskStart)(void))
144 r = createOSThread(&tid,taskStart);
146 barf("startTask: Can't create new task");
148 newTask (tid, rtsTrue);
153 threadIsTask (OSThreadId id)
157 task_info = lookupHashTable(taskHash, id);
158 if (task_info != NULL) {
159 if (task_info->stopped) {
160 task_info->stopped = rtsFalse;
165 return newTask(id, rtsFalse);
169 taskOfId (OSThreadId id)
171 return lookupHashTable(taskHash, id);
178 long currentElapsedTime, currentUserTime, elapsedGCTime;
182 task_info = taskOfId(id);
183 if (task_info == NULL) {
184 debugBelch("taskStop: not a task");
187 ASSERT(task_info->id == id);
189 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
191 task_info->mut_time =
192 currentUserTime - task_info->muttimestart - task_info->gc_time;
193 task_info->mut_etime =
194 currentElapsedTime - task_info->elapsedtimestart - elapsedGCTime;
196 if (task_info->mut_time < 0.0) { task_info->mut_time = 0.0; }
197 if (task_info->mut_etime < 0.0) { task_info->mut_etime = 0.0; }
199 task_info->stopped = rtsTrue;
204 resetTaskManagerAfterFork (void)
206 rts_n_waiting_tasks = 0;
211 maybeStartNewWorker (void (*taskStart)(void))
214 * If more than one worker thread is known to be blocked waiting
215 * on thread_ready_cond, don't create a new one.
217 if ( rts_n_waiting_tasks > 0) {
218 IF_DEBUG(scheduler,sched_belch(
219 "startTask: %d tasks waiting, not creating new one",
220 rts_n_waiting_tasks););
221 // the task will run as soon as a capability is available,
222 // so there's no need to wake it.
226 /* If the task limit has been reached, just return. */
227 if (maxWorkers > 0 && workerCount >= maxWorkers) {
228 IF_DEBUG(scheduler,sched_belch("startTask: worker limit (%d) reached, not creating new one",maxWorkers));
232 return startTask(taskStart);
235 #endif /* RTS_SUPPORTS_THREADS */