[project @ 2002-02-04 20:24:14 by sof]
[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  *
15  * The 'threads' build has at any one time only one task executing STG
16  * code, other tasks are either busy executing code outside the RTS
17  * (e.g., a ccall) or waiting for their turn to (again) evaluate some
18  * STG code. A task relinquishes its RTS token when it is asked to
19  * evaluate an external (C) call.
20  *
21  * -------------------------------------------------------------------------*/
22 #include "Rts.h"
23 #if defined(RTS_SUPPORTS_THREADS) /* to the end */
24 #include "RtsUtils.h"
25 #include "OSThreads.h"
26 #include "Task.h"
27 #include "Stats.h"
28 #include "RtsFlags.h"
29
30 static TaskInfo* taskTable;
31 static nat maxTasks;  /* upper bound / the number of tasks created. */
32 static nat taskCount; /* number of tasks currently created */
33
34
35 #if defined(SMP)
36 void
37 startTaskManager( nat maxCount, void (*taskStart)(void) )
38 {
39   nat i;
40   static int initialized = 0;
41   
42   if (!initialized) {
43   
44     taskCount = 0;
45     maxTasks = maxCount;
46     /* allocate table holding task metadata */
47   
48     if (maxCount > 0) {
49       taskTable = stgMallocBytes(maxCount * sizeof(TaskInfo),
50                                "startTaskManager:tasks");
51
52       /* and eagerly create them all. */
53       for (i = 0; i < maxCount; i++) {
54         startTask(taskStart);
55         taskCount++;
56       }
57     }
58     initialized = 1;
59   }
60 }
61 #else
62 void
63 startTaskManager( nat maxCount, void (*taskStart)(void) )
64 {
65   /* In the threaded case, maxCount is used to limit the
66      the creation of worker tasks. Tasks are created lazily, i.e.,
67      when the current task gives up the token on executing
68      STG code.
69   */
70   maxTasks = maxCount;
71   taskCount = 0;
72 }
73
74 #endif
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 #if defined(SMP)
88   taskTable[taskCount].id = tid;
89   taskTable[taskCount].mut_time = 0.0;
90   taskTable[taskCount].mut_etime = 0.0;
91   taskTable[taskCount].gc_time = 0.0;
92   taskTable[taskCount].gc_etime = 0.0;
93   taskTable[taskCount].elapsedtimestart = stat_getElapsedTime();
94 #endif
95
96   IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Started task: %ld\n",tid););
97   return;
98 }
99
100 #if defined(SMP)
101 void
102 stopTaskManager ()
103 {
104   nat i;
105
106   /* Don't want to use pthread_cancel, since we'd have to install
107    * these silly exception handlers (pthread_cleanup_{push,pop}) around
108    * all our locks.
109    */
110 #if 0
111   /* Cancel all our tasks */
112   for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
113     pthread_cancel(taskTable[i].id);
114   }
115   
116   /* Wait for all the tasks to terminate */
117   for (i = 0; i < maxCount; i++) {
118     IF_DEBUG(scheduler,fprintf(stderr,"scheduler: waiting for task %ld\n", 
119                                taskTable[i].id));
120     pthread_join(taskTable[i].id, NULL);
121   }
122 #endif
123
124   /* Send 'em all a SIGHUP.  That should shut 'em up. */
125   await_death = maxCount;
126   for (i = 0; i < maxCount; i++) {
127     pthread_kill(taskTable[i].id,SIGTERM);
128   }
129   while (await_death > 0) {
130     sched_yield();
131   }
132   
133   return;
134 }
135 #else
136 void
137 stopTaskManager ()
138 {
139
140 }
141 #endif
142
143 nat
144 getTaskCount ()
145 {
146   return taskCount;
147 }
148
149
150 #endif /* RTS_SUPPORTS_THREADS */