| rev |
line source |
|
seanhalle@230
|
1 /*
|
|
seanhalle@230
|
2 * Copyright 2010 OpenSourceStewardshipFoundation
|
|
seanhalle@230
|
3 *
|
|
seanhalle@230
|
4 * Licensed under BSD
|
|
seanhalle@230
|
5 */
|
|
seanhalle@230
|
6
|
|
seanhalle@230
|
7
|
|
seanhalle@230
|
8
|
|
seanhalle@230
|
9 #include <stdio.h>
|
|
seanhalle@230
|
10 #include <stddef.h>
|
|
seanhalle@230
|
11
|
|
seanhalle@260
|
12 #include "PR.h"
|
|
seanhalle@261
|
13 #include "VSs_impl/VSs.h"
|
|
seanhalle@230
|
14
|
|
seanhalle@261
|
15 inline void
|
|
seanhalle@267
|
16 replaceWithNewSlotSlv( SlaveVP *slave );
|
|
seanhalle@230
|
17
|
|
seanhalle@230
|
18
|
|
seanhalle@230
|
19 /*The animationMaster embodies most of the animator of the language. The
|
|
seanhalle@230
|
20 * animator is what emodies the behavior of language constructs.
|
|
seanhalle@230
|
21 * As such, it is the animationMaster, in combination with the plugin
|
|
seanhalle@230
|
22 * functions, that make the language constructs do their behavior.
|
|
seanhalle@230
|
23 *
|
|
seanhalle@230
|
24 *Within the code, this is the top-level-function of the masterVPs, and
|
|
seanhalle@230
|
25 * runs when the coreController has no more slave VPs. It's job is to
|
|
seanhalle@260
|
26 * refill the animation slots with slaves that have work.
|
|
seanhalle@230
|
27 *
|
|
seanhalle@260
|
28 *There are multiple versions of the master, each tuned to a specific
|
|
seanhalle@260
|
29 * combination of modes. This keeps the master simple, with reduced overhead,
|
|
seanhalle@260
|
30 * when the application is not using the extra complexity.
|
|
seanhalle@260
|
31 *
|
|
seanhalle@260
|
32 *As of Sept 2012, the versions available will be:
|
|
seanhalle@260
|
33 * 1) Single langauge, which only exposes slaves (such as SSR or Vthread)
|
|
seanhalle@260
|
34 * 2) Single language, which only exposes tasks (such as pure dataflow)
|
|
seanhalle@260
|
35 * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP)
|
|
seanhalle@260
|
36 * 4) Multi-language, which always assumes both tasks and slaves
|
|
seanhalle@260
|
37 * 5) Multi-language and multi-process, which also assumes both tasks and slaves
|
|
seanhalle@260
|
38 *
|
|
seanhalle@260
|
39 *
|
|
seanhalle@260
|
40 *
|
|
seanhalle@260
|
41 */
|
|
seanhalle@260
|
42
|
|
seanhalle@261
|
43
|
|
seanhalle@260
|
44 //===================== The versions of the Animation Master =================
|
|
seanhalle@260
|
45 //
|
|
seanhalle@260
|
46 //==============================================================================
|
|
seanhalle@260
|
47
|
|
seanhalle@260
|
48 /* 1) This version is for a single language, that has only slaves, no tasks,
|
|
seanhalle@260
|
49 * such as Vthread or SSR.
|
|
seanhalle@260
|
50 *This version is for when an application has only a single language, and
|
|
seanhalle@260
|
51 * that language exposes slaves explicitly (as opposed to a task based
|
|
seanhalle@260
|
52 * language like pure dataflow).
|
|
seanhalle@260
|
53 *
|
|
seanhalle@260
|
54 *
|
|
seanhalle@260
|
55 *It scans the animation slots for just-completed slaves.
|
|
seanhalle@260
|
56 * Each completed slave has a request in it. So, the master hands each to
|
|
seanhalle@260
|
57 * the plugin's request handler (there is only one plugin, because only one
|
|
seanhalle@260
|
58 * lang).
|
|
seanhalle@230
|
59 *Each request represents a language construct that has been encountered
|
|
seanhalle@230
|
60 * by the application code in the slave. Passing the request to the
|
|
seanhalle@230
|
61 * request handler is how that language construct's behavior gets invoked.
|
|
seanhalle@230
|
62 * The request handler then performs the actions of the construct's
|
|
seanhalle@230
|
63 * behavior. So, the request handler encodes the behavior of the
|
|
seanhalle@230
|
64 * language's parallelism constructs, and performs that when the master
|
|
seanhalle@230
|
65 * hands it a slave containing a request to perform that construct.
|
|
seanhalle@230
|
66 *
|
|
seanhalle@230
|
67 *On a shared-memory machine, the behavior of parallelism constructs
|
|
seanhalle@230
|
68 * equals control, over order of execution of code. Hence, the behavior
|
|
seanhalle@230
|
69 * of the language constructs performed by the request handler is to
|
|
seanhalle@230
|
70 * choose the order that slaves get animated, and thereby control the
|
|
seanhalle@230
|
71 * order that application code in the slaves executes.
|
|
seanhalle@230
|
72 *
|
|
seanhalle@230
|
73 *To control order of animation of slaves, the request handler has a
|
|
seanhalle@230
|
74 * semantic environment that holds data structures used to hold slaves
|
|
seanhalle@230
|
75 * and choose when they're ready to be animated.
|
|
seanhalle@230
|
76 *
|
|
seanhalle@230
|
77 *Once a slave is marked as ready to be animated by the request handler,
|
|
seanhalle@230
|
78 * it is the second plugin function, the Assigner, which chooses the core
|
|
seanhalle@230
|
79 * the slave gets assigned to for animation. Hence, the Assigner doesn't
|
|
seanhalle@230
|
80 * perform any of the semantic behavior of language constructs, rather
|
|
seanhalle@230
|
81 * it gives the language a chance to improve performance. The performance
|
|
seanhalle@230
|
82 * of application code is strongly related to communication between
|
|
seanhalle@230
|
83 * cores. On shared-memory machines, communication is caused during
|
|
seanhalle@230
|
84 * execution of code, by memory accesses, and how much depends on contents
|
|
seanhalle@230
|
85 * of caches connected to the core executing the code. So, the placement
|
|
seanhalle@230
|
86 * of slaves determines the communication caused during execution of the
|
|
seanhalle@230
|
87 * slave's code.
|
|
seanhalle@230
|
88 *The point of the Assigner, then, is to use application information during
|
|
seanhalle@230
|
89 * execution of the program, to make choices about slave placement onto
|
|
seanhalle@230
|
90 * cores, with the aim to put slaves close to caches containing the data
|
|
seanhalle@230
|
91 * used by the slave's code.
|
|
seanhalle@230
|
92 *
|
|
seanhalle@230
|
93 *==========================================================================
|
|
seanhalle@230
|
94 *In summary, the animationMaster scans the slots, finds slaves
|
|
seanhalle@230
|
95 * just-finished, which hold requests, pass those to the request handler,
|
|
seanhalle@230
|
96 * along with the semantic environment, and the request handler then manages
|
|
seanhalle@230
|
97 * the structures in the semantic env, which controls the order of
|
|
seanhalle@230
|
98 * animation of slaves, and so embodies the behavior of the language
|
|
seanhalle@230
|
99 * constructs.
|
|
seanhalle@230
|
100 *The animationMaster then rescans the slots, offering each empty one to
|
|
seanhalle@230
|
101 * the Assigner, along with the semantic environment. The Assigner chooses
|
|
seanhalle@230
|
102 * among the ready slaves in the semantic Env, finding the one best suited
|
|
seanhalle@230
|
103 * to be animated by that slot's associated core.
|
|
seanhalle@230
|
104 *
|
|
seanhalle@230
|
105 *==========================================================================
|
|
seanhalle@230
|
106 *Implementation Details:
|
|
seanhalle@230
|
107 *
|
|
seanhalle@230
|
108 *There is a separate masterVP for each core, but a single semantic
|
|
seanhalle@230
|
109 * environment shared by all cores. Each core also has its own scheduling
|
|
seanhalle@230
|
110 * slots, which are used to communicate slaves between animationMaster and
|
|
seanhalle@261
|
111 * coreController. There is only one global variable, _PRTopEnv, which
|
|
seanhalle@230
|
112 * holds the semantic env and other things shared by the different
|
|
seanhalle@230
|
113 * masterVPs. The request handler and Assigner are registered with
|
|
seanhalle@230
|
114 * the animationMaster by the language's init function, and a pointer to
|
|
seanhalle@261
|
115 * each is in the _PRTopEnv. (There are also some pthread related global
|
|
seanhalle@260
|
116 * vars, but they're only used during init of PR).
|
|
seanhalle@260
|
117 *PR gains control over the cores by essentially "turning off" the OS's
|
|
seanhalle@230
|
118 * scheduler, using pthread pin-to-core commands.
|
|
seanhalle@230
|
119 *
|
|
seanhalle@230
|
120 *The masterVPs are created during init, with this animationMaster as their
|
|
seanhalle@230
|
121 * top level function. The masterVPs use the same SlaveVP data structure,
|
|
seanhalle@230
|
122 * even though they're not slave VPs.
|
|
seanhalle@230
|
123 *A "seed slave" is also created during init -- this is equivalent to the
|
|
seanhalle@260
|
124 * "main" function in C, and acts as the entry-point to the PR-language-
|
|
seanhalle@230
|
125 * based application.
|
|
seanhalle@260
|
126 *The masterVPs share a single system-wide master-lock, so only one
|
|
seanhalle@230
|
127 * masterVP may be animated at a time.
|
|
seanhalle@261
|
128 *The core controllers access _PRTopEnv to get the masterVP, and when
|
|
seanhalle@230
|
129 * they start, the slots are all empty, so they run their associated core's
|
|
seanhalle@230
|
130 * masterVP. The first of those to get the master lock sees the seed slave
|
|
seanhalle@230
|
131 * in the shared semantic environment, so when it runs the Assigner, that
|
|
seanhalle@230
|
132 * returns the seed slave, which the animationMaster puts into a scheduling
|
|
seanhalle@230
|
133 * slot then switches to the core controller. That then switches the core
|
|
seanhalle@230
|
134 * over to the seed slave, which then proceeds to execute language
|
|
seanhalle@230
|
135 * constructs to create more slaves, and so on. Each of those constructs
|
|
seanhalle@230
|
136 * causes the seed slave to suspend, switching over to the core controller,
|
|
seanhalle@230
|
137 * which eventually switches to the masterVP, which executes the
|
|
seanhalle@260
|
138 * request handler, which uses PR primitives to carry out the creation of
|
|
seanhalle@230
|
139 * new slave VPs, which are marked as ready for the Assigner, and so on..
|
|
seanhalle@230
|
140 *
|
|
seanhalle@230
|
141 *On animation slots, and system behavior:
|
|
seanhalle@260
|
142 * A request may linger in an animation slot for a long time while
|
|
seanhalle@230
|
143 * the slaves in the other slots are animated. This only becomes a problem
|
|
seanhalle@230
|
144 * when such a request is a choke-point in the constraints, and is needed
|
|
seanhalle@260
|
145 * to free work for *other* cores. To reduce this occurrence, the number
|
|
seanhalle@230
|
146 * of animation slots should be kept low. In balance, having multiple
|
|
seanhalle@230
|
147 * animation slots amortizes the overhead of switching to the masterVP and
|
|
seanhalle@230
|
148 * executing the animationMaster code, which drives for more than one. In
|
|
seanhalle@230
|
149 * practice, the best balance should be discovered by profiling.
|
|
seanhalle@230
|
150 */
|
|
seanhalle@230
|
151 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@230
|
152 {
|
|
seanhalle@230
|
153 //Used while scanning and filling animation slots
|
|
seanhalle@230
|
154 int32 slotIdx, numSlotsFilled;
|
|
seanhalle@235
|
155 AnimSlot *currSlot, **animSlots;
|
|
seanhalle@230
|
156 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
|
|
seanhalle@230
|
157
|
|
seanhalle@230
|
158 //Local copies, for performance
|
|
seanhalle@230
|
159 MasterEnv *masterEnv;
|
|
seanhalle@230
|
160 SlaveAssigner slaveAssigner;
|
|
seanhalle@230
|
161 RequestHandler requestHandler;
|
|
seanhalle@230
|
162 void *semanticEnv;
|
|
seanhalle@230
|
163 int32 thisCoresIdx;
|
|
nengel@238
|
164
|
|
seanhalle@230
|
165 //======================== Initializations ========================
|
|
seanhalle@261
|
166 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@230
|
167
|
|
seanhalle@230
|
168 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@235
|
169 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@230
|
170
|
|
seanhalle@230
|
171 requestHandler = masterEnv->requestHandler;
|
|
seanhalle@230
|
172 slaveAssigner = masterEnv->slaveAssigner;
|
|
seanhalle@230
|
173 semanticEnv = masterEnv->semanticEnv;
|
|
nengel@238
|
174
|
|
nengel@238
|
175 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@230
|
176
|
|
seanhalle@230
|
177 //======================== animationMaster ========================
|
|
seanhalle@230
|
178 while(1){
|
|
seanhalle@230
|
179
|
|
seanhalle@230
|
180 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@230
|
181
|
|
seanhalle@230
|
182 //Scan the animation slots
|
|
seanhalle@230
|
183 numSlotsFilled = 0;
|
|
seanhalle@236
|
184 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@230
|
185 {
|
|
seanhalle@235
|
186 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@230
|
187
|
|
nengel@239
|
188 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@230
|
189 if( currSlot->workIsDone )
|
|
seanhalle@230
|
190 {
|
|
seanhalle@230
|
191 currSlot->workIsDone = FALSE;
|
|
seanhalle@267
|
192 currSlot->needsWorkAssigned = TRUE;
|
|
nengel@238
|
193
|
|
nengel@238
|
194 HOLISTIC__Record_AppResponder_start;
|
|
seanhalle@230
|
195 MEAS__startReqHdlr;
|
|
seanhalle@230
|
196
|
|
seanhalle@260
|
197 currSlot->workIsDone = FALSE;
|
|
seanhalle@267
|
198 currSlot->needsWorkAssigned = TRUE;
|
|
seanhalle@260
|
199 SlaveVP *currSlave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@260
|
200
|
|
seanhalle@260
|
201 justAddedReqHdlrChg();
|
|
seanhalle@261
|
202 //handle the request, either by PR or by the language
|
|
seanhalle@260
|
203 if( currSlave->requests->reqType != LangReq )
|
|
seanhalle@261
|
204 { //The request is a standard PR one, not one defined by the
|
|
seanhalle@261
|
205 // language, so PR handles it, then queues slave to be assigned
|
|
seanhalle@261
|
206 handleReqInPR( currSlave );
|
|
seanhalle@261
|
207 writePrivQ( currSlave, PRReadyQ ); //Q slave to be assigned below
|
|
seanhalle@260
|
208 }
|
|
seanhalle@260
|
209 else
|
|
seanhalle@260
|
210 { MEAS__startReqHdlr;
|
|
seanhalle@260
|
211
|
|
seanhalle@260
|
212 //Language handles request, which is held inside slave struc
|
|
seanhalle@260
|
213 (*requestHandler)( currSlave, semanticEnv );
|
|
seanhalle@260
|
214
|
|
seanhalle@260
|
215 MEAS__endReqHdlr;
|
|
seanhalle@260
|
216 }
|
|
seanhalle@260
|
217 }
|
|
seanhalle@260
|
218
|
|
seanhalle@260
|
219 //process the requests made by the slave (held inside slave struc)
|
|
seanhalle@230
|
220 (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv );
|
|
seanhalle@230
|
221
|
|
nengel@238
|
222 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@230
|
223 MEAS__endReqHdlr;
|
|
seanhalle@230
|
224 }
|
|
seanhalle@230
|
225 //If slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@267
|
226 if( currSlot->needsWorkAssigned )
|
|
seanhalle@230
|
227 { //Call plugin's Assigner to give slot a new slave
|
|
nengel@238
|
228 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@230
|
229 assignedSlaveVP =
|
|
seanhalle@230
|
230 (*slaveAssigner)( semanticEnv, currSlot );
|
|
seanhalle@230
|
231
|
|
seanhalle@230
|
232 //put the chosen slave into slot, and adjust flags and state
|
|
seanhalle@230
|
233 if( assignedSlaveVP != NULL )
|
|
seanhalle@230
|
234 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@235
|
235 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@267
|
236 currSlot->needsWorkAssigned = FALSE;
|
|
seanhalle@230
|
237 numSlotsFilled += 1;
|
|
nengel@238
|
238
|
|
nengel@238
|
239 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@230
|
240 }
|
|
seanhalle@230
|
241 }
|
|
seanhalle@230
|
242 }
|
|
seanhalle@230
|
243
|
|
seanhalle@230
|
244 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@230
|
245
|
|
seanhalle@231
|
246 masterSwitchToCoreCtlr( masterVP );
|
|
seanhalle@230
|
247 flushRegisters();
|
|
seanhalle@235
|
248 DEBUG__printf(FALSE,"came back after switch to core -- so lock released!");
|
|
seanhalle@232
|
249 }//while(1)
|
|
seanhalle@230
|
250 }
|
|
seanhalle@230
|
251
|
|
seanhalle@260
|
252
|
|
seanhalle@260
|
253 /* 2) This version is for a single language that has only tasks, which
|
|
seanhalle@260
|
254 * cannot be suspended.
|
|
seanhalle@260
|
255 */
|
|
seanhalle@260
|
256 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@260
|
257 {
|
|
seanhalle@260
|
258 //Used while scanning and filling animation slots
|
|
seanhalle@260
|
259 int32 slotIdx, numSlotsFilled;
|
|
seanhalle@260
|
260 AnimSlot *currSlot, **animSlots;
|
|
seanhalle@260
|
261 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
|
|
seanhalle@260
|
262
|
|
seanhalle@260
|
263 //Local copies, for performance
|
|
seanhalle@260
|
264 MasterEnv *masterEnv;
|
|
seanhalle@260
|
265 SlaveAssigner slaveAssigner;
|
|
seanhalle@260
|
266 RequestHandler requestHandler;
|
|
seanhalle@260
|
267 PRSemEnv *semanticEnv;
|
|
seanhalle@260
|
268 int32 thisCoresIdx;
|
|
seanhalle@260
|
269
|
|
seanhalle@260
|
270 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
271 SlaveVP *slave;
|
|
seanhalle@260
|
272 PRProcess *process;
|
|
seanhalle@260
|
273 int32 langMagicNumber;
|
|
seanhalle@260
|
274 //#endif
|
|
seanhalle@260
|
275
|
|
seanhalle@260
|
276 //======================== Initializations ========================
|
|
seanhalle@261
|
277 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@260
|
278
|
|
seanhalle@260
|
279 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@260
|
280 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@260
|
281
|
|
seanhalle@260
|
282 requestHandler = masterEnv->requestHandler;
|
|
seanhalle@260
|
283 slaveAssigner = masterEnv->slaveAssigner;
|
|
seanhalle@260
|
284 semanticEnv = masterEnv->semanticEnv;
|
|
seanhalle@260
|
285
|
|
seanhalle@260
|
286 //initialize, for non-multi-lang, non multi-proc case
|
|
seanhalle@260
|
287 // default handler gets put into master env by a registration call by lang
|
|
seanhalle@260
|
288 endTaskHandler = masterEnv->defaultTaskHandler;
|
|
seanhalle@260
|
289
|
|
seanhalle@260
|
290 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@260
|
291
|
|
seanhalle@260
|
292 //======================== animationMaster ========================
|
|
seanhalle@260
|
293 //Do loop gets requests handled and work assigned to slots..
|
|
seanhalle@260
|
294 // work can either be a task or a resumed slave
|
|
seanhalle@260
|
295 //Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
296 // then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
297 // loops that are inter-twined..
|
|
seanhalle@260
|
298 while(1){
|
|
seanhalle@260
|
299
|
|
seanhalle@260
|
300 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@260
|
301
|
|
seanhalle@260
|
302 //Scan the animation slots
|
|
seanhalle@260
|
303 numSlotsFilled = 0;
|
|
seanhalle@260
|
304 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@260
|
305 {
|
|
seanhalle@260
|
306 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@260
|
307
|
|
seanhalle@260
|
308 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@260
|
309 if( currSlot->workIsDone )
|
|
seanhalle@260
|
310 { currSlot->workIsDone = FALSE;
|
|
seanhalle@260
|
311
|
|
seanhalle@260
|
312 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@260
|
313 MEAS__startReqHdlr;
|
|
seanhalle@260
|
314
|
|
seanhalle@260
|
315
|
|
seanhalle@260
|
316 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@260
|
317 slave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@260
|
318
|
|
seanhalle@260
|
319 //check if the completed work was a task..
|
|
seanhalle@267
|
320 if( slave->metaTask->isATask )
|
|
seanhalle@260
|
321 {
|
|
seanhalle@267
|
322 if( slave->request->type == TaskEnd )
|
|
seanhalle@260
|
323 { //do task end handler, which is registered separately
|
|
seanhalle@260
|
324 //note, end hdlr may use semantic data from reqst..
|
|
seanhalle@260
|
325 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
326 //get end-task handler
|
|
seanhalle@260
|
327 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
|
|
seanhalle@267
|
328 taskEndHandler = slave->metaTask->endTaskHandler;
|
|
seanhalle@260
|
329 //#endif
|
|
seanhalle@260
|
330 (*taskEndHandler)( slave, semanticEnv );
|
|
seanhalle@260
|
331
|
|
seanhalle@260
|
332 goto AssignWork;
|
|
seanhalle@260
|
333 }
|
|
seanhalle@260
|
334 else //is a task, and just suspended
|
|
seanhalle@260
|
335 { //turn slot slave into free task slave & make replacement
|
|
seanhalle@266
|
336 if( slave->typeOfVP == SlotTaskSlv ) changeSlvType();
|
|
seanhalle@260
|
337
|
|
seanhalle@260
|
338 //goto normal slave request handling
|
|
seanhalle@260
|
339 goto SlaveReqHandling;
|
|
seanhalle@260
|
340 }
|
|
seanhalle@260
|
341 }
|
|
seanhalle@260
|
342 else //is a slave that suspended
|
|
seanhalle@260
|
343 {
|
|
seanhalle@260
|
344 SlaveReqHandling:
|
|
seanhalle@260
|
345 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
|
|
seanhalle@260
|
346
|
|
seanhalle@260
|
347 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@260
|
348 MEAS__endReqHdlr;
|
|
seanhalle@260
|
349
|
|
seanhalle@260
|
350 goto AssignWork;
|
|
seanhalle@260
|
351 }
|
|
seanhalle@260
|
352 } //if has suspended slave that needs handling
|
|
seanhalle@260
|
353
|
|
seanhalle@260
|
354 //if slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@267
|
355 if( currSlot->needsWorkAssigned )
|
|
seanhalle@260
|
356 { //Call plugin's Assigner to give slot a new slave
|
|
seanhalle@260
|
357 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@260
|
358
|
|
seanhalle@260
|
359 AssignWork:
|
|
seanhalle@260
|
360
|
|
seanhalle@260
|
361 assignedSlaveVP = assignWork( semanticEnv, currSlot );
|
|
seanhalle@260
|
362
|
|
seanhalle@260
|
363 //put the chosen slave into slot, and adjust flags and state
|
|
seanhalle@260
|
364 if( assignedSlaveVP != NULL )
|
|
seanhalle@260
|
365 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@260
|
366 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@267
|
367 currSlot->needsWorkAssigned = FALSE;
|
|
seanhalle@260
|
368 numSlotsFilled += 1;
|
|
seanhalle@260
|
369 }
|
|
seanhalle@260
|
370 else
|
|
seanhalle@260
|
371 {
|
|
seanhalle@267
|
372 currSlot->needsWorkAssigned = TRUE; //local write
|
|
seanhalle@260
|
373 }
|
|
seanhalle@260
|
374 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@260
|
375 }//if slot needs slave assigned
|
|
seanhalle@260
|
376 }//for( slotIdx..
|
|
seanhalle@260
|
377
|
|
seanhalle@260
|
378 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@260
|
379
|
|
seanhalle@260
|
380 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@260
|
381 flushRegisters();
|
|
seanhalle@260
|
382 }//while(1)
|
|
seanhalle@260
|
383 }
|
|
seanhalle@260
|
384
|
|
seanhalle@260
|
385
|
|
seanhalle@260
|
386 /*This is the master when just multi-lang, but not multi-process mode is on.
|
|
seanhalle@260
|
387 * This version has to handle both tasks and slaves, and do extra work of
|
|
seanhalle@260
|
388 * looking up the semantic env and handlers to use, for each completed bit of
|
|
seanhalle@260
|
389 * work.
|
|
seanhalle@260
|
390 *It also has to search through the semantic envs to find one with work,
|
|
seanhalle@260
|
391 * then ask that env's assigner to return a unit of that work.
|
|
seanhalle@260
|
392 *
|
|
seanhalle@260
|
393 *The language is written to startup in the same way as if it were the only
|
|
seanhalle@260
|
394 * language in the app, and it operates in the same way,
|
|
seanhalle@260
|
395 * the only difference between single language and multi-lang is here, in the
|
|
seanhalle@260
|
396 * master.
|
|
seanhalle@260
|
397 *This invisibility to mode is why the language has to use registration calls
|
|
seanhalle@260
|
398 * for everything during startup -- those calls do different things depending
|
|
seanhalle@260
|
399 * on whether it's single-language or multi-language mode.
|
|
seanhalle@260
|
400 *
|
|
seanhalle@260
|
401 *In this version of the master, work can either be a task or a resumed slave
|
|
seanhalle@260
|
402 *Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
403 * then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
404 * loops that are inter-twined..
|
|
seanhalle@260
|
405 *
|
|
seanhalle@260
|
406 *Some special cases:
|
|
seanhalle@260
|
407 * A task-end is a special case for a few reasons (below).
|
|
seanhalle@260
|
408 * A task-end can't block a slave (can't cause it to "logically suspend")
|
|
seanhalle@260
|
409 * A task available for work can only be assigned to a special slave, which
|
|
seanhalle@260
|
410 * has been set aside for doing tasks, one such task-slave is always
|
|
seanhalle@260
|
411 * assigned to each slot. So, when a task ends, a new task is assigned to
|
|
seanhalle@260
|
412 * that slot's task-slave right away.
|
|
seanhalle@260
|
413 * But if no tasks are available, then have to switch over to looking at
|
|
seanhalle@260
|
414 * slaves to find one ready to resume, to find work for the slot.
|
|
seanhalle@260
|
415 * If a task just suspends, not ends, then its task-slave is no longer
|
|
seanhalle@260
|
416 * available to take new tasks, so a new task-slave has to be assigned to
|
|
seanhalle@260
|
417 * that slot. Then the slave of the suspended task is turned into a free
|
|
seanhalle@260
|
418 * task-slave and request handling is done on it as if it were a slave
|
|
seanhalle@260
|
419 * that suspended.
|
|
seanhalle@260
|
420 * After request handling, do the same sequence of looking for a task to be
|
|
seanhalle@260
|
421 * work, and if none, look for a slave ready to resume, as work for the slot.
|
|
seanhalle@260
|
422 * If a slave suspends, handle its request, then look for work.. first for a
|
|
seanhalle@260
|
423 * task to assign, and if none, slaves ready to resume.
|
|
seanhalle@260
|
424 * Another special case is when task-end is done on a free task-slave.. in
|
|
seanhalle@260
|
425 * that case, the slave has no more work and no way to get more.. so place
|
|
seanhalle@260
|
426 * it into a recycle queue.
|
|
seanhalle@260
|
427 * If no work is found of either type, then do a special thing to prune down
|
|
seanhalle@260
|
428 * the extra slaves in the recycle queue, just so don't get too many..
|
|
seanhalle@260
|
429 *
|
|
seanhalle@260
|
430 *The multi-lang thing complicates matters..
|
|
seanhalle@260
|
431 *
|
|
seanhalle@260
|
432 *For request handling, it means have to first fetch the semantic environment
|
|
seanhalle@260
|
433 * of the language, and then do the request handler pointed to by that
|
|
seanhalle@260
|
434 * semantic env.
|
|
seanhalle@260
|
435 *For assigning, things get more complex because of competing goals.. One
|
|
seanhalle@260
|
436 * goal is for language specific stuff to be used during assignment, so
|
|
seanhalle@260
|
437 * assigner can make higher quality decisions.. but with multiple languages,
|
|
seanhalle@260
|
438 * which only get mixed in the application, the assigners can't be written
|
|
seanhalle@260
|
439 * with knowledge of each other. So, they can only make localized decisions,
|
|
seanhalle@260
|
440 * and so different language's assigners may interfere with each other..
|
|
seanhalle@260
|
441 *
|
|
seanhalle@260
|
442 *So, have some possibilities available:
|
|
seanhalle@260
|
443 *1) can have a fixed scheduler in the proto-runtime, that all the
|
|
seanhalle@260
|
444 * languages give their work to.. (but then lose language-specific info,
|
|
seanhalle@260
|
445 * there is a standard PR format for assignment info, and the langauge
|
|
seanhalle@260
|
446 * attaches this to the work-unit when it gives it to PR.. also have issue
|
|
seanhalle@260
|
447 * with HWSim, which uses a priority Q instead of FIFO, and requests can
|
|
seanhalle@260
|
448 * "undo" previous work put in, so request handlers need way to manipulate
|
|
seanhalle@260
|
449 * the work-holding Q..) (this might be fudgeable with
|
|
seanhalle@260
|
450 * HWSim, if the master did a lang-supplied callback each time it assigns a
|
|
seanhalle@260
|
451 * unit to a slot.. then HWSim can keep exactly one unit of work in PR's
|
|
seanhalle@260
|
452 * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies
|
|
seanhalle@260
|
453 * a task-end handler that kicks the next unit of work from HWSim internal
|
|
seanhalle@260
|
454 * priority queue, over to PR readyQ)
|
|
seanhalle@260
|
455 *2) can have each language have its own semantic env, that holds its own
|
|
seanhalle@260
|
456 * work, which is assigned by its own assigner.. then the master searches
|
|
seanhalle@260
|
457 * through all the semantic envs to find one with work and asks it give work..
|
|
seanhalle@260
|
458 * (this has downside of blinding assigners to each other.. but does work
|
|
seanhalle@260
|
459 * for HWSim case)
|
|
seanhalle@260
|
460 *3) could make PR have a different readyQ for each core, and ask the lang
|
|
seanhalle@260
|
461 * to put work to the core it prefers.. but the work may be moved by PR if
|
|
seanhalle@260
|
462 * needed, say if one core idles for too long. This is a hybrid approach,
|
|
seanhalle@260
|
463 * letting the language decide which core, but PR keeps the work and does it
|
|
seanhalle@260
|
464 * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion,
|
|
seanhalle@260
|
465 * but it would be complicated by having to track cores separately)
|
|
seanhalle@260
|
466 *
|
|
seanhalle@260
|
467 *Choosing 2, to keep compatibility with single-lang mode.. it allows the same
|
|
seanhalle@260
|
468 * assigner to be used for single-lang as for multi-lang.. the overhead of
|
|
seanhalle@260
|
469 * the extra master search for work is part of the price of the flexibility,
|
|
seanhalle@260
|
470 * but should be fairly small.. takes the first env that has work available,
|
|
seanhalle@260
|
471 * and whatever it returns is assigned to the slot..
|
|
seanhalle@260
|
472 *
|
|
seanhalle@260
|
473 *As a hybrid, giving an option for a unified override assigner to be registered
|
|
seanhalle@260
|
474 * and used.. This allows something like a static analysis to detect
|
|
seanhalle@260
|
475 * which languages are grouped together, and then analyze the pattern of
|
|
seanhalle@260
|
476 * construct calls, and generate a custom assigner that uses info from all
|
|
seanhalle@260
|
477 * the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@260
|
478 * but making it possible.
|
|
seanhalle@260
|
479 */
|
|
seanhalle@260
|
480 #ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
481 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@260
|
482 {
|
|
seanhalle@260
|
483 //Used while scanning and filling animation slots
|
|
seanhalle@260
|
484 int32 slotIdx, numSlotsFilled;
|
|
seanhalle@260
|
485 AnimSlot *currSlot, **animSlots;
|
|
seanhalle@260
|
486 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
|
|
seanhalle@260
|
487
|
|
seanhalle@260
|
488 //Local copies, for performance
|
|
seanhalle@260
|
489 MasterEnv *masterEnv;
|
|
seanhalle@260
|
490 SlaveAssigner slaveAssigner;
|
|
seanhalle@260
|
491 RequestHandler requestHandler;
|
|
seanhalle@260
|
492 PRSemEnv *semanticEnv;
|
|
seanhalle@260
|
493 int32 thisCoresIdx;
|
|
seanhalle@260
|
494
|
|
seanhalle@260
|
495 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
496 SlaveVP *slave;
|
|
seanhalle@260
|
497 PRProcess *process;
|
|
seanhalle@260
|
498 int32 langMagicNumber;
|
|
seanhalle@260
|
499 //#endif
|
|
seanhalle@260
|
500
|
|
seanhalle@260
|
501 //======================== Initializations ========================
|
|
seanhalle@261
|
502 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@260
|
503
|
|
seanhalle@260
|
504 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@260
|
505 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@260
|
506
|
|
seanhalle@260
|
507 requestHandler = masterEnv->requestHandler;
|
|
seanhalle@260
|
508 slaveAssigner = masterEnv->slaveAssigner;
|
|
seanhalle@260
|
509 semanticEnv = masterEnv->semanticEnv;
|
|
seanhalle@260
|
510
|
|
seanhalle@260
|
511 //initialize, for non-multi-lang, non multi-proc case
|
|
seanhalle@260
|
512 // default handler gets put into master env by a registration call by lang
|
|
seanhalle@260
|
513 endTaskHandler = masterEnv->defaultTaskHandler;
|
|
seanhalle@260
|
514
|
|
seanhalle@260
|
515 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@260
|
516
|
|
seanhalle@260
|
517 //======================== animationMaster ========================
|
|
seanhalle@260
|
518 //Do loop gets requests handled and work assigned to slots..
|
|
seanhalle@260
|
519 // work can either be a task or a resumed slave
|
|
seanhalle@260
|
520 //Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
521 // then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
522 // loops that are inter-twined..
|
|
seanhalle@260
|
523 while(1){
|
|
seanhalle@260
|
524
|
|
seanhalle@260
|
525 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@260
|
526
|
|
seanhalle@260
|
527 //Scan the animation slots
|
|
seanhalle@260
|
528 numSlotsFilled = 0;
|
|
seanhalle@260
|
529 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@260
|
530 {
|
|
seanhalle@260
|
531 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@260
|
532
|
|
seanhalle@260
|
533 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@260
|
534 if( currSlot->workIsDone )
|
|
seanhalle@260
|
535 { currSlot->workIsDone = FALSE;
|
|
seanhalle@260
|
536
|
|
seanhalle@260
|
537 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@260
|
538 MEAS__startReqHdlr;
|
|
seanhalle@260
|
539
|
|
seanhalle@260
|
540
|
|
seanhalle@260
|
541 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@260
|
542 slave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@260
|
543
|
|
seanhalle@260
|
544 //check if the completed work was a task..
|
|
seanhalle@260
|
545 if( slave->taskMetaInfo->isATask )
|
|
seanhalle@260
|
546 {
|
|
seanhalle@260
|
547 if( slave->reqst->type == TaskEnd )
|
|
seanhalle@260
|
548 { //do task end handler, which is registered separately
|
|
seanhalle@260
|
549 //note, end hdlr may use semantic data from reqst..
|
|
seanhalle@260
|
550 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
551 //get end-task handler
|
|
seanhalle@260
|
552 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
|
|
seanhalle@260
|
553 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
|
|
seanhalle@260
|
554 //#endif
|
|
seanhalle@260
|
555 (*taskEndHandler)( slave, semanticEnv );
|
|
seanhalle@260
|
556
|
|
seanhalle@260
|
557 goto AssignWork;
|
|
seanhalle@260
|
558 }
|
|
seanhalle@260
|
559 else //is a task, and just suspended
|
|
seanhalle@260
|
560 { //turn slot slave into free task slave & make replacement
|
|
seanhalle@266
|
561 if( slave->typeOfVP == SlotTaskSlv ) changeSlvType();
|
|
seanhalle@260
|
562
|
|
seanhalle@260
|
563 //goto normal slave request handling
|
|
seanhalle@260
|
564 goto SlaveReqHandling;
|
|
seanhalle@260
|
565 }
|
|
seanhalle@260
|
566 }
|
|
seanhalle@260
|
567 else //is a slave that suspended
|
|
seanhalle@260
|
568 {
|
|
seanhalle@260
|
569 SlaveReqHandling:
|
|
seanhalle@260
|
570 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
|
|
seanhalle@260
|
571
|
|
seanhalle@260
|
572 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@260
|
573 MEAS__endReqHdlr;
|
|
seanhalle@260
|
574
|
|
seanhalle@260
|
575 goto AssignWork;
|
|
seanhalle@260
|
576 }
|
|
seanhalle@260
|
577 } //if has suspended slave that needs handling
|
|
seanhalle@260
|
578
|
|
seanhalle@260
|
579 //if slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@267
|
580 if( currSlot->needsWorkAssigned )
|
|
seanhalle@260
|
581 { //Call plugin's Assigner to give slot a new slave
|
|
seanhalle@260
|
582 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@260
|
583
|
|
seanhalle@260
|
584 AssignWork:
|
|
seanhalle@260
|
585
|
|
seanhalle@260
|
586 assignedSlaveVP = assignWork( semanticEnv, currSlot );
|
|
seanhalle@260
|
587
|
|
seanhalle@260
|
588 //put the chosen slave into slot, and adjust flags and state
|
|
seanhalle@260
|
589 if( assignedSlaveVP != NULL )
|
|
seanhalle@260
|
590 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@260
|
591 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@267
|
592 currSlot->needsWorkAssigned = FALSE;
|
|
seanhalle@260
|
593 numSlotsFilled += 1;
|
|
seanhalle@260
|
594 }
|
|
seanhalle@260
|
595 else
|
|
seanhalle@260
|
596 {
|
|
seanhalle@267
|
597 currSlot->needsWorkAssigned = TRUE; //local write
|
|
seanhalle@260
|
598 }
|
|
seanhalle@260
|
599 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@260
|
600 }//if slot needs slave assigned
|
|
seanhalle@260
|
601 }//for( slotIdx..
|
|
seanhalle@260
|
602
|
|
seanhalle@260
|
603 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@260
|
604
|
|
seanhalle@260
|
605 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@260
|
606 flushRegisters();
|
|
seanhalle@260
|
607 }//while(1)
|
|
seanhalle@260
|
608 }
|
|
seanhalle@260
|
609 #endif //MODE__MULTI_LANG
|
|
seanhalle@260
|
610
|
|
seanhalle@260
|
611
|
|
seanhalle@260
|
612
|
|
seanhalle@260
|
613 //This is the master when both multi-lang and multi-process modes are turned on
|
|
seanhalle@260
|
614 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
615 //#ifdef MODE__MULTI_PROCESS
|
|
seanhalle@260
|
616 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@260
|
617 {
|
|
seanhalle@261
|
618 int32 slotIdx;
|
|
seanhalle@261
|
619 AnimSlot *currSlot;
|
|
seanhalle@260
|
620 //Used while scanning and filling animation slots
|
|
seanhalle@261
|
621 AnimSlot **animSlots;
|
|
seanhalle@260
|
622
|
|
seanhalle@260
|
623 //Local copies, for performance
|
|
seanhalle@260
|
624 MasterEnv *masterEnv;
|
|
seanhalle@260
|
625 int32 thisCoresIdx;
|
|
seanhalle@260
|
626
|
|
seanhalle@260
|
627 //======================== Initializations ========================
|
|
seanhalle@261
|
628 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@260
|
629
|
|
seanhalle@260
|
630 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@260
|
631 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@261
|
632
|
|
seanhalle@260
|
633 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@260
|
634
|
|
seanhalle@260
|
635 //======================== animationMaster ========================
|
|
seanhalle@260
|
636 //Do loop gets requests handled and work assigned to slots..
|
|
seanhalle@260
|
637 // work can either be a task or a resumed slave
|
|
seanhalle@260
|
638 //Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
639 // then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
640 // loops that are inter-twined..
|
|
seanhalle@261
|
641 while(1)
|
|
seanhalle@261
|
642 {
|
|
seanhalle@261
|
643 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@261
|
644
|
|
seanhalle@261
|
645 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@261
|
646 {
|
|
seanhalle@261
|
647 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@260
|
648
|
|
seanhalle@261
|
649 masterFunction_multiLang( currSlot );
|
|
seanhalle@261
|
650 }
|
|
seanhalle@261
|
651
|
|
seanhalle@261
|
652 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@261
|
653
|
|
seanhalle@261
|
654 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@261
|
655 flushRegisters();
|
|
seanhalle@261
|
656 }
|
|
seanhalle@261
|
657 }
|
|
seanhalle@261
|
658 #endif //MODE__MULTI_LANG
|
|
seanhalle@261
|
659 #endif //MODE__MULTI_PROCESS
|
|
seanhalle@261
|
660
|
|
seanhalle@267
|
661
|
|
seanhalle@267
|
662 //This version of the master selects one of three loops, depending upon
|
|
seanhalle@267
|
663 // whether stand-alone single language (just slaves), or standalone with
|
|
seanhalle@267
|
664 // tasks, or multi-lang (implies multi-process)
|
|
seanhalle@267
|
665 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@267
|
666 {
|
|
seanhalle@267
|
667 int32 slotIdx;
|
|
seanhalle@267
|
668 AnimSlot *currSlot;
|
|
seanhalle@267
|
669 //Used while scanning and filling animation slots
|
|
seanhalle@267
|
670 AnimSlot **animSlots;
|
|
seanhalle@267
|
671
|
|
seanhalle@267
|
672 //Local copies, for performance
|
|
seanhalle@267
|
673 MasterEnv *masterEnv;
|
|
seanhalle@267
|
674 int32 thisCoresIdx;
|
|
seanhalle@267
|
675
|
|
seanhalle@267
|
676 //======================== Initializations ========================
|
|
seanhalle@267
|
677 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@267
|
678
|
|
seanhalle@267
|
679 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@267
|
680 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@267
|
681
|
|
seanhalle@267
|
682 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@267
|
683
|
|
seanhalle@267
|
684 //======================== animationMaster ========================
|
|
seanhalle@267
|
685 //Have three different modes, and the master behavior is different for
|
|
seanhalle@267
|
686 // each, so jump to the loop that corresponds to the mode.
|
|
seanhalle@267
|
687 //
|
|
seanhalle@267
|
688 switch(mode)
|
|
seanhalle@267
|
689 { case StandaloneSlavesOnly:
|
|
seanhalle@267
|
690 while(1)
|
|
seanhalle@267
|
691 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@267
|
692 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@267
|
693 {
|
|
seanhalle@267
|
694 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@267
|
695
|
|
seanhalle@267
|
696 masterFunction_StandaloneSlavesOnly( currSlot );
|
|
seanhalle@267
|
697 }
|
|
seanhalle@267
|
698 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@267
|
699 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@267
|
700 flushRegisters();
|
|
seanhalle@267
|
701 }
|
|
seanhalle@267
|
702 case StandaloneWTasks:
|
|
seanhalle@267
|
703 while(1)
|
|
seanhalle@267
|
704 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@267
|
705 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@267
|
706 {
|
|
seanhalle@267
|
707 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@267
|
708
|
|
seanhalle@267
|
709 masterFunction_StandaloneWTasks( currSlot );
|
|
seanhalle@267
|
710 }
|
|
seanhalle@267
|
711 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@267
|
712 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@267
|
713 flushRegisters();
|
|
seanhalle@267
|
714 }
|
|
seanhalle@267
|
715 case MultiLang:
|
|
seanhalle@267
|
716 while(1)
|
|
seanhalle@267
|
717 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@267
|
718 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@267
|
719 {
|
|
seanhalle@267
|
720 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@267
|
721
|
|
seanhalle@267
|
722 masterFunction_multiLang( currSlot );
|
|
seanhalle@267
|
723 }
|
|
seanhalle@267
|
724 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@267
|
725 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@267
|
726 flushRegisters();
|
|
seanhalle@267
|
727 }
|
|
seanhalle@267
|
728 }
|
|
seanhalle@267
|
729 }
|
|
seanhalle@267
|
730
|
|
seanhalle@267
|
731
|
|
seanhalle@261
|
732 inline
|
|
seanhalle@261
|
733 void
|
|
seanhalle@261
|
734 masterFunction_multiLang( AnimSlot *currSlot )
|
|
seanhalle@261
|
735 { //Scan the animation slots
|
|
seanhalle@261
|
736 int32 magicNumber;
|
|
seanhalle@261
|
737 SlaveVP *slave;
|
|
seanhalle@261
|
738 SlaveVP *assignedSlaveVP;
|
|
seanhalle@261
|
739 PRSemEnv *semanticEnv;
|
|
seanhalle@261
|
740 PRReqst *req;
|
|
seanhalle@261
|
741 RequestHandler requestHandler;
|
|
seanhalle@260
|
742
|
|
seanhalle@260
|
743 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@260
|
744 if( currSlot->workIsDone )
|
|
seanhalle@260
|
745 { currSlot->workIsDone = FALSE;
|
|
seanhalle@267
|
746 currSlot->needsWorkAssigned = TRUE;
|
|
seanhalle@260
|
747
|
|
seanhalle@260
|
748 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@260
|
749 MEAS__startReqHdlr;
|
|
seanhalle@260
|
750
|
|
seanhalle@260
|
751
|
|
seanhalle@260
|
752 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@260
|
753 slave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@267
|
754 req = slave->request;
|
|
seanhalle@261
|
755
|
|
seanhalle@267
|
756 //If the requesting slave is a slot slave, and request is not
|
|
seanhalle@267
|
757 // task-end, then turn it into a free task slave.
|
|
seanhalle@267
|
758 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
|
|
seanhalle@267
|
759 replaceWithNewSlotSlv( slave );
|
|
seanhalle@261
|
760
|
|
seanhalle@267
|
761 //Handle task create and end first -- they're special cases..
|
|
seanhalle@267
|
762 switch( req->reqType )
|
|
seanhalle@267
|
763 { case TaskEnd:
|
|
seanhalle@267
|
764 { //do PR handler, which calls lang's hdlr and does recycle of
|
|
seanhalle@267
|
765 // free task slave if needed -- PR handler checks for free task Slv
|
|
seanhalle@267
|
766 PRHandle_EndTask( slave ); break;
|
|
seanhalle@267
|
767 }
|
|
seanhalle@267
|
768 case TaskCreate:
|
|
seanhalle@267
|
769 { //Do PR's create-task handler, which calls the lang's hdlr
|
|
seanhalle@267
|
770 // PR handler checks for free task Slv
|
|
seanhalle@267
|
771 PRHandle_CreateTask( slave ); break;
|
|
seanhalle@267
|
772 }
|
|
seanhalle@267
|
773 case SlvCreate: PRHandle_CreateSlave( slave ); break;
|
|
seanhalle@267
|
774 case SlvDissipate: PRHandle_Dissipate( slave ); break;
|
|
seanhalle@267
|
775 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own semantic env
|
|
seanhalle@267
|
776 case Hardware: //for future expansion
|
|
seanhalle@267
|
777 case IO: //for future expansion
|
|
seanhalle@267
|
778 case OSCall: //for future expansion
|
|
seanhalle@267
|
779 PR_int__throw_exception("Not implemented"); break;
|
|
seanhalle@267
|
780 case Language: //normal sem request
|
|
seanhalle@267
|
781 magicNumber = req->langMagicNumber;
|
|
seanhalle@267
|
782 semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber );
|
|
seanhalle@267
|
783 requestHandler = semanticEnv->requestHdlr;
|
|
seanhalle@267
|
784 (*requestHandler)( req->semReq, slave, semanticEnv );
|
|
seanhalle@267
|
785 }
|
|
seanhalle@261
|
786
|
|
seanhalle@267
|
787 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@267
|
788 MEAS__endReqHdlr;
|
|
seanhalle@267
|
789 } //if have request to be handled
|
|
seanhalle@260
|
790
|
|
seanhalle@267
|
791 if( currSlot->needsWorkAssigned )
|
|
seanhalle@267
|
792 {
|
|
seanhalle@267
|
793 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@267
|
794
|
|
seanhalle@261
|
795 //Scan sem environs, looking for semEnv with ready work.
|
|
seanhalle@261
|
796 // call the Assigner for that sem Env, to get a slave for the slot
|
|
seanhalle@260
|
797 assignedSlaveVP = assignWork( semanticEnv, currSlot );
|
|
seanhalle@260
|
798
|
|
seanhalle@267
|
799 //if work found, put into slot, and adjust flags and state
|
|
seanhalle@260
|
800 if( assignedSlaveVP != NULL )
|
|
seanhalle@260
|
801 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@260
|
802 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@267
|
803 currSlot->needsWorkAssigned = FALSE;
|
|
seanhalle@260
|
804 }
|
|
seanhalle@260
|
805 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@260
|
806 }//if slot needs slave assigned
|
|
seanhalle@261
|
807 }
|
|
seanhalle@260
|
808
|
|
seanhalle@261
|
809 //==========================================================================
|
|
seanhalle@261
|
810 /*When a task in a slot slave suspends, the slot slave has to be changed to
|
|
seanhalle@261
|
811 * a free task slave, then the slot slave replaced. The replacement can be
|
|
seanhalle@261
|
812 * either a recycled free task slave that finished it's task and has been
|
|
seanhalle@261
|
813 * idle in the recycle queue, or else create a new slave to be the slot slave.
|
|
seanhalle@261
|
814 *The master only calls this with a slot slave that needs to be replaced.
|
|
seanhalle@261
|
815 */
|
|
seanhalle@261
|
816 inline void
|
|
seanhalle@266
|
817 replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcess *process )
|
|
seanhalle@261
|
818 { SlaveVP *newSlotSlv;
|
|
seanhalle@261
|
819
|
|
seanhalle@267
|
820 When slot slave converted to a free task slave, insert the process pointer -- slot slaves are not assigned to any process;
|
|
seanhalle@267
|
821 when convert from slot slave to free task slave, check what should do about num (live slaves + live tasks) inside VSs's task stub, and properly update process's count of liveFreeTaskSlaves
|
|
seanhalle@267
|
822
|
|
seanhalle@261
|
823 //get a new slave to be the slot slave
|
|
seanhalle@266
|
824 newSlotSlv = readPrivQ( process->freeTaskSlvRecycleQ );
|
|
seanhalle@261
|
825 if( newSlotSlv == NULL )
|
|
seanhalle@266
|
826 { newSlotSlv = PR_int__create_slaveVP( &idle_fn, NULL, process, 0);
|
|
seanhalle@261
|
827 //just made a new free task slave, so count it
|
|
seanhalle@266
|
828 process->numLiveFreeTaskSlvs += 1;
|
|
seanhalle@261
|
829 }
|
|
seanhalle@260
|
830
|
|
seanhalle@261
|
831 //set slave values to make it the slot slave
|
|
seanhalle@261
|
832 newSlotSlv->metaTask = NULL;
|
|
seanhalle@266
|
833 newSlotSlv->typeOfVP = SlotTaskSlv;
|
|
seanhalle@267
|
834 // newSlotSlv->needsTaskAssigned = TRUE;
|
|
seanhalle@261
|
835
|
|
seanhalle@261
|
836 //a slot slave is pinned to a particular slot on a particular core
|
|
seanhalle@261
|
837 //Note, this happens before the request is seen by handler, so nothing
|
|
seanhalle@261
|
838 // has had a chance to change the coreAnimatedBy or anything else..
|
|
seanhalle@261
|
839 newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo;
|
|
seanhalle@261
|
840 newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy;
|
|
seanhalle@261
|
841
|
|
seanhalle@261
|
842 //put it into the slot slave matrix
|
|
seanhalle@261
|
843 int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx;
|
|
seanhalle@261
|
844 int32 coreNum = requestingSlv->coreAnimatedBy;
|
|
seanhalle@266
|
845 process->slotTaskSlvs[coreNum][slotNum] = newSlotSlv;
|
|
seanhalle@261
|
846
|
|
seanhalle@261
|
847 //Fix up requester, to be an extra slave now (but not an ended one)
|
|
seanhalle@261
|
848 // because it's active, doesn't go into freeTaskSlvRecycleQ
|
|
seanhalle@261
|
849 requestingSlv->typeOfVP = FreeTaskSlv;
|
|
seanhalle@267
|
850 requestingSlv->metaTask->taskType = FreeTask;
|
|
seanhalle@260
|
851 }
|
|
seanhalle@260
|
852
|
|
seanhalle@260
|
853
|
|
seanhalle@261
|
854
|
|
seanhalle@261
|
855 /*This does:
|
|
seanhalle@261
|
856 * 1) searches the semantic environments for one with work ready
|
|
seanhalle@261
|
857 * if finds one, asks its assigner to return work
|
|
seanhalle@261
|
858 * 2) checks what kind of work: new task, resuming task, resuming slave
|
|
seanhalle@261
|
859 * if new task, gets the slot slave and assigns task to it and returns slave
|
|
seanhalle@261
|
860 * else, gets the slave attached to the metaTask and returns that.
|
|
seanhalle@261
|
861 * 3) if no work found, then prune former task slaves waiting to be recycled.
|
|
seanhalle@261
|
862 * If no work and no slaves to prune, check for shutdown conditions.
|
|
seanhalle@261
|
863 *
|
|
seanhalle@261
|
864 * Semantic env keeps its own work in its own structures, and has its own
|
|
seanhalle@261
|
865 * assigner. It chooses
|
|
seanhalle@261
|
866 * However, include a switch that switches-in an override assigner, which
|
|
seanhalle@261
|
867 * sees all the work in all the semantic env's. This is most likely
|
|
seanhalle@261
|
868 * generated by static tools and included in the executable. That means it
|
|
seanhalle@261
|
869 * has to be called via a registered pointer from here. The idea is that
|
|
seanhalle@261
|
870 * the static tools know which languages are grouped together.. and the
|
|
seanhalle@261
|
871 * override enables them to generate a custom assigner that uses info from
|
|
seanhalle@261
|
872 * all the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@261
|
873 * but am making it possible.
|
|
seanhalle@260
|
874 */
|
|
seanhalle@260
|
875 inline SlaveVP *
|
|
seanhalle@261
|
876 assignWork( PRProcess *process, AnimSlot *slot )
|
|
seanhalle@261
|
877 { SlaveVP *returnSlv;
|
|
seanhalle@261
|
878 int32 coreNum, slotNum;
|
|
seanhalle@267
|
879 PRMetaTask *assignedMetaTask;
|
|
seanhalle@260
|
880
|
|
seanhalle@261
|
881 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@260
|
882
|
|
seanhalle@267
|
883 if( process->overrideAssigner != NULL )
|
|
seanhalle@267
|
884 { assignedMetaTask = (*process->overrideAssigner)( process, slot );
|
|
seanhalle@261
|
885 if( assignedMetaTask != NULL )
|
|
seanhalle@261
|
886 {
|
|
seanhalle@261
|
887 //have work, so reset Done flag (caused by work generated on other core)
|
|
seanhalle@267
|
888 // if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
|
|
seanhalle@267
|
889 // process->coreIsDone[coreNum] = FALSE; //don't just write always
|
|
seanhalle@261
|
890
|
|
seanhalle@267
|
891 // switch( assignedMetaTask->taskType )
|
|
seanhalle@267
|
892 // { case GenericSlave: goto AssignSlave;
|
|
seanhalle@267
|
893 // case FreeTask: goto AssignSlave;
|
|
seanhalle@267
|
894 // case SlotTask: goto AssignNewTask;
|
|
seanhalle@267
|
895 // default: PR_int__throw_exception( "unknown task type ret by assigner" );
|
|
seanhalle@267
|
896 // }
|
|
seanhalle@267
|
897 //If meta task has a slave attached, then goto assign slave,
|
|
seanhalle@267
|
898 // else it's a new task, so goto where assign it to a slot slave
|
|
seanhalle@267
|
899 if( assignedMetaTask->slaveAssignedTo != NULL )
|
|
seanhalle@267
|
900 goto AssignSlave;
|
|
seanhalle@267
|
901 else
|
|
seanhalle@267
|
902 goto AssignNewTask;
|
|
seanhalle@261
|
903 }
|
|
seanhalle@267
|
904 else //metaTask is NULL, so no work..
|
|
seanhalle@261
|
905 goto NoWork;
|
|
seanhalle@261
|
906 }
|
|
seanhalle@261
|
907
|
|
seanhalle@261
|
908 //If here, then no override assigner, so search semantic envs for work
|
|
seanhalle@261
|
909 int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner;
|
|
seanhalle@261
|
910 semEnvs = process->semEnvs;
|
|
seanhalle@261
|
911 numEnvs = process->numSemEnvs;
|
|
seanhalle@267
|
912 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash & array
|
|
seanhalle@260
|
913 { semEnv = semEnvs[envIdx];
|
|
seanhalle@260
|
914 if( semEnv->hasWork )
|
|
seanhalle@266
|
915 { assigner = semEnv->slaveAssigner;
|
|
seanhalle@261
|
916 assignedMetaTask = (*assigner)( semEnv, slot );
|
|
seanhalle@260
|
917
|
|
seanhalle@261
|
918 //have work, so reset Done flag (caused by work generated on other core)
|
|
seanhalle@267
|
919 // if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
|
|
seanhalle@267
|
920 // process->coreIsDone[coreNum] = FALSE; //don't just write always
|
|
seanhalle@261
|
921
|
|
seanhalle@267
|
922 // switch( assignedMetaTask->taskType )
|
|
seanhalle@267
|
923 // { case GenericSlave: goto AssignSlave;
|
|
seanhalle@267
|
924 // case FreeTask: goto AssignSlave;
|
|
seanhalle@267
|
925 // case SlotTask: goto AssignNewTask;
|
|
seanhalle@267
|
926 // default: PR_int__throw_exception( "unknown task type ret by assigner" );
|
|
seanhalle@267
|
927 // }
|
|
seanhalle@267
|
928 //If meta task has a slave attached, then goto assign slave,
|
|
seanhalle@267
|
929 // else it's a new task, so goto where assign it to a slot slave
|
|
seanhalle@267
|
930 if( assignedMetaTask->slaveAssignedTo != NULL )
|
|
seanhalle@267
|
931 goto AssignSlave;
|
|
seanhalle@267
|
932 else
|
|
seanhalle@267
|
933 goto AssignNewTask;
|
|
seanhalle@260
|
934 }
|
|
seanhalle@260
|
935 }
|
|
seanhalle@267
|
936 //If reach here, then have searched all semEnv's & none have work..
|
|
seanhalle@260
|
937
|
|
seanhalle@261
|
938 NoWork:
|
|
seanhalle@261
|
939 //No work, if reach here..
|
|
seanhalle@266
|
940 { goto ReturnTheSlv;
|
|
seanhalle@261
|
941 }
|
|
seanhalle@266
|
942
|
|
seanhalle@267
|
943 AssignSlave: //Have a metaTask attached to a slave, so get the slave & ret it
|
|
seanhalle@267
|
944 { returnSlv = assignedMetaTask->slaveAssignedTo;
|
|
seanhalle@261
|
945 returnSlv->coreAnimatedBy = coreNum;
|
|
seanhalle@260
|
946
|
|
seanhalle@260
|
947 goto ReturnTheSlv;
|
|
seanhalle@260
|
948 }
|
|
seanhalle@261
|
949
|
|
seanhalle@267
|
950 AssignNewTask: //Have a new metaTask that has no slave yet.. assign to slot slv
|
|
seanhalle@260
|
951 {
|
|
seanhalle@260
|
952 //get the slot slave to assign the task to..
|
|
seanhalle@261
|
953 slotNum = slot->slotIdx;
|
|
seanhalle@261
|
954 returnSlv = process->slotTaskSlvs[coreNum][slotNum];
|
|
seanhalle@260
|
955
|
|
seanhalle@267
|
956 //point slave to task's function
|
|
seanhalle@260
|
957 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv,
|
|
seanhalle@261
|
958 assignedMetaTask->topLevelFn, assignedMetaTask->initData );
|
|
seanhalle@267
|
959 returnSlv->metaTask = assignedMetaTask;
|
|
seanhalle@261
|
960 assignedMetaTask->slaveAssignedTo = returnSlv;
|
|
seanhalle@267
|
961 // returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type
|
|
seanhalle@260
|
962
|
|
seanhalle@260
|
963 //have work, so reset Done flag, if was set
|
|
seanhalle@267
|
964 // if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
|
|
seanhalle@267
|
965 // process->coreIsDone[coreNum] = FALSE; //don't just write always
|
|
seanhalle@260
|
966
|
|
seanhalle@260
|
967 goto ReturnTheSlv;
|
|
seanhalle@260
|
968 }
|
|
seanhalle@260
|
969
|
|
seanhalle@260
|
970
|
|
seanhalle@260
|
971 ReturnTheSlv: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@260
|
972
|
|
seanhalle@260
|
973 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@260
|
974 if( returnSlv == NULL )
|
|
seanhalle@261
|
975 { returnSlv = process->idleSlv[coreNum][slotNum];
|
|
seanhalle@260
|
976
|
|
seanhalle@260
|
977 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@260
|
978 // never go there
|
|
seanhalle@261
|
979 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@260
|
980 Unit newU;
|
|
seanhalle@260
|
981 newU.vp = returnSlv->slaveID;
|
|
seanhalle@261
|
982 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
983 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@260
|
984
|
|
seanhalle@261
|
985 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@260
|
986 { Dependency newD; // to this one
|
|
seanhalle@260
|
987 newD.from_vp = returnSlv->slaveID;
|
|
seanhalle@261
|
988 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@260
|
989 newD.to_vp = returnSlv->slaveID;
|
|
seanhalle@261
|
990 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
991 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@260
|
992 }
|
|
seanhalle@260
|
993 }
|
|
seanhalle@260
|
994 else //have a slave will be assigned to the slot
|
|
seanhalle@260
|
995 { //assignSlv->numTimesAssigned++;
|
|
seanhalle@260
|
996 //get previous occupant of the slot
|
|
seanhalle@260
|
997 Unit prev_in_slot =
|
|
seanhalle@261
|
998 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
|
|
seanhalle@260
|
999 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency
|
|
seanhalle@260
|
1000 { Dependency newD; // is a hardware dependency
|
|
seanhalle@260
|
1001 newD.from_vp = prev_in_slot.vp;
|
|
seanhalle@260
|
1002 newD.from_task = prev_in_slot.task;
|
|
seanhalle@260
|
1003 newD.to_vp = returnSlv->slaveID;
|
|
seanhalle@261
|
1004 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
1005 addToListOfArrays(Dependency,newD,process->hwArcs);
|
|
seanhalle@260
|
1006 }
|
|
seanhalle@260
|
1007 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous
|
|
seanhalle@261
|
1008 prev_in_slot.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
1009 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
|
|
seanhalle@260
|
1010 prev_in_slot;
|
|
seanhalle@260
|
1011 }
|
|
seanhalle@260
|
1012 #endif
|
|
seanhalle@260
|
1013
|
|
seanhalle@260
|
1014 return( returnSlv );
|
|
seanhalle@260
|
1015 }
|
|
seanhalle@260
|
1016
|
|
seanhalle@260
|
1017
|
|
seanhalle@261
|
1018 /*In creator, only PR related things happen, and things in the langlet whose
|
|
seanhalle@261
|
1019 * creator construct was used.
|
|
seanhalle@261
|
1020 *Other langlet still gets a chance to create semData -- but by registering a
|
|
seanhalle@261
|
1021 * "createSemData" handler in the semEnv. When a construct of the langlet
|
|
seanhalle@261
|
1022 * calls "PR__give_sem_data()", if there is no semData for that langlet,
|
|
seanhalle@261
|
1023 * the PR will call the creator in the langlet's semEnv, place whatever it
|
|
seanhalle@261
|
1024 * makes as the semData in that slave for that langlet, and return that semData
|
|
seanhalle@261
|
1025 *
|
|
seanhalle@261
|
1026 *So, as far as counting things, a langlet is only allowed to count creation
|
|
seanhalle@261
|
1027 * of slaves it creates itself.. may have to change this later.. add a way for
|
|
seanhalle@261
|
1028 * langlet to register a trigger Fn called each time a slave gets created..
|
|
seanhalle@261
|
1029 * need more experience with what langlets will do at create time.. think Cilk
|
|
seanhalle@261
|
1030 * has interesting create behavior.. not sure how that will differ in light
|
|
seanhalle@261
|
1031 * of true tasks and langlet approach. Look at it after all done and start
|
|
seanhalle@261
|
1032 * modifying the langs to be langlets..
|
|
seanhalle@261
|
1033 *
|
|
seanhalle@261
|
1034 *PR itself needs to create the slave, then update numLiveSlaves in process,
|
|
seanhalle@261
|
1035 * copy processID from requestor to newly created
|
|
seanhalle@261
|
1036 */
|
|
seanhalle@261
|
1037 PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@261
|
1038 { SlaveVP *newSlv;
|
|
seanhalle@261
|
1039 PRMetaTask metaTask;
|
|
seanhalle@261
|
1040 PRProcess *process;
|
|
seanhalle@261
|
1041
|
|
seanhalle@261
|
1042 process = requestingSlv->processSlaveIsIn;
|
|
seanhalle@261
|
1043 newSlv = PR_int__create_slaveVP();
|
|
seanhalle@261
|
1044 newSlv->typeOfVP = GenericSlv;
|
|
seanhalle@261
|
1045 newSlv->processSlaveIsIn = process;
|
|
seanhalle@266
|
1046 process->numLiveGenericSlvs += 1;
|
|
seanhalle@261
|
1047 metaTask = PR_int__create_slave_meta_task();
|
|
seanhalle@261
|
1048 metaTask->taskID = req->ID;
|
|
seanhalle@267
|
1049 // metaTask->taskType = GenericSlave;
|
|
seanhalle@260
|
1050
|
|
seanhalle@267
|
1051 (*req->handler)( req->semReq, newSlv, requestingSlv, semEnv );
|
|
seanhalle@260
|
1052 }
|
|
seanhalle@260
|
1053
|
|
seanhalle@267
|
1054 /*The dissipate handler has to, sdate the number of slaves of the type, within
|
|
seanhalle@261
|
1055 * the process, and call the langlet handler linked into the request,
|
|
seanhalle@261
|
1056 * and after that returns, then call the PR function that frees the slave state
|
|
seanhalle@261
|
1057 * (or recycles the slave).
|
|
seanhalle@261
|
1058 *
|
|
seanhalle@261
|
1059 *The PR function that frees the slave state has to also free all of the
|
|
seanhalle@261
|
1060 * semData in the slave.. or else reset all of the semDatas.. by, say, marking
|
|
seanhalle@261
|
1061 * them, then in PR__give_semData( magicNum ) call the langlet registered
|
|
seanhalle@261
|
1062 * "resetSemData" Fn.
|
|
seanhalle@261
|
1063 */
|
|
seanhalle@261
|
1064 PRHandle_Dissipate( SlaveVP *slave )
|
|
seanhalle@261
|
1065 { PRProcess *process;
|
|
seanhalle@261
|
1066 void *semEnv;
|
|
seanhalle@261
|
1067
|
|
seanhalle@261
|
1068 process = slave->processSlaveIsIn;
|
|
seanhalle@261
|
1069
|
|
seanhalle@261
|
1070 //do the language's dissipate handler
|
|
seanhalle@267
|
1071 semEnv = PR_int__give_sem_env_for_slave( slave, slave->request->langMagicNumber );
|
|
seanhalle@267
|
1072 (*slave->request->handler)( slave->request->semReq, slave, semEnv );
|
|
seanhalle@261
|
1073
|
|
seanhalle@266
|
1074 process->numLiveGenericSlvs -= 1;
|
|
seanhalle@267
|
1075 PR_int__recycle_slave_multilang( requestingSlv );
|
|
seanhalle@267
|
1076
|
|
seanhalle@261
|
1077 //check End Of Process Condition
|
|
seanhalle@261
|
1078 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
1079 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@267
|
1080 PR_SS__shutdown_process( process );
|
|
seanhalle@261
|
1081 }
|
|
seanhalle@261
|
1082
|
|
seanhalle@261
|
1083 /*Create task is a special form, that has PR behavior in addition to plugin
|
|
seanhalle@267
|
1084 * behavior. Master calls this first, and then calls the plugin's
|
|
seanhalle@261
|
1085 * create task handler.
|
|
seanhalle@267
|
1086 *
|
|
seanhalle@267
|
1087 *Note: the requesting slave must be either generic slave or free task slave
|
|
seanhalle@261
|
1088 */
|
|
seanhalle@267
|
1089 inline PRMetaTask *
|
|
seanhalle@267
|
1090 PRHandle_CreateTask( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@267
|
1091 { PRMetaTask *metaTask;
|
|
seanhalle@267
|
1092 PRProcess *process;
|
|
seanhalle@261
|
1093 PRLangMetaTask *langMetaTask;
|
|
seanhalle@267
|
1094 PRSemEnv *semanticEnv;
|
|
seanhalle@267
|
1095
|
|
seanhalle@261
|
1096 process = requestingSlv->processSlaveIsIn;
|
|
seanhalle@261
|
1097
|
|
seanhalle@267
|
1098 metaTask = PR_int__create_meta_task( req );
|
|
seanhalle@267
|
1099 metaTask->taskID = req->ID; //may be NULL
|
|
seanhalle@267
|
1100 metaTask->topLevelFn = req->topLevelFn;
|
|
seanhalle@267
|
1101 metaTask->initData = req->initData;
|
|
seanhalle@261
|
1102
|
|
seanhalle@261
|
1103 process->numLiveTasks += 1;
|
|
seanhalle@267
|
1104
|
|
seanhalle@267
|
1105 semanticEnv = PR_int__give_sem_env_for_slave( slave,
|
|
seanhalle@267
|
1106 req->langMagicNumber );
|
|
seanhalle@267
|
1107
|
|
seanhalle@267
|
1108 //Do the langlet's create-task handler, which keeps the task
|
|
seanhalle@267
|
1109 // inside the langlet's sem env, but returns the langMetaTask
|
|
seanhalle@267
|
1110 // so PR can hook it to the PRMetaTask.
|
|
seanhalle@267
|
1111 //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size
|
|
seanhalle@267
|
1112 // of the lang's metaTask, and alloc's that plus the prolog and returns
|
|
seanhalle@267
|
1113 // ptr to position just above the prolog)
|
|
seanhalle@267
|
1114 langMetaTask = (*req->handler)(req->semReq, slave, semanticEnv);
|
|
seanhalle@261
|
1115 metaTask->langMetaTask = langMetaTask;
|
|
seanhalle@261
|
1116 langMetaTask->protoMetaTask = metaTask;
|
|
seanhalle@267
|
1117
|
|
seanhalle@261
|
1118 return;
|
|
seanhalle@261
|
1119 }
|
|
seanhalle@261
|
1120
|
|
seanhalle@261
|
1121 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
|
|
seanhalle@261
|
1122 * suspended at some point in its code.
|
|
seanhalle@261
|
1123 *For 1, just decr count of live tasks (and check for end condition) -- the
|
|
seanhalle@261
|
1124 * master loop will decide what goes into the slot freed up by this task end,
|
|
seanhalle@261
|
1125 * so, here, don't worry about assigning a new task to the slot slave.
|
|
seanhalle@261
|
1126 *For 2, the task's slot slave has been converted to a free task slave, which
|
|
seanhalle@261
|
1127 * now has nothing more to do, so send it to the recycle Q (which includes
|
|
seanhalle@261
|
1128 * freeing all the semData and meta task structs alloc'd for it). Then
|
|
seanhalle@261
|
1129 * decrement the live task count and check end condition.
|
|
seanhalle@261
|
1130 *
|
|
seanhalle@261
|
1131 *PR has to update count of live tasks, and check end of process condition.
|
|
seanhalle@267
|
1132 * The "main" can invoke constructs that wait for a process to end, so when
|
|
seanhalle@267
|
1133 * end detected, have to resume what's waiting..
|
|
seanhalle@267
|
1134 *Thing is, that wait involves the main OS thread. That means
|
|
seanhalle@261
|
1135 * PR internals have to do OS thread signaling. Want to do that in the
|
|
seanhalle@267
|
1136 * core controller, which has the original stack of an OS thread. So the
|
|
seanhalle@267
|
1137 * end process handling happens in the core controller.
|
|
seanhalle@261
|
1138 *
|
|
seanhalle@261
|
1139 *So here, when detect process end, signal to the core controller, which will
|
|
seanhalle@267
|
1140 * then do the condition variable notify to the OS thread that's waiting.
|
|
seanhalle@267
|
1141 *
|
|
seanhalle@267
|
1142 *Note: slave may be either a slot slave or a free task slave.
|
|
seanhalle@261
|
1143 */
|
|
seanhalle@261
|
1144 inline void
|
|
seanhalle@261
|
1145 PRHandle_EndTask( SlaveVP *requestingSlv )
|
|
seanhalle@267
|
1146 { void *semEnv;
|
|
seanhalle@267
|
1147 PRReqst *req;
|
|
seanhalle@267
|
1148 PRLangMetaTask *langMetaTask;
|
|
seanhalle@261
|
1149 PRProcess *process;
|
|
seanhalle@267
|
1150
|
|
seanhalle@261
|
1151 req = requestingSlv->request;
|
|
seanhalle@267
|
1152 semEnv = PR_int__give_sem_env_of_req( req, requestingSlv ); //magic num in req
|
|
seanhalle@267
|
1153 langMetaTask = requestingSlv->metaTask->langMetaTask;
|
|
seanhalle@261
|
1154
|
|
seanhalle@267
|
1155 //Do the langlet's request handler
|
|
seanhalle@267
|
1156 //Want to keep PR structs hidden from plugin, so extract semReq..
|
|
seanhalle@267
|
1157 (*req->handler)( langMetaTask, req->semReq, semEnv );
|
|
seanhalle@267
|
1158
|
|
seanhalle@267
|
1159 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
|
|
seanhalle@267
|
1160 if( requestingSlv->typeOfVP == FreeTaskSlv )
|
|
seanhalle@267
|
1161 PR_int__recycle_slave_multilang( requestingSlv );
|
|
seanhalle@261
|
1162
|
|
seanhalle@261
|
1163 process->numLiveTasks -= 1;
|
|
seanhalle@261
|
1164
|
|
seanhalle@261
|
1165 //check End Of Process Condition
|
|
seanhalle@261
|
1166 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
1167 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@267
|
1168 //Tell the core controller to do wakeup of any waiting OS thread
|
|
seanhalle@267
|
1169 PR_SS__shutdown_process( process );
|
|
seanhalle@261
|
1170 }
|
|
seanhalle@261
|
1171
|