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"));
84 IF_DEBUG(scheduler, sched_belch("%d tasks still running, exiting anyway", tasksRunning));
90 /* Send 'em all a SIGHUP. That should shut 'em up. */
91 awaitDeath = taskCount==0 ? 0 : taskCount-1;
92 for (i = 0; i < taskCount; i++) {
93 /* don't cancel the thread running this piece of code. */
94 if ( taskTable[i].id != tid ) {
95 pthread_kill(taskTable[i].id,SIGTERM);
98 while (awaitDeath > 0) {
106 startTasks (nat num, void (*taskStart)(void))
109 for (i = 0; i < num; i++) {
110 if (!startTask(taskStart)) {
118 newTask (OSThreadId id, rtsBool is_worker)
120 long currentElapsedTime, currentUserTime, elapsedGCTime;
123 if (taskCount >= taskTableSize) {
127 insertHashTable( taskHash, id, &(taskTable[taskCount]) );
129 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
131 task_info = &taskTable[taskCount];
134 task_info->is_worker = is_worker;
135 task_info->stopped = rtsFalse;
136 task_info->mut_time = 0.0;
137 task_info->mut_etime = 0.0;
138 task_info->gc_time = 0.0;
139 task_info->gc_etime = 0.0;
140 task_info->muttimestart = currentUserTime;
141 task_info->elapsedtimestart = currentElapsedTime;
147 IF_DEBUG(scheduler,sched_belch("startTask: new task %ld (total_count: %d; waiting: %d)\n", id, taskCount, rts_n_waiting_tasks););
153 startTask (void (*taskStart)(void))
158 r = createOSThread(&tid,taskStart);
160 barf("startTask: Can't create new task");
162 newTask (tid, rtsTrue);
167 threadIsTask (OSThreadId id)
171 task_info = lookupHashTable(taskHash, id);
172 if (task_info != NULL) {
173 if (task_info->stopped) {
174 task_info->stopped = rtsFalse;
179 return newTask(id, rtsFalse);
183 taskOfId (OSThreadId id)
185 return lookupHashTable(taskHash, id);
192 long currentElapsedTime, currentUserTime, elapsedGCTime;
196 task_info = taskOfId(id);
197 if (task_info == NULL) {
198 debugBelch("taskStop: not a task");
201 ASSERT(task_info->id == id);
203 task_info->stopped = rtsTrue;
206 stat_getTimes(¤tElapsedTime, ¤tUserTime, &elapsedGCTime);
208 task_info->mut_time =
209 currentUserTime - task_info->muttimestart - task_info->gc_time;
210 task_info->mut_etime =
211 currentElapsedTime - task_info->elapsedtimestart - elapsedGCTime;
213 if (task_info->mut_time < 0.0) { task_info->mut_time = 0.0; }
214 if (task_info->mut_etime < 0.0) { task_info->mut_etime = 0.0; }
218 resetTaskManagerAfterFork (void)
220 rts_n_waiting_tasks = 0;
225 maybeStartNewWorker (void (*taskStart)(void))
228 * If more than one worker thread is known to be blocked waiting
229 * on thread_ready_cond, don't create a new one.
231 if ( rts_n_waiting_tasks > 0) {
232 IF_DEBUG(scheduler,sched_belch(
233 "startTask: %d tasks waiting, not creating new one",
234 rts_n_waiting_tasks););
235 // the task will run as soon as a capability is available,
236 // so there's no need to wake it.
240 /* If the task limit has been reached, just return. */
241 if (maxWorkers > 0 && workerCount >= maxWorkers) {
242 IF_DEBUG(scheduler,sched_belch("startTask: worker limit (%d) reached, not creating new one",maxWorkers));
246 return startTask(taskStart);
249 #endif /* RTS_SUPPORTS_THREADS */