1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team 2001-
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 * Two kinds of RTS builds uses 'tasks' - the SMP and the
10 * 'native thread-friendly' builds.
12 * The SMP build lets multiple tasks concurrently execute STG code,
13 * all sharing vital internal RTS data structures in a controlled manner
14 * (see details elsewhere...ToDo: fill in ref!)
16 * The 'threads' build has at any one time only one task executing STG
17 * code, other tasks are either busy executing code outside the RTS
18 * (e.g., a C call) or waiting for their turn to (again) evaluate some
19 * STG code. A task relinquishes its RTS token when it is asked to
20 * evaluate an external (C) call.
22 * -------------------------------------------------------------------------*/
24 #if defined(RTS_SUPPORTS_THREADS) /* to the end */
26 #include "OSThreads.h"
36 /* There's not all that much code that is shared between the
37 * SMP and threads version of the 'task manager.' A sign
38 * that the code ought to be structured differently..(Maybe ToDo).
42 * The following Task Manager-local variables are assumed to be
43 * accessed with the RTS lock in hand.
48 /* upper bound / the number of tasks created. */
50 /* number of tasks currently created */
52 static nat awaitDeath;
56 startTaskManager( nat maxCount, void (*taskStart)(void) )
59 static int initialized = 0;
65 /* allocate table holding task metadata */
68 taskTable = stgMallocBytes(maxCount * sizeof(TaskInfo),
69 "startTaskManager:tasks");
71 /* and eagerly create them all. */
72 for (i = 0; i < maxCount; i++) {
82 startTask ( void (*taskStart)(void) )
87 r = createOSThread(&tid,taskStart);
89 barf("startTask: Can't create new task");
92 taskTable[taskCount].id = tid;
93 taskTable[taskCount].mut_time = 0.0;
94 taskTable[taskCount].mut_etime = 0.0;
95 taskTable[taskCount].gc_time = 0.0;
96 taskTable[taskCount].gc_etime = 0.0;
97 taskTable[taskCount].elapsedtimestart = stat_getElapsedTime();
99 IF_DEBUG(scheduler,debugBelch("scheduler: Started task: %ld\n",tid););
104 stopTaskManager (void)
107 OSThreadId tid = osThreadId();
109 /* Don't want to use pthread_cancel, since we'd have to install
110 * these silly exception handlers (pthread_cleanup_{push,pop}) around
114 /* Cancel all our tasks */
115 for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
116 pthread_cancel(taskTable[i].id);
119 /* Wait for all the tasks to terminate */
120 for (i = 0; i < maxCount; i++) {
121 IF_DEBUG(scheduler,debugBelch("scheduler: waiting for task %ld\n",
123 pthread_join(taskTable[i].id, NULL);
127 /* Send 'em all a SIGHUP. That should shut 'em up. */
128 awaitDeath = taskCount==0 ? 0 : taskCount-1;
129 for (i = 0; i < taskCount; i++) {
130 /* don't cancel the thread running this piece of code. */
131 if ( taskTable[i].id != tid ) {
132 pthread_kill(taskTable[i].id,SIGTERM);
135 while (awaitDeath > 0) {
143 resetTaskManagerAfterFork (void)
145 barf("resetTaskManagerAfterFork not implemented for SMP");
149 /************ THREADS version *****************/
152 startTaskManager( nat maxCount,
153 void (*taskStart)(void) STG_UNUSED )
155 /* In the threaded case, maxCount is used to limit the
156 the creation of worker tasks. Tasks are created lazily, i.e.,
157 when the current task gives up the token on executing
165 startTask ( void (*taskStart)(void) )
170 /* If more than one worker thread is known to be blocked waiting
171 on thread_ready_cond, don't create a new one.
173 if ( rts_n_waiting_tasks > 0) {
174 IF_DEBUG(scheduler,debugBelch(
175 "scheduler: startTask: %d tasks waiting, not creating new one.\n",
176 rts_n_waiting_tasks););
177 // the task will run as soon as a capability is available,
178 // so there's no need to wake it.
182 /* If the task limit has been reached, just return. */
183 if (maxTasks > 0 && taskCount == maxTasks) {
184 IF_DEBUG(scheduler,debugBelch("scheduler: startTask: task limit (%d) reached, not creating new one.\n",maxTasks));
188 r = createOSThread(&tid,taskStart);
190 barf("startTask: Can't create new task");
194 IF_DEBUG(scheduler,debugBelch("scheduler: startTask: new task %ld (total_count: %d; waiting: %d)\n", tid, taskCount, rts_n_waiting_tasks););
207 resetTaskManagerAfterFork ( void )
209 rts_n_waiting_tasks = 0;
215 #endif /* RTS_SUPPORTS_THREADS */