| 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@261
|
16 replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv );
|
|
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@230
|
192 currSlot->needsSlaveAssigned = 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@260
|
198 currSlot->needsSlaveAssigned = 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@230
|
226 if( currSlot->needsSlaveAssigned )
|
|
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@230
|
236 currSlot->needsSlaveAssigned = 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 PRConstrEnvHolder *constrEnvHolder;
|
|
seanhalle@260
|
274 int32 langMagicNumber;
|
|
seanhalle@260
|
275 //#endif
|
|
seanhalle@260
|
276
|
|
seanhalle@260
|
277 //======================== Initializations ========================
|
|
seanhalle@261
|
278 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@260
|
279
|
|
seanhalle@260
|
280 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@260
|
281 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@260
|
282
|
|
seanhalle@260
|
283 requestHandler = masterEnv->requestHandler;
|
|
seanhalle@260
|
284 slaveAssigner = masterEnv->slaveAssigner;
|
|
seanhalle@260
|
285 semanticEnv = masterEnv->semanticEnv;
|
|
seanhalle@260
|
286
|
|
seanhalle@260
|
287 //initialize, for non-multi-lang, non multi-proc case
|
|
seanhalle@260
|
288 // default handler gets put into master env by a registration call by lang
|
|
seanhalle@260
|
289 endTaskHandler = masterEnv->defaultTaskHandler;
|
|
seanhalle@260
|
290
|
|
seanhalle@260
|
291 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@260
|
292
|
|
seanhalle@260
|
293 //======================== animationMaster ========================
|
|
seanhalle@260
|
294 //Do loop gets requests handled and work assigned to slots..
|
|
seanhalle@260
|
295 // work can either be a task or a resumed slave
|
|
seanhalle@260
|
296 //Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
297 // then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
298 // loops that are inter-twined..
|
|
seanhalle@260
|
299 while(1){
|
|
seanhalle@260
|
300
|
|
seanhalle@260
|
301 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@260
|
302
|
|
seanhalle@260
|
303 //Scan the animation slots
|
|
seanhalle@260
|
304 numSlotsFilled = 0;
|
|
seanhalle@260
|
305 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@260
|
306 {
|
|
seanhalle@260
|
307 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@260
|
308
|
|
seanhalle@260
|
309 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@260
|
310 if( currSlot->workIsDone )
|
|
seanhalle@260
|
311 { currSlot->workIsDone = FALSE;
|
|
seanhalle@260
|
312
|
|
seanhalle@260
|
313 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@260
|
314 MEAS__startReqHdlr;
|
|
seanhalle@260
|
315
|
|
seanhalle@260
|
316
|
|
seanhalle@260
|
317 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@260
|
318 slave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@260
|
319
|
|
seanhalle@260
|
320 //check if the completed work was a task..
|
|
seanhalle@260
|
321 if( slave->taskMetaInfo->isATask )
|
|
seanhalle@260
|
322 {
|
|
seanhalle@260
|
323 if( slave->reqst->type == TaskEnd )
|
|
seanhalle@260
|
324 { //do task end handler, which is registered separately
|
|
seanhalle@260
|
325 //note, end hdlr may use semantic data from reqst..
|
|
seanhalle@260
|
326 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
327 //get end-task handler
|
|
seanhalle@260
|
328 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
|
|
seanhalle@260
|
329 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
|
|
seanhalle@260
|
330 //#endif
|
|
seanhalle@260
|
331 (*taskEndHandler)( slave, semanticEnv );
|
|
seanhalle@260
|
332
|
|
seanhalle@260
|
333 goto AssignWork;
|
|
seanhalle@260
|
334 }
|
|
seanhalle@260
|
335 else //is a task, and just suspended
|
|
seanhalle@260
|
336 { //turn slot slave into free task slave & make replacement
|
|
seanhalle@266
|
337 if( slave->typeOfVP == SlotTaskSlv ) changeSlvType();
|
|
seanhalle@260
|
338
|
|
seanhalle@260
|
339 //goto normal slave request handling
|
|
seanhalle@260
|
340 goto SlaveReqHandling;
|
|
seanhalle@260
|
341 }
|
|
seanhalle@260
|
342 }
|
|
seanhalle@260
|
343 else //is a slave that suspended
|
|
seanhalle@260
|
344 {
|
|
seanhalle@260
|
345 SlaveReqHandling:
|
|
seanhalle@260
|
346 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
|
|
seanhalle@260
|
347
|
|
seanhalle@260
|
348 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@260
|
349 MEAS__endReqHdlr;
|
|
seanhalle@260
|
350
|
|
seanhalle@260
|
351 goto AssignWork;
|
|
seanhalle@260
|
352 }
|
|
seanhalle@260
|
353 } //if has suspended slave that needs handling
|
|
seanhalle@260
|
354
|
|
seanhalle@260
|
355 //if slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@260
|
356 if( currSlot->needsSlaveAssigned )
|
|
seanhalle@260
|
357 { //Call plugin's Assigner to give slot a new slave
|
|
seanhalle@260
|
358 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@260
|
359
|
|
seanhalle@260
|
360 AssignWork:
|
|
seanhalle@260
|
361
|
|
seanhalle@260
|
362 assignedSlaveVP = assignWork( semanticEnv, currSlot );
|
|
seanhalle@260
|
363
|
|
seanhalle@260
|
364 //put the chosen slave into slot, and adjust flags and state
|
|
seanhalle@260
|
365 if( assignedSlaveVP != NULL )
|
|
seanhalle@260
|
366 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@260
|
367 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@260
|
368 currSlot->needsSlaveAssigned = FALSE;
|
|
seanhalle@260
|
369 numSlotsFilled += 1;
|
|
seanhalle@260
|
370 }
|
|
seanhalle@260
|
371 else
|
|
seanhalle@260
|
372 {
|
|
seanhalle@260
|
373 currSlot->needsSlaveAssigned = TRUE; //local write
|
|
seanhalle@260
|
374 }
|
|
seanhalle@260
|
375 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@260
|
376 }//if slot needs slave assigned
|
|
seanhalle@260
|
377 }//for( slotIdx..
|
|
seanhalle@260
|
378
|
|
seanhalle@260
|
379 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@260
|
380
|
|
seanhalle@260
|
381 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@260
|
382 flushRegisters();
|
|
seanhalle@260
|
383 }//while(1)
|
|
seanhalle@260
|
384 }
|
|
seanhalle@260
|
385
|
|
seanhalle@260
|
386
|
|
seanhalle@260
|
387 /*This is the master when just multi-lang, but not multi-process mode is on.
|
|
seanhalle@260
|
388 * This version has to handle both tasks and slaves, and do extra work of
|
|
seanhalle@260
|
389 * looking up the semantic env and handlers to use, for each completed bit of
|
|
seanhalle@260
|
390 * work.
|
|
seanhalle@260
|
391 *It also has to search through the semantic envs to find one with work,
|
|
seanhalle@260
|
392 * then ask that env's assigner to return a unit of that work.
|
|
seanhalle@260
|
393 *
|
|
seanhalle@260
|
394 *The language is written to startup in the same way as if it were the only
|
|
seanhalle@260
|
395 * language in the app, and it operates in the same way,
|
|
seanhalle@260
|
396 * the only difference between single language and multi-lang is here, in the
|
|
seanhalle@260
|
397 * master.
|
|
seanhalle@260
|
398 *This invisibility to mode is why the language has to use registration calls
|
|
seanhalle@260
|
399 * for everything during startup -- those calls do different things depending
|
|
seanhalle@260
|
400 * on whether it's single-language or multi-language mode.
|
|
seanhalle@260
|
401 *
|
|
seanhalle@260
|
402 *In this version of the master, work can either be a task or a resumed slave
|
|
seanhalle@260
|
403 *Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
404 * then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
405 * loops that are inter-twined..
|
|
seanhalle@260
|
406 *
|
|
seanhalle@260
|
407 *Some special cases:
|
|
seanhalle@260
|
408 * A task-end is a special case for a few reasons (below).
|
|
seanhalle@260
|
409 * A task-end can't block a slave (can't cause it to "logically suspend")
|
|
seanhalle@260
|
410 * A task available for work can only be assigned to a special slave, which
|
|
seanhalle@260
|
411 * has been set aside for doing tasks, one such task-slave is always
|
|
seanhalle@260
|
412 * assigned to each slot. So, when a task ends, a new task is assigned to
|
|
seanhalle@260
|
413 * that slot's task-slave right away.
|
|
seanhalle@260
|
414 * But if no tasks are available, then have to switch over to looking at
|
|
seanhalle@260
|
415 * slaves to find one ready to resume, to find work for the slot.
|
|
seanhalle@260
|
416 * If a task just suspends, not ends, then its task-slave is no longer
|
|
seanhalle@260
|
417 * available to take new tasks, so a new task-slave has to be assigned to
|
|
seanhalle@260
|
418 * that slot. Then the slave of the suspended task is turned into a free
|
|
seanhalle@260
|
419 * task-slave and request handling is done on it as if it were a slave
|
|
seanhalle@260
|
420 * that suspended.
|
|
seanhalle@260
|
421 * After request handling, do the same sequence of looking for a task to be
|
|
seanhalle@260
|
422 * work, and if none, look for a slave ready to resume, as work for the slot.
|
|
seanhalle@260
|
423 * If a slave suspends, handle its request, then look for work.. first for a
|
|
seanhalle@260
|
424 * task to assign, and if none, slaves ready to resume.
|
|
seanhalle@260
|
425 * Another special case is when task-end is done on a free task-slave.. in
|
|
seanhalle@260
|
426 * that case, the slave has no more work and no way to get more.. so place
|
|
seanhalle@260
|
427 * it into a recycle queue.
|
|
seanhalle@260
|
428 * If no work is found of either type, then do a special thing to prune down
|
|
seanhalle@260
|
429 * the extra slaves in the recycle queue, just so don't get too many..
|
|
seanhalle@260
|
430 *
|
|
seanhalle@260
|
431 *The multi-lang thing complicates matters..
|
|
seanhalle@260
|
432 *
|
|
seanhalle@260
|
433 *For request handling, it means have to first fetch the semantic environment
|
|
seanhalle@260
|
434 * of the language, and then do the request handler pointed to by that
|
|
seanhalle@260
|
435 * semantic env.
|
|
seanhalle@260
|
436 *For assigning, things get more complex because of competing goals.. One
|
|
seanhalle@260
|
437 * goal is for language specific stuff to be used during assignment, so
|
|
seanhalle@260
|
438 * assigner can make higher quality decisions.. but with multiple languages,
|
|
seanhalle@260
|
439 * which only get mixed in the application, the assigners can't be written
|
|
seanhalle@260
|
440 * with knowledge of each other. So, they can only make localized decisions,
|
|
seanhalle@260
|
441 * and so different language's assigners may interfere with each other..
|
|
seanhalle@260
|
442 *
|
|
seanhalle@260
|
443 *So, have some possibilities available:
|
|
seanhalle@260
|
444 *1) can have a fixed scheduler in the proto-runtime, that all the
|
|
seanhalle@260
|
445 * languages give their work to.. (but then lose language-specific info,
|
|
seanhalle@260
|
446 * there is a standard PR format for assignment info, and the langauge
|
|
seanhalle@260
|
447 * attaches this to the work-unit when it gives it to PR.. also have issue
|
|
seanhalle@260
|
448 * with HWSim, which uses a priority Q instead of FIFO, and requests can
|
|
seanhalle@260
|
449 * "undo" previous work put in, so request handlers need way to manipulate
|
|
seanhalle@260
|
450 * the work-holding Q..) (this might be fudgeable with
|
|
seanhalle@260
|
451 * HWSim, if the master did a lang-supplied callback each time it assigns a
|
|
seanhalle@260
|
452 * unit to a slot.. then HWSim can keep exactly one unit of work in PR's
|
|
seanhalle@260
|
453 * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies
|
|
seanhalle@260
|
454 * a task-end handler that kicks the next unit of work from HWSim internal
|
|
seanhalle@260
|
455 * priority queue, over to PR readyQ)
|
|
seanhalle@260
|
456 *2) can have each language have its own semantic env, that holds its own
|
|
seanhalle@260
|
457 * work, which is assigned by its own assigner.. then the master searches
|
|
seanhalle@260
|
458 * through all the semantic envs to find one with work and asks it give work..
|
|
seanhalle@260
|
459 * (this has downside of blinding assigners to each other.. but does work
|
|
seanhalle@260
|
460 * for HWSim case)
|
|
seanhalle@260
|
461 *3) could make PR have a different readyQ for each core, and ask the lang
|
|
seanhalle@260
|
462 * to put work to the core it prefers.. but the work may be moved by PR if
|
|
seanhalle@260
|
463 * needed, say if one core idles for too long. This is a hybrid approach,
|
|
seanhalle@260
|
464 * letting the language decide which core, but PR keeps the work and does it
|
|
seanhalle@260
|
465 * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion,
|
|
seanhalle@260
|
466 * but it would be complicated by having to track cores separately)
|
|
seanhalle@260
|
467 *
|
|
seanhalle@260
|
468 *Choosing 2, to keep compatibility with single-lang mode.. it allows the same
|
|
seanhalle@260
|
469 * assigner to be used for single-lang as for multi-lang.. the overhead of
|
|
seanhalle@260
|
470 * the extra master search for work is part of the price of the flexibility,
|
|
seanhalle@260
|
471 * but should be fairly small.. takes the first env that has work available,
|
|
seanhalle@260
|
472 * and whatever it returns is assigned to the slot..
|
|
seanhalle@260
|
473 *
|
|
seanhalle@260
|
474 *As a hybrid, giving an option for a unified override assigner to be registered
|
|
seanhalle@260
|
475 * and used.. This allows something like a static analysis to detect
|
|
seanhalle@260
|
476 * which languages are grouped together, and then analyze the pattern of
|
|
seanhalle@260
|
477 * construct calls, and generate a custom assigner that uses info from all
|
|
seanhalle@260
|
478 * the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@260
|
479 * but making it possible.
|
|
seanhalle@260
|
480 */
|
|
seanhalle@260
|
481 #ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
482 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@260
|
483 {
|
|
seanhalle@260
|
484 //Used while scanning and filling animation slots
|
|
seanhalle@260
|
485 int32 slotIdx, numSlotsFilled;
|
|
seanhalle@260
|
486 AnimSlot *currSlot, **animSlots;
|
|
seanhalle@260
|
487 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
|
|
seanhalle@260
|
488
|
|
seanhalle@260
|
489 //Local copies, for performance
|
|
seanhalle@260
|
490 MasterEnv *masterEnv;
|
|
seanhalle@260
|
491 SlaveAssigner slaveAssigner;
|
|
seanhalle@260
|
492 RequestHandler requestHandler;
|
|
seanhalle@260
|
493 PRSemEnv *semanticEnv;
|
|
seanhalle@260
|
494 int32 thisCoresIdx;
|
|
seanhalle@260
|
495
|
|
seanhalle@260
|
496 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
497 SlaveVP *slave;
|
|
seanhalle@260
|
498 PRProcess *process;
|
|
seanhalle@260
|
499 PRConstrEnvHolder *constrEnvHolder;
|
|
seanhalle@260
|
500 int32 langMagicNumber;
|
|
seanhalle@260
|
501 //#endif
|
|
seanhalle@260
|
502
|
|
seanhalle@260
|
503 //======================== Initializations ========================
|
|
seanhalle@261
|
504 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@260
|
505
|
|
seanhalle@260
|
506 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@260
|
507 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@260
|
508
|
|
seanhalle@260
|
509 requestHandler = masterEnv->requestHandler;
|
|
seanhalle@260
|
510 slaveAssigner = masterEnv->slaveAssigner;
|
|
seanhalle@260
|
511 semanticEnv = masterEnv->semanticEnv;
|
|
seanhalle@260
|
512
|
|
seanhalle@260
|
513 //initialize, for non-multi-lang, non multi-proc case
|
|
seanhalle@260
|
514 // default handler gets put into master env by a registration call by lang
|
|
seanhalle@260
|
515 endTaskHandler = masterEnv->defaultTaskHandler;
|
|
seanhalle@260
|
516
|
|
seanhalle@260
|
517 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@260
|
518
|
|
seanhalle@260
|
519 //======================== animationMaster ========================
|
|
seanhalle@260
|
520 //Do loop gets requests handled and work assigned to slots..
|
|
seanhalle@260
|
521 // work can either be a task or a resumed slave
|
|
seanhalle@260
|
522 //Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
523 // then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
524 // loops that are inter-twined..
|
|
seanhalle@260
|
525 while(1){
|
|
seanhalle@260
|
526
|
|
seanhalle@260
|
527 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@260
|
528
|
|
seanhalle@260
|
529 //Scan the animation slots
|
|
seanhalle@260
|
530 numSlotsFilled = 0;
|
|
seanhalle@260
|
531 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@260
|
532 {
|
|
seanhalle@260
|
533 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@260
|
534
|
|
seanhalle@260
|
535 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@260
|
536 if( currSlot->workIsDone )
|
|
seanhalle@260
|
537 { currSlot->workIsDone = FALSE;
|
|
seanhalle@260
|
538
|
|
seanhalle@260
|
539 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@260
|
540 MEAS__startReqHdlr;
|
|
seanhalle@260
|
541
|
|
seanhalle@260
|
542
|
|
seanhalle@260
|
543 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@260
|
544 slave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@260
|
545
|
|
seanhalle@260
|
546 //check if the completed work was a task..
|
|
seanhalle@260
|
547 if( slave->taskMetaInfo->isATask )
|
|
seanhalle@260
|
548 {
|
|
seanhalle@260
|
549 if( slave->reqst->type == TaskEnd )
|
|
seanhalle@260
|
550 { //do task end handler, which is registered separately
|
|
seanhalle@260
|
551 //note, end hdlr may use semantic data from reqst..
|
|
seanhalle@260
|
552 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
553 //get end-task handler
|
|
seanhalle@260
|
554 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
|
|
seanhalle@260
|
555 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
|
|
seanhalle@260
|
556 //#endif
|
|
seanhalle@260
|
557 (*taskEndHandler)( slave, semanticEnv );
|
|
seanhalle@260
|
558
|
|
seanhalle@260
|
559 goto AssignWork;
|
|
seanhalle@260
|
560 }
|
|
seanhalle@260
|
561 else //is a task, and just suspended
|
|
seanhalle@260
|
562 { //turn slot slave into free task slave & make replacement
|
|
seanhalle@266
|
563 if( slave->typeOfVP == SlotTaskSlv ) changeSlvType();
|
|
seanhalle@260
|
564
|
|
seanhalle@260
|
565 //goto normal slave request handling
|
|
seanhalle@260
|
566 goto SlaveReqHandling;
|
|
seanhalle@260
|
567 }
|
|
seanhalle@260
|
568 }
|
|
seanhalle@260
|
569 else //is a slave that suspended
|
|
seanhalle@260
|
570 {
|
|
seanhalle@260
|
571 SlaveReqHandling:
|
|
seanhalle@260
|
572 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
|
|
seanhalle@260
|
573
|
|
seanhalle@260
|
574 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@260
|
575 MEAS__endReqHdlr;
|
|
seanhalle@260
|
576
|
|
seanhalle@260
|
577 goto AssignWork;
|
|
seanhalle@260
|
578 }
|
|
seanhalle@260
|
579 } //if has suspended slave that needs handling
|
|
seanhalle@260
|
580
|
|
seanhalle@260
|
581 //if slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@260
|
582 if( currSlot->needsSlaveAssigned )
|
|
seanhalle@260
|
583 { //Call plugin's Assigner to give slot a new slave
|
|
seanhalle@260
|
584 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@260
|
585
|
|
seanhalle@260
|
586 AssignWork:
|
|
seanhalle@260
|
587
|
|
seanhalle@260
|
588 assignedSlaveVP = assignWork( semanticEnv, currSlot );
|
|
seanhalle@260
|
589
|
|
seanhalle@260
|
590 //put the chosen slave into slot, and adjust flags and state
|
|
seanhalle@260
|
591 if( assignedSlaveVP != NULL )
|
|
seanhalle@260
|
592 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@260
|
593 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@260
|
594 currSlot->needsSlaveAssigned = FALSE;
|
|
seanhalle@260
|
595 numSlotsFilled += 1;
|
|
seanhalle@260
|
596 }
|
|
seanhalle@260
|
597 else
|
|
seanhalle@260
|
598 {
|
|
seanhalle@260
|
599 currSlot->needsSlaveAssigned = TRUE; //local write
|
|
seanhalle@260
|
600 }
|
|
seanhalle@260
|
601 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@260
|
602 }//if slot needs slave assigned
|
|
seanhalle@260
|
603 }//for( slotIdx..
|
|
seanhalle@260
|
604
|
|
seanhalle@260
|
605 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@260
|
606
|
|
seanhalle@260
|
607 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@260
|
608 flushRegisters();
|
|
seanhalle@260
|
609 }//while(1)
|
|
seanhalle@260
|
610 }
|
|
seanhalle@260
|
611 #endif //MODE__MULTI_LANG
|
|
seanhalle@260
|
612
|
|
seanhalle@260
|
613
|
|
seanhalle@260
|
614
|
|
seanhalle@260
|
615 //This is the master when both multi-lang and multi-process modes are turned on
|
|
seanhalle@260
|
616 //#ifdef MODE__MULTI_LANG
|
|
seanhalle@260
|
617 //#ifdef MODE__MULTI_PROCESS
|
|
seanhalle@260
|
618 void animationMaster( void *initData, SlaveVP *masterVP )
|
|
seanhalle@260
|
619 {
|
|
seanhalle@261
|
620 int32 slotIdx;
|
|
seanhalle@261
|
621 // int32 numSlotsFilled;
|
|
seanhalle@261
|
622 AnimSlot *currSlot;
|
|
seanhalle@260
|
623 //Used while scanning and filling animation slots
|
|
seanhalle@261
|
624 AnimSlot **animSlots;
|
|
seanhalle@260
|
625
|
|
seanhalle@260
|
626 //Local copies, for performance
|
|
seanhalle@260
|
627 MasterEnv *masterEnv;
|
|
seanhalle@260
|
628 int32 thisCoresIdx;
|
|
seanhalle@260
|
629
|
|
seanhalle@260
|
630 //======================== Initializations ========================
|
|
seanhalle@261
|
631 masterEnv = (MasterEnv*)_PRTopEnv;
|
|
seanhalle@260
|
632
|
|
seanhalle@260
|
633 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@260
|
634 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@261
|
635
|
|
seanhalle@260
|
636 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@260
|
637
|
|
seanhalle@260
|
638 //======================== animationMaster ========================
|
|
seanhalle@260
|
639 //Do loop gets requests handled and work assigned to slots..
|
|
seanhalle@260
|
640 // work can either be a task or a resumed slave
|
|
seanhalle@260
|
641 //Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
642 // then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
643 // loops that are inter-twined..
|
|
seanhalle@261
|
644 while(1)
|
|
seanhalle@261
|
645 {
|
|
seanhalle@261
|
646 MEAS__Capture_Pre_Master_Point
|
|
seanhalle@261
|
647
|
|
seanhalle@261
|
648 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@261
|
649 {
|
|
seanhalle@261
|
650 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@260
|
651
|
|
seanhalle@261
|
652 masterFunction_multiLang( currSlot );
|
|
seanhalle@261
|
653 }
|
|
seanhalle@261
|
654
|
|
seanhalle@261
|
655 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@261
|
656
|
|
seanhalle@261
|
657 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@261
|
658 flushRegisters();
|
|
seanhalle@261
|
659 }
|
|
seanhalle@261
|
660 }
|
|
seanhalle@261
|
661 #endif //MODE__MULTI_LANG
|
|
seanhalle@261
|
662 #endif //MODE__MULTI_PROCESS
|
|
seanhalle@261
|
663
|
|
seanhalle@261
|
664 inline
|
|
seanhalle@261
|
665 void
|
|
seanhalle@261
|
666 masterFunction_multiLang( AnimSlot *currSlot )
|
|
seanhalle@261
|
667 { //Scan the animation slots
|
|
seanhalle@261
|
668 int32 magicNumber;
|
|
seanhalle@261
|
669 SlaveVP *slave;
|
|
seanhalle@261
|
670 SlaveVP *assignedSlaveVP;
|
|
seanhalle@261
|
671 PRSemEnv *semanticEnv;
|
|
seanhalle@261
|
672 PRReqst *req;
|
|
seanhalle@261
|
673 RequestHandler requestHandler;
|
|
seanhalle@260
|
674
|
|
seanhalle@260
|
675 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@260
|
676 if( currSlot->workIsDone )
|
|
seanhalle@260
|
677 { currSlot->workIsDone = FALSE;
|
|
seanhalle@260
|
678
|
|
seanhalle@260
|
679 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@260
|
680 MEAS__startReqHdlr;
|
|
seanhalle@260
|
681
|
|
seanhalle@260
|
682
|
|
seanhalle@260
|
683 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@260
|
684 slave = currSlot->slaveAssignedToSlot;
|
|
seanhalle@260
|
685
|
|
seanhalle@261
|
686 //check if the slave was doing a task..
|
|
seanhalle@261
|
687 //Action depends on both on the request type, and whether it's on
|
|
seanhalle@261
|
688 // a generic slave vs a suspended task
|
|
seanhalle@261
|
689 if( slave->metaTask->taskType == AtomicTask ||
|
|
seanhalle@261
|
690 slave->metaTask->taskType == SuspendedTask )
|
|
seanhalle@261
|
691 {
|
|
seanhalle@261
|
692 switch( slave->request->reqType )
|
|
seanhalle@261
|
693 { case TaskEnd:
|
|
seanhalle@261
|
694 { PRHandle_EndTask( slave ); //if free task slave, update count, put into recycle Q -- do handler before lang's handler
|
|
seanhalle@261
|
695
|
|
seanhalle@261
|
696 //do task end handler, which is registered separately
|
|
seanhalle@261
|
697 //note, end hdlr may use semantic data from reqst..
|
|
seanhalle@261
|
698 //get end-task handler
|
|
seanhalle@261
|
699
|
|
seanhalle@261
|
700 RequestHandler
|
|
seanhalle@266
|
701 taskEndHandler = slave->request->handler;
|
|
seanhalle@261
|
702 semanticEnv = PR_int__give_sem_env_for_slave( slave,
|
|
seanhalle@261
|
703 slave->request->langMagicNumber );
|
|
seanhalle@261
|
704 (*taskEndHandler)( slave, semanticEnv );
|
|
seanhalle@261
|
705
|
|
seanhalle@261
|
706 goto AssignWork;
|
|
seanhalle@261
|
707 }
|
|
seanhalle@261
|
708 case TaskCreate:
|
|
seanhalle@261
|
709 { PRHandle_CreateTask( slave );
|
|
seanhalle@261
|
710 RequestHandler
|
|
seanhalle@266
|
711 taskCreateHandler = slave->request->handler;
|
|
seanhalle@261
|
712 semanticEnv = PR_int__give_sem_env_for_slave( slave,
|
|
seanhalle@261
|
713 slave->request->langMagicNumber );
|
|
seanhalle@266
|
714 (*taskCreateHandler)( slave, semanticEnv ); //resumes creating slave
|
|
seanhalle@261
|
715 goto AssignWork;
|
|
seanhalle@261
|
716 }
|
|
seanhalle@261
|
717 default:
|
|
seanhalle@261
|
718 { //is a task, and just suspended, so tied to a free task slave
|
|
seanhalle@261
|
719 //First turn slot slave into free task slave & make replacement
|
|
seanhalle@266
|
720 if( slave->typeOfVP == SlotTaskSlv )
|
|
seanhalle@261
|
721 replaceWithNewSlotSlv( slave, slave->processSlaveIsIn->processEnv );
|
|
seanhalle@261
|
722
|
|
seanhalle@261
|
723 //goto normal slave request handling
|
|
seanhalle@261
|
724 goto SlaveReqHandling;
|
|
seanhalle@261
|
725 }
|
|
seanhalle@261
|
726 }
|
|
seanhalle@260
|
727 }
|
|
seanhalle@260
|
728 else //is a slave that suspended
|
|
seanhalle@260
|
729 {
|
|
seanhalle@260
|
730
|
|
seanhalle@260
|
731 SlaveReqHandling:
|
|
seanhalle@261
|
732 //Q: put the switch in inline call, to clean up code?
|
|
seanhalle@261
|
733 req = slave->request;
|
|
seanhalle@261
|
734 switch( req->reqType )
|
|
seanhalle@261
|
735 { case SlvCreate: PRHandle_CreateSlave( slave ); break;
|
|
seanhalle@261
|
736 case SlvDissipate: PRHandle_Dissipate( slave ); break;
|
|
seanhalle@261
|
737 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own semantic env
|
|
seanhalle@261
|
738 case Hardware: //for future expansion
|
|
seanhalle@261
|
739 case IO: //for future expansion
|
|
seanhalle@261
|
740 case OSCall: //for future expansion
|
|
seanhalle@261
|
741 case Language: //normal sem request
|
|
seanhalle@261
|
742 magicNumber = slave->request->langMagicNumber;
|
|
seanhalle@261
|
743 semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber );
|
|
seanhalle@261
|
744 requestHandler = semanticEnv->requestHdlr;
|
|
seanhalle@261
|
745 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
|
|
seanhalle@261
|
746 }
|
|
seanhalle@261
|
747
|
|
seanhalle@260
|
748 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@260
|
749 MEAS__endReqHdlr;
|
|
seanhalle@260
|
750
|
|
seanhalle@260
|
751 goto AssignWork;
|
|
seanhalle@260
|
752 }
|
|
seanhalle@260
|
753 } //if has suspended slave that needs handling
|
|
seanhalle@260
|
754
|
|
seanhalle@261
|
755 //End up here when the slot did not have ended work in it (no req)
|
|
seanhalle@261
|
756 //So, here, if slot empty, look for work to fill the slot
|
|
seanhalle@260
|
757 if( currSlot->needsSlaveAssigned )
|
|
seanhalle@261
|
758 { HOLISTIC__Record_Assigner_start;
|
|
seanhalle@260
|
759
|
|
seanhalle@260
|
760 AssignWork:
|
|
seanhalle@261
|
761 //Scan sem environs, looking for semEnv with ready work.
|
|
seanhalle@261
|
762 // call the Assigner for that sem Env, to get a slave for the slot
|
|
seanhalle@260
|
763 assignedSlaveVP = assignWork( semanticEnv, currSlot );
|
|
seanhalle@260
|
764
|
|
seanhalle@260
|
765 //put the chosen slave into slot, and adjust flags and state
|
|
seanhalle@260
|
766 if( assignedSlaveVP != NULL )
|
|
seanhalle@260
|
767 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
|
|
seanhalle@260
|
768 assignedSlaveVP->animSlotAssignedTo = currSlot;
|
|
seanhalle@260
|
769 currSlot->needsSlaveAssigned = FALSE;
|
|
seanhalle@260
|
770 }
|
|
seanhalle@260
|
771 else
|
|
seanhalle@261
|
772 { currSlot->needsSlaveAssigned = TRUE; //local write
|
|
seanhalle@260
|
773 }
|
|
seanhalle@260
|
774 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@260
|
775 }//if slot needs slave assigned
|
|
seanhalle@261
|
776 }
|
|
seanhalle@260
|
777
|
|
seanhalle@261
|
778 //==========================================================================
|
|
seanhalle@261
|
779 /*When a task in a slot slave suspends, the slot slave has to be changed to
|
|
seanhalle@261
|
780 * a free task slave, then the slot slave replaced. The replacement can be
|
|
seanhalle@261
|
781 * either a recycled free task slave that finished it's task and has been
|
|
seanhalle@261
|
782 * idle in the recycle queue, or else create a new slave to be the slot slave.
|
|
seanhalle@261
|
783 *The master only calls this with a slot slave that needs to be replaced.
|
|
seanhalle@261
|
784 */
|
|
seanhalle@261
|
785 inline void
|
|
seanhalle@266
|
786 replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcess *process )
|
|
seanhalle@261
|
787 { SlaveVP *newSlotSlv;
|
|
seanhalle@261
|
788
|
|
seanhalle@261
|
789 //get a new slave to be the slot slave
|
|
seanhalle@266
|
790 newSlotSlv = readPrivQ( process->freeTaskSlvRecycleQ );
|
|
seanhalle@261
|
791 if( newSlotSlv == NULL )
|
|
seanhalle@266
|
792 { newSlotSlv = PR_int__create_slaveVP( &idle_fn, NULL, process, 0);
|
|
seanhalle@261
|
793 //just made a new free task slave, so count it
|
|
seanhalle@266
|
794 process->numLiveFreeTaskSlvs += 1;
|
|
seanhalle@261
|
795 }
|
|
seanhalle@260
|
796
|
|
seanhalle@261
|
797 //set slave values to make it the slot slave
|
|
seanhalle@261
|
798 newSlotSlv->metaTask = NULL;
|
|
seanhalle@266
|
799 newSlotSlv->typeOfVP = SlotTaskSlv;
|
|
seanhalle@261
|
800 newSlotSlv->needsTaskAssigned = TRUE;
|
|
seanhalle@261
|
801
|
|
seanhalle@261
|
802 //a slot slave is pinned to a particular slot on a particular core
|
|
seanhalle@261
|
803 //Note, this happens before the request is seen by handler, so nothing
|
|
seanhalle@261
|
804 // has had a chance to change the coreAnimatedBy or anything else..
|
|
seanhalle@261
|
805 newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo;
|
|
seanhalle@261
|
806 newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy;
|
|
seanhalle@261
|
807
|
|
seanhalle@261
|
808 //put it into the slot slave matrix
|
|
seanhalle@261
|
809 int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx;
|
|
seanhalle@261
|
810 int32 coreNum = requestingSlv->coreAnimatedBy;
|
|
seanhalle@266
|
811 process->slotTaskSlvs[coreNum][slotNum] = newSlotSlv;
|
|
seanhalle@261
|
812
|
|
seanhalle@261
|
813 //Fix up requester, to be an extra slave now (but not an ended one)
|
|
seanhalle@261
|
814 // because it's active, doesn't go into freeTaskSlvRecycleQ
|
|
seanhalle@261
|
815 requestingSlv->typeOfVP = FreeTaskSlv;
|
|
seanhalle@266
|
816 check_if_need_to_change_metaTask_type_or_something;
|
|
seanhalle@260
|
817 }
|
|
seanhalle@260
|
818
|
|
seanhalle@260
|
819
|
|
seanhalle@261
|
820
|
|
seanhalle@261
|
821 /*This does:
|
|
seanhalle@261
|
822 * 1) searches the semantic environments for one with work ready
|
|
seanhalle@261
|
823 * if finds one, asks its assigner to return work
|
|
seanhalle@261
|
824 * 2) checks what kind of work: new task, resuming task, resuming slave
|
|
seanhalle@261
|
825 * if new task, gets the slot slave and assigns task to it and returns slave
|
|
seanhalle@261
|
826 * else, gets the slave attached to the metaTask and returns that.
|
|
seanhalle@261
|
827 * 3) if no work found, then prune former task slaves waiting to be recycled.
|
|
seanhalle@261
|
828 * If no work and no slaves to prune, check for shutdown conditions.
|
|
seanhalle@261
|
829 *
|
|
seanhalle@261
|
830 * Semantic env keeps its own work in its own structures, and has its own
|
|
seanhalle@261
|
831 * assigner. It chooses
|
|
seanhalle@261
|
832 * However, include a switch that switches-in an override assigner, which
|
|
seanhalle@261
|
833 * sees all the work in all the semantic env's. This is most likely
|
|
seanhalle@261
|
834 * generated by static tools and included in the executable. That means it
|
|
seanhalle@261
|
835 * has to be called via a registered pointer from here. The idea is that
|
|
seanhalle@261
|
836 * the static tools know which languages are grouped together.. and the
|
|
seanhalle@261
|
837 * override enables them to generate a custom assigner that uses info from
|
|
seanhalle@261
|
838 * all the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@261
|
839 * but am making it possible.
|
|
seanhalle@260
|
840 */
|
|
seanhalle@260
|
841 inline SlaveVP *
|
|
seanhalle@261
|
842 assignWork( PRProcess *process, AnimSlot *slot )
|
|
seanhalle@261
|
843 { SlaveVP *returnSlv;
|
|
seanhalle@261
|
844 //VSsSemEnv *semEnv;
|
|
seanhalle@261
|
845 //VSsSemData *semData;
|
|
seanhalle@261
|
846 int32 coreNum, slotNum;
|
|
seanhalle@261
|
847 PRMetaTask *newMetaTask, *assignedMetaTask;
|
|
seanhalle@261
|
848 SlaveVP *freeTaskSlv;
|
|
seanhalle@260
|
849
|
|
seanhalle@261
|
850 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@260
|
851
|
|
seanhalle@261
|
852 if( _PRTopEnv->overrideAssigner != NULL )
|
|
seanhalle@261
|
853 { assignedMetaTask = (*_PRTopEnv->overrideAssigner)( process, slot );
|
|
seanhalle@261
|
854 if( assignedMetaTask != NULL )
|
|
seanhalle@261
|
855 {
|
|
seanhalle@261
|
856 //have work, so reset Done flag (caused by work generated on other core)
|
|
seanhalle@261
|
857 if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
|
|
seanhalle@261
|
858 process->coreIsDone[coreNum] = FALSE; //don't just write always
|
|
seanhalle@261
|
859
|
|
seanhalle@261
|
860 switch( assignedMetaTask->taskType )
|
|
seanhalle@266
|
861 { case GenericSlave: goto AssignSlave;
|
|
seanhalle@266
|
862 case SuspendedTask: goto AssignSlave;
|
|
seanhalle@266
|
863 case AtomicTask: goto AssignNewTask;
|
|
seanhalle@266
|
864 default: PR_int__throw_exception( "unknown task type ret by assigner" );
|
|
seanhalle@261
|
865 }
|
|
seanhalle@261
|
866 }
|
|
seanhalle@261
|
867 else
|
|
seanhalle@261
|
868 goto NoWork;
|
|
seanhalle@261
|
869 }
|
|
seanhalle@261
|
870
|
|
seanhalle@261
|
871 //If here, then no override assigner, so search semantic envs for work
|
|
seanhalle@261
|
872 int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner;
|
|
seanhalle@261
|
873 semEnvs = process->semEnvs;
|
|
seanhalle@261
|
874 numEnvs = process->numSemEnvs;
|
|
seanhalle@261
|
875 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash AND array
|
|
seanhalle@260
|
876 { semEnv = semEnvs[envIdx];
|
|
seanhalle@260
|
877 if( semEnv->hasWork )
|
|
seanhalle@266
|
878 { assigner = semEnv->slaveAssigner;
|
|
seanhalle@261
|
879 assignedMetaTask = (*assigner)( semEnv, slot );
|
|
seanhalle@260
|
880
|
|
seanhalle@261
|
881 //have work, so reset Done flag (caused by work generated on other core)
|
|
seanhalle@261
|
882 if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
|
|
seanhalle@261
|
883 process->coreIsDone[coreNum] = FALSE; //don't just write always
|
|
seanhalle@261
|
884
|
|
seanhalle@261
|
885 switch( assignedMetaTask->taskType )
|
|
seanhalle@266
|
886 { case GenericSlave: goto AssignSlave;
|
|
seanhalle@266
|
887 case SuspendedTask: goto AssignSlave;
|
|
seanhalle@266
|
888 case AtomicTask: goto AssignNewTask;
|
|
seanhalle@266
|
889 default: PR_int__throw_exception( "unknown task type ret by assigner" );
|
|
seanhalle@261
|
890 }
|
|
seanhalle@260
|
891 }
|
|
seanhalle@260
|
892 }
|
|
seanhalle@260
|
893
|
|
seanhalle@261
|
894 NoWork:
|
|
seanhalle@261
|
895 //No work, if reach here..
|
|
seanhalle@266
|
896 { goto ReturnTheSlv;
|
|
seanhalle@261
|
897 }
|
|
seanhalle@266
|
898
|
|
seanhalle@266
|
899 AssignSlave: //Have a metaTask attached to a slave, so get the slave out
|
|
seanhalle@261
|
900 { //get slave pointed to by meta task.
|
|
seanhalle@261
|
901 returnSlv = assignedMetaTask->slaveAssignedTo;
|
|
seanhalle@261
|
902
|
|
seanhalle@261
|
903 returnSlv->coreAnimatedBy = coreNum;
|
|
seanhalle@260
|
904
|
|
seanhalle@260
|
905 goto ReturnTheSlv;
|
|
seanhalle@260
|
906 }
|
|
seanhalle@261
|
907
|
|
seanhalle@261
|
908 AssignNewTask:
|
|
seanhalle@260
|
909 {
|
|
seanhalle@260
|
910 //get the slot slave to assign the task to..
|
|
seanhalle@261
|
911 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@261
|
912 slotNum = slot->slotIdx;
|
|
seanhalle@261
|
913 returnSlv = process->slotTaskSlvs[coreNum][slotNum];
|
|
seanhalle@260
|
914
|
|
seanhalle@260
|
915 //point slave to task's function, and mark slave as having task
|
|
seanhalle@260
|
916 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv,
|
|
seanhalle@261
|
917 assignedMetaTask->topLevelFn, assignedMetaTask->initData );
|
|
seanhalle@261
|
918 returnSlv->metaTask = assignedMetaTask;
|
|
seanhalle@261
|
919 assignedMetaTask->slaveAssignedTo = returnSlv;
|
|
seanhalle@260
|
920 returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type
|
|
seanhalle@260
|
921
|
|
seanhalle@260
|
922 //have work, so reset Done flag, if was set
|
|
seanhalle@261
|
923 if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
|
|
seanhalle@261
|
924 process->coreIsDone[coreNum] = FALSE; //don't just write always
|
|
seanhalle@260
|
925
|
|
seanhalle@260
|
926 goto ReturnTheSlv;
|
|
seanhalle@260
|
927 }
|
|
seanhalle@260
|
928
|
|
seanhalle@260
|
929
|
|
seanhalle@260
|
930 ReturnTheSlv: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@260
|
931
|
|
seanhalle@260
|
932 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@260
|
933 if( returnSlv == NULL )
|
|
seanhalle@261
|
934 { returnSlv = process->idleSlv[coreNum][slotNum];
|
|
seanhalle@260
|
935
|
|
seanhalle@260
|
936 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@260
|
937 // never go there
|
|
seanhalle@261
|
938 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@260
|
939 Unit newU;
|
|
seanhalle@260
|
940 newU.vp = returnSlv->slaveID;
|
|
seanhalle@261
|
941 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
942 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@260
|
943
|
|
seanhalle@261
|
944 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@260
|
945 { Dependency newD; // to this one
|
|
seanhalle@260
|
946 newD.from_vp = returnSlv->slaveID;
|
|
seanhalle@261
|
947 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@260
|
948 newD.to_vp = returnSlv->slaveID;
|
|
seanhalle@261
|
949 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
950 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@260
|
951 }
|
|
seanhalle@260
|
952 }
|
|
seanhalle@260
|
953 else //have a slave will be assigned to the slot
|
|
seanhalle@260
|
954 { //assignSlv->numTimesAssigned++;
|
|
seanhalle@260
|
955 //get previous occupant of the slot
|
|
seanhalle@260
|
956 Unit prev_in_slot =
|
|
seanhalle@261
|
957 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
|
|
seanhalle@260
|
958 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency
|
|
seanhalle@260
|
959 { Dependency newD; // is a hardware dependency
|
|
seanhalle@260
|
960 newD.from_vp = prev_in_slot.vp;
|
|
seanhalle@260
|
961 newD.from_task = prev_in_slot.task;
|
|
seanhalle@260
|
962 newD.to_vp = returnSlv->slaveID;
|
|
seanhalle@261
|
963 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
964 addToListOfArrays(Dependency,newD,process->hwArcs);
|
|
seanhalle@260
|
965 }
|
|
seanhalle@260
|
966 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous
|
|
seanhalle@261
|
967 prev_in_slot.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
968 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
|
|
seanhalle@260
|
969 prev_in_slot;
|
|
seanhalle@260
|
970 }
|
|
seanhalle@260
|
971 #endif
|
|
seanhalle@260
|
972
|
|
seanhalle@260
|
973 return( returnSlv );
|
|
seanhalle@260
|
974 }
|
|
seanhalle@260
|
975
|
|
seanhalle@260
|
976
|
|
seanhalle@261
|
977 /*In creator, only PR related things happen, and things in the langlet whose
|
|
seanhalle@261
|
978 * creator construct was used.
|
|
seanhalle@261
|
979 *Other langlet still gets a chance to create semData -- but by registering a
|
|
seanhalle@261
|
980 * "createSemData" handler in the semEnv. When a construct of the langlet
|
|
seanhalle@261
|
981 * calls "PR__give_sem_data()", if there is no semData for that langlet,
|
|
seanhalle@261
|
982 * the PR will call the creator in the langlet's semEnv, place whatever it
|
|
seanhalle@261
|
983 * makes as the semData in that slave for that langlet, and return that semData
|
|
seanhalle@261
|
984 *
|
|
seanhalle@261
|
985 *So, as far as counting things, a langlet is only allowed to count creation
|
|
seanhalle@261
|
986 * of slaves it creates itself.. may have to change this later.. add a way for
|
|
seanhalle@261
|
987 * langlet to register a trigger Fn called each time a slave gets created..
|
|
seanhalle@261
|
988 * need more experience with what langlets will do at create time.. think Cilk
|
|
seanhalle@261
|
989 * has interesting create behavior.. not sure how that will differ in light
|
|
seanhalle@261
|
990 * of true tasks and langlet approach. Look at it after all done and start
|
|
seanhalle@261
|
991 * modifying the langs to be langlets..
|
|
seanhalle@261
|
992 *
|
|
seanhalle@261
|
993 *PR itself needs to create the slave, then update numLiveSlaves in process,
|
|
seanhalle@261
|
994 * copy processID from requestor to newly created
|
|
seanhalle@261
|
995 */
|
|
seanhalle@261
|
996 PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@261
|
997 { SlaveVP *newSlv;
|
|
seanhalle@261
|
998 PRMetaTask metaTask;
|
|
seanhalle@261
|
999 PRProcess *process;
|
|
seanhalle@261
|
1000
|
|
seanhalle@261
|
1001 process = requestingSlv->processSlaveIsIn;
|
|
seanhalle@261
|
1002 newSlv = PR_int__create_slaveVP();
|
|
seanhalle@261
|
1003 newSlv->typeOfVP = GenericSlv;
|
|
seanhalle@261
|
1004 newSlv->processSlaveIsIn = process;
|
|
seanhalle@266
|
1005 process->numLiveGenericSlvs += 1;
|
|
seanhalle@261
|
1006 metaTask = PR_int__create_slave_meta_task();
|
|
seanhalle@261
|
1007 metaTask->taskID = req->ID;
|
|
seanhalle@261
|
1008 metaTask->taskType = GenericSlave;
|
|
seanhalle@260
|
1009
|
|
seanhalle@261
|
1010 (*req->handler)(newSlv);
|
|
seanhalle@260
|
1011 }
|
|
seanhalle@260
|
1012
|
|
seanhalle@261
|
1013 /*The dissipate handler has to update the number of slaves of the type, within
|
|
seanhalle@261
|
1014 * the process, and call the langlet handler linked into the request,
|
|
seanhalle@261
|
1015 * and after that returns, then call the PR function that frees the slave state
|
|
seanhalle@261
|
1016 * (or recycles the slave).
|
|
seanhalle@261
|
1017 *
|
|
seanhalle@261
|
1018 *The PR function that frees the slave state has to also free all of the
|
|
seanhalle@261
|
1019 * semData in the slave.. or else reset all of the semDatas.. by, say, marking
|
|
seanhalle@261
|
1020 * them, then in PR__give_semData( magicNum ) call the langlet registered
|
|
seanhalle@261
|
1021 * "resetSemData" Fn.
|
|
seanhalle@261
|
1022 */
|
|
seanhalle@261
|
1023 PRHandle_Dissipate( SlaveVP *slave )
|
|
seanhalle@261
|
1024 { PRProcess *process;
|
|
seanhalle@261
|
1025 void *semEnv;
|
|
seanhalle@261
|
1026
|
|
seanhalle@261
|
1027 process = slave->processSlaveIsIn;
|
|
seanhalle@261
|
1028
|
|
seanhalle@261
|
1029 //do the language's dissipate handler
|
|
seanhalle@261
|
1030 semEnv = PR_int__give_sem_env_for( slave, slave->request->langMagicNumber );
|
|
seanhalle@261
|
1031 (*slave->request->handler)( slave, semEnv );
|
|
seanhalle@261
|
1032
|
|
seanhalle@266
|
1033 process->numLiveGenericSlvs -= 1;
|
|
seanhalle@261
|
1034 PR_int__dissipate_slaveVP_multilang( slave ); //recycles and resets semDatas
|
|
seanhalle@261
|
1035
|
|
seanhalle@261
|
1036 //check End Of Process Condition
|
|
seanhalle@261
|
1037 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
1038 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@261
|
1039 signalEndOfProcess;
|
|
seanhalle@261
|
1040 }
|
|
seanhalle@261
|
1041
|
|
seanhalle@261
|
1042 /*Create task is a special form, that has PR behavior in addition to plugin
|
|
seanhalle@261
|
1043 * behavior. Master calls this first, and this in turn calls the plugin's
|
|
seanhalle@261
|
1044 * create task handler.
|
|
seanhalle@261
|
1045 */
|
|
seanhalle@261
|
1046 inline void
|
|
seanhalle@261
|
1047 PRHandle_CreateTask( TopLevelFn topLevelFn, void *initData, PRReqst *req,
|
|
seanhalle@261
|
1048 SlaveVP *requestingSlv )
|
|
seanhalle@261
|
1049 { PRMetaTask *metaTask;
|
|
seanhalle@261
|
1050 PRProcess *process;
|
|
seanhalle@261
|
1051 void *semEnv, _langMetaTask;
|
|
seanhalle@261
|
1052 PRLangMetaTask *langMetaTask;
|
|
seanhalle@261
|
1053
|
|
seanhalle@261
|
1054 process = requestingSlv->processSlaveIsIn;
|
|
seanhalle@261
|
1055
|
|
seanhalle@261
|
1056 metaTask = PR_int__create_meta_task( req );
|
|
seanhalle@261
|
1057 metaTask->taskID = req->ID; //may be NULL
|
|
seanhalle@261
|
1058 metaTask->topLevelFn = topLevelFn;
|
|
seanhalle@261
|
1059 metaTask->initData = initData;
|
|
seanhalle@261
|
1060
|
|
seanhalle@261
|
1061 process->numLiveTasks += 1;
|
|
seanhalle@261
|
1062
|
|
seanhalle@261
|
1063 //plugin tracks tasks ready, and has its own assigner, so task doesn't
|
|
seanhalle@261
|
1064 // come back from lang's handler -- it's consumed and stays in semEnv.
|
|
seanhalle@261
|
1065 //But handler gives back the language-specific meta-task it creates, and
|
|
seanhalle@261
|
1066 // then hook that into the PR meta-task
|
|
seanhalle@261
|
1067 //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size
|
|
seanhalle@261
|
1068 // of the lang's metaTask, and alloc's that plus the prolog and returns
|
|
seanhalle@261
|
1069 // ptr to position just above the prolog)
|
|
seanhalle@261
|
1070 semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req
|
|
seanhalle@261
|
1071 _langMetaTask = (*requestingSlv->request->handler)(req, semEnv);
|
|
seanhalle@261
|
1072 langMetaTask = (PRLangMetaTask *)_langMetaTask;
|
|
seanhalle@261
|
1073 metaTask->langMetaTask = langMetaTask;
|
|
seanhalle@261
|
1074 langMetaTask->protoMetaTask = metaTask;
|
|
seanhalle@261
|
1075
|
|
seanhalle@261
|
1076 return;
|
|
seanhalle@261
|
1077 }
|
|
seanhalle@261
|
1078
|
|
seanhalle@261
|
1079 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
|
|
seanhalle@261
|
1080 * suspended at some point in its code.
|
|
seanhalle@261
|
1081 *For 1, just decr count of live tasks (and check for end condition) -- the
|
|
seanhalle@261
|
1082 * master loop will decide what goes into the slot freed up by this task end,
|
|
seanhalle@261
|
1083 * so, here, don't worry about assigning a new task to the slot slave.
|
|
seanhalle@261
|
1084 *For 2, the task's slot slave has been converted to a free task slave, which
|
|
seanhalle@261
|
1085 * now has nothing more to do, so send it to the recycle Q (which includes
|
|
seanhalle@261
|
1086 * freeing all the semData and meta task structs alloc'd for it). Then
|
|
seanhalle@261
|
1087 * decrement the live task count and check end condition.
|
|
seanhalle@261
|
1088 *
|
|
seanhalle@261
|
1089 *PR has to update count of live tasks, and check end of process condition.
|
|
seanhalle@261
|
1090 * There are constructs that wait for a process to end, so when end detected,
|
|
seanhalle@261
|
1091 * have to resume what's waiting..
|
|
seanhalle@261
|
1092 *Thing is, the wait is used in "main", so it's an OS thread. That means
|
|
seanhalle@261
|
1093 * PR internals have to do OS thread signaling. Want to do that in the
|
|
seanhalle@261
|
1094 * core controller, which has the original stack of an OS thread.
|
|
seanhalle@261
|
1095 *
|
|
seanhalle@261
|
1096 *So here, when detect process end, signal to the core controller, which will
|
|
seanhalle@261
|
1097 * then do the condition variable notify to the OS thread that's waiting.
|
|
seanhalle@261
|
1098 */
|
|
seanhalle@261
|
1099 inline void
|
|
seanhalle@261
|
1100 PRHandle_EndTask( SlaveVP *requestingSlv )
|
|
seanhalle@261
|
1101 { void *semEnv;
|
|
seanhalle@261
|
1102 PRReqst *req;
|
|
seanhalle@261
|
1103 PRMetaTask *metaTask;
|
|
seanhalle@261
|
1104 PRProcess *process;
|
|
seanhalle@261
|
1105
|
|
seanhalle@261
|
1106 req = requestingSlv->request;
|
|
seanhalle@261
|
1107 semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req
|
|
seanhalle@261
|
1108 metaTask = req->metaTask;
|
|
seanhalle@261
|
1109 //Want to keep PRMetaTask hidden from plugin, so extract semReq..
|
|
seanhalle@261
|
1110 (*req->handler)( metaTask, req->semReq, semEnv );
|
|
seanhalle@261
|
1111
|
|
seanhalle@261
|
1112 recycleFreeTaskSlave( requestingSlv );
|
|
seanhalle@261
|
1113
|
|
seanhalle@261
|
1114 process->numLiveTasks -= 1;
|
|
seanhalle@261
|
1115
|
|
seanhalle@261
|
1116 //check End Of Process Condition
|
|
seanhalle@261
|
1117 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
1118 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@261
|
1119 signalEndOfProcessToCoreCtlr;
|
|
seanhalle@261
|
1120 }
|
|
seanhalle@261
|
1121
|
|
seanhalle@261
|
1122 |