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)
89 IF_DEBUG(scheduler, sched_belch("stopping task manager, %d tasks still running", tasksRunning));
90 for (i = 1000; i > 0; i--) {
91 if (tasksRunning == 0) {
92 IF_DEBUG(scheduler, sched_belch("all tasks stopped"));
95 IF_DEBUG(scheduler, sched_belch("yielding"));
99 IF_DEBUG(scheduler, sched_belch("%d tasks still running, exiting anyway", tasksRunning));
105 /* Send 'em all a SIGHUP. That should shut 'em up. */
106 awaitDeath = taskCount==0 ? 0 : taskCount-1;
107 for (i = 0; i < taskCount; i++) {
108 /* don't cancel the thread running this piece of code. */
109 if ( taskTable[i].id != tid ) {
110 pthread_kill(taskTable[i].id,SIGTERM);
113 while (awaitDeath > 0) {
121 startTasks (nat num, void (*taskStart)(void))
124 for (i = 0; i < num; i++) {
125 if (!startTask(taskStart)) {
133 newTask (OSThreadId id, rtsBool is_worker)
135 long currentElapsedTime, currentUserTime, elapsedGCTime;
138 if (taskCount >= taskTableSize) {
142 insertHashTable( taskHash, id, &(taskTable[taskCount]) );
144 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
146 task_info = &taskTable[taskCount];
149 task_info->is_worker = is_worker;
150 task_info->stopped = rtsFalse;
151 task_info->mut_time = 0.0;
152 task_info->mut_etime = 0.0;
153 task_info->gc_time = 0.0;
154 task_info->gc_etime = 0.0;
155 task_info->muttimestart = currentUserTime;
156 task_info->elapsedtimestart = currentElapsedTime;
162 IF_DEBUG(scheduler,sched_belch("startTask: new task %ld (total_count: %d; waiting: %d)\n", id, taskCount, rts_n_waiting_tasks););
168 startTask (void (*taskStart)(void))
173 r = createOSThread(&tid,taskStart);
175 barf("startTask: Can't create new task");
177 newTask (tid, rtsTrue);
182 threadIsTask (OSThreadId id)
186 task_info = lookupHashTable(taskHash, id);
187 if (task_info != NULL) {
188 if (task_info->stopped) {
189 task_info->stopped = rtsFalse;
194 return newTask(id, rtsFalse);
198 taskOfId (OSThreadId id)
200 return lookupHashTable(taskHash, id);
207 long currentElapsedTime, currentUserTime, elapsedGCTime;
211 task_info = taskOfId(id);
212 if (task_info == NULL) {
213 debugBelch("taskStop: not a task");
216 ASSERT(task_info->id == id);
218 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
220 task_info->mut_time =
221 currentUserTime - task_info->muttimestart - task_info->gc_time;
222 task_info->mut_etime =
223 currentElapsedTime - task_info->elapsedtimestart - elapsedGCTime;
225 if (task_info->mut_time < 0.0) { task_info->mut_time = 0.0; }
226 if (task_info->mut_etime < 0.0) { task_info->mut_etime = 0.0; }
228 task_info->stopped = rtsTrue;
233 resetTaskManagerAfterFork (void)
235 rts_n_waiting_tasks = 0;
240 maybeStartNewWorker (void (*taskStart)(void))
243 * If more than one worker thread is known to be blocked waiting
244 * on thread_ready_cond, don't create a new one.
246 if ( rts_n_waiting_tasks > 0) {
247 IF_DEBUG(scheduler,sched_belch(
248 "startTask: %d tasks waiting, not creating new one",
249 rts_n_waiting_tasks););
250 // the task will run as soon as a capability is available,
251 // so there's no need to wake it.
255 /* If the task limit has been reached, just return. */
256 if (maxWorkers > 0 && workerCount >= maxWorkers) {
257 IF_DEBUG(scheduler,sched_belch("startTask: worker limit (%d) reached, not creating new one",maxWorkers));
261 return startTask(taskStart);
264 #endif /* RTS_SUPPORTS_THREADS */