[project @ 2004-02-12 02:04:59 by mthomas]
[ghc-hetmet.git] / ghc / rts / Task.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 2001-
4  *
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.
8  *
9  * Two kinds of RTS builds uses 'tasks' - the SMP and the
10  * 'native thread-friendly' builds. 
11  * 
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!)
15  *
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.
21  *
22  * -------------------------------------------------------------------------*/
23 #include "Rts.h"
24 #if defined(RTS_SUPPORTS_THREADS) /* to the end */
25 #include "RtsUtils.h"
26 #include "OSThreads.h"
27 #include "Task.h"
28 #include "Stats.h"
29 #include "RtsFlags.h"
30 #include "Schedule.h"
31
32 /* There's not all that much code that is shared between the
33  * SMP and threads version of the 'task manager.' A sign
34  * that the code ought to be structured differently..(Maybe ToDo).
35  */
36
37 /* 
38  * The following Task Manager-local variables are assumed to be
39  * accessed with the RTS lock in hand.
40  */
41 #if defined(SMP)
42 static TaskInfo* taskTable;
43 #endif
44 /* upper bound / the number of tasks created. */
45 static nat maxTasks;  
46 /* number of tasks currently created */
47 static nat taskCount; 
48
49 #if defined(SMP)
50 void
51 startTaskManager( nat maxCount, void (*taskStart)(void) )
52 {
53   nat i;
54   static int initialized = 0;
55   
56   if (!initialized) {
57   
58     taskCount = 0;
59     maxTasks = maxCount;
60     /* allocate table holding task metadata */
61   
62     if (maxCount > 0) {
63       taskTable = stgMallocBytes(maxCount * sizeof(TaskInfo),
64                                "startTaskManager:tasks");
65
66       /* and eagerly create them all. */
67       for (i = 0; i < maxCount; i++) {
68         startTask(taskStart);
69         taskCount++;
70       }
71     }
72     initialized = 1;
73   }
74 }
75
76 void
77 startTask ( void (*taskStart)(void) )
78 {
79   int r;
80   OSThreadId tid;
81
82   r = createOSThread(&tid,taskStart);
83   if (r != 0) {
84     barf("startTask: Can't create new task");
85   }
86
87   taskTable[taskCount].id = tid;
88   taskTable[taskCount].mut_time = 0.0;
89   taskTable[taskCount].mut_etime = 0.0;
90   taskTable[taskCount].gc_time = 0.0;
91   taskTable[taskCount].gc_etime = 0.0;
92   taskTable[taskCount].elapsedtimestart = stat_getElapsedTime();
93
94   IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Started task: %ld\n",tid););
95   return;
96 }
97
98 void
99 stopTaskManager ()
100 {
101   nat i;
102   OSThreadId tid = osThreadId();
103
104   /* Don't want to use pthread_cancel, since we'd have to install
105    * these silly exception handlers (pthread_cleanup_{push,pop}) around
106    * all our locks.
107    */
108 #if 0
109   /* Cancel all our tasks */
110   for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
111     pthread_cancel(taskTable[i].id);
112   }
113   
114   /* Wait for all the tasks to terminate */
115   for (i = 0; i < maxCount; i++) {
116     IF_DEBUG(scheduler,fprintf(stderr,"scheduler: waiting for task %ld\n", 
117                                taskTable[i].id));
118     pthread_join(taskTable[i].id, NULL);
119   }
120 #endif
121
122   /* Send 'em all a SIGHUP.  That should shut 'em up. */
123   await_death = maxCount - 1;
124   for (i = 0; i < maxCount; i++) {
125     /* don't cancel the thread running this piece of code. */
126     if ( taskTable[i].id != tid ) {
127       pthread_kill(taskTable[i].id,SIGTERM);
128     }
129   }
130   while (await_death > 0) {
131     sched_yield();
132   }
133   
134   return;
135 }
136
137 void
138 resetTaskManagerAfterFork ()
139 {
140         barf("resetTaskManagerAfterFork not implemented for SMP");
141 }
142
143 #else
144 /************ THREADS version *****************/
145
146 void
147 startTaskManager( nat maxCount,
148                   void (*taskStart)(void) STG_UNUSED )
149 {
150   /* In the threaded case, maxCount is used to limit the
151      the creation of worker tasks. Tasks are created lazily, i.e.,
152      when the current task gives up the token on executing
153      STG code.
154   */
155   maxTasks = maxCount;
156   taskCount = 0;
157 }
158
159 void
160 startTask ( void (*taskStart)(void) )
161 {
162   int r;
163   OSThreadId tid;
164   
165   /* If more than one worker thread is known to be blocked waiting
166      on thread_ready_cond, don't create a new one.
167   */
168   if ( rts_n_waiting_tasks > 0) {
169     IF_DEBUG(scheduler,fprintf(stderr,
170                                "scheduler: startTask: %d tasks waiting, not creating new one.\n", 
171                                rts_n_waiting_tasks););
172     // the task will run as soon as a capability is available,
173     // so there's no need to wake it.
174     return;
175   }
176
177   /* If the task limit has been reached, just return. */
178   if (maxTasks > 0 && taskCount == maxTasks) {
179     IF_DEBUG(scheduler,fprintf(stderr,"scheduler: startTask: task limit (%d) reached, not creating new one.\n",maxTasks));
180     return;
181   }
182   
183
184   r = createOSThread(&tid,taskStart);
185   if (r != 0) {
186     barf("startTask: Can't create new task");
187   }
188   taskCount++;
189
190   IF_DEBUG(scheduler,fprintf(stderr,"scheduler: startTask: new task %ld (total_count: %d; waiting: %d)\n", tid, taskCount, rts_n_waiting_tasks););
191   return;
192 }
193
194
195
196 void
197 stopTaskManager ()
198 {
199
200 }
201
202 void
203 resetTaskManagerAfterFork ( void )
204 {
205         rts_n_waiting_tasks = 0;
206         taskCount = 0;
207 }
208 #endif
209
210
211 #endif /* RTS_SUPPORTS_THREADS */