Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
view AnimationMaster.c @ 270:292393c6bef1
about to recover probes, so need to commit current state
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Wed, 16 Jan 2013 01:50:26 -0800 |
| parents | e6a68e7ea63f |
| children | bc5030385120 |
line source
1 /*
2 * Copyright 2012 OpenSourceResearchInstitute.org
3 *
4 * Licensed under BSD
5 */
9 #include <stdio.h>
10 #include <stddef.h>
12 #include "PR.h"
13 #include "VSs_impl/VSs.h"
15 /*
16 void PRHandle_CreateTask_SL(SlaveVP *slave);
18 void PRHandle_CreateSlave_SL(SlaveVP *slave);
19 void PRHandle_Dissipate_SL(SlaveVP *slave);
20 void PR_int__handle_PRServiceReq_SL(SlaveVP *slave);
21 */
22 inline void PRHandle_CreateTask( PRReqst *req, SlaveVP *slave );
23 inline void PRHandle_EndTask( PRReqst *req, SlaveVP *slave );
24 inline void PRHandle_CreateSlave(PRReqst *req, SlaveVP *slave );
25 void PRHandle_EndSlave( PRReqst *req, SlaveVP *slave );
28 //inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot );
29 inline PRProcess * pickAProcess( AnimSlot *slot );
30 inline bool32 assignWork( PRProcess *process, AnimSlot *slot );
32 /*The animationMaster embodies most of the animator of the language. The
33 * animator is what emodies the behavior of language constructs.
34 * As such, it is the animationMaster, in combination with the plugin
35 * functions, that make the language constructs do their behavior.
36 *
37 *Within the code, this is the top-level-function of the masterVPs, and
38 * runs when the coreController has no more slave VPs. It's job is to
39 * refill the animation slots with slaves that have work.
40 *
41 *There are multiple versions of the master, each tuned to a specific
42 * combination of modes. This keeps the master simple, with reduced overhead,
43 * when the application is not using the extra complexity.
44 *
45 *As of Sept 2012, the versions available will be:
46 * 1) Single langauge, which only exposes slaves (such as SSR or Vthread)
47 * 2) Single language, which only exposes tasks (such as pure dataflow)
48 * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP)
49 * 4) Multi-language, which always assumes both tasks and slaves
50 * 5) Multi-language and multi-process, which also assumes both tasks and slaves
51 *
52 *
53 *
54 */
56 //This version of the master selects one of three loops, depending upon
57 // whether stand-alone single language (just slaves), or standalone with
58 // tasks, or multi-lang (implies multi-process)
59 void animationMaster( void *_environment, SlaveVP *masterVP )
60 {
61 TopEnv *masterEnv = (TopEnv *)_environment;
62 int32 slotIdx;
63 AnimSlot *currSlot;
64 //Used while scanning and filling animation slots
65 AnimSlot **animSlots;
67 //Local copies, for performance
68 int32 thisCoresIdx;
70 //======================== Initializations ========================
71 thisCoresIdx = masterVP->coreAnimatedBy;
72 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
74 HOLISTIC__Insert_Master_Global_Vars;
76 //======================== animationMaster ========================
77 //Have three different modes, and the master behavior is different for
78 // each, so jump to the loop that corresponds to the mode.
79 //
80 while(1)
81 { MEAS__Capture_Pre_Master_Point
82 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
83 {
84 currSlot = animSlots[ slotIdx ];
86 masterFunction( currSlot );
87 }
88 MEAS__Capture_Post_Master_Point;
89 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
90 flushRegisters();
91 }
92 }
95 inline
96 bool32
97 masterFunction( AnimSlot *slot )
98 { //Scan the animation slots
99 int32 magicNumber;
100 SlaveVP *slave;
101 PRLangEnv *langEnv;
102 PRReqst *req;
103 PRProcess *process;
104 bool32 foundWork;
106 //Check if newly-done slave in slot, which will need request handled
107 if( slot->workIsDone )
108 { slot->workIsDone = FALSE;
109 slot->needsWorkAssigned = TRUE;
111 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
112 MEAS__startReqHdlr;
115 //process the request made by the slave (held inside slave struc)
116 slave = slot->slaveAssignedToSlot;
117 req = slave->request;
119 //If the requesting slave is a slot slave, and request is not
120 // task-end, then turn it into a free task slave.
121 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
122 PR_int__replace_with_new_slot_slv( slave );
124 //Handle task create and end first -- they're special cases..
125 switch( req->reqType )
126 { case TaskEnd:
127 { //do PR handler, which calls lang's hdlr and does recycle of
128 // free task slave if needed -- PR handler checks for free task Slv
129 PRHandle_EndTask( req, slave ); break;
130 }
131 case TaskCreate:
132 { //Do PR's create-task handler, which calls the lang's hdlr
133 // PR handler checks for free task Slv
134 PRHandle_CreateTask( req, slave ); break;
135 }
136 case SlvCreate: PRHandle_CreateSlave( req, slave ); break;
137 case SlvDissipate: PRHandle_EndSlave( req, slave ); break;
138 case Service: PR_int__handle_PRServiceReq( slave ); break; //resumes into Service lang env
139 case Hardware: //for future expansion
140 case IO: //for future expansion
141 case OSCall: //for future expansion
142 PR_int__throw_exception("Not implemented", slave, NULL); break;
143 case Language: //normal lang request
144 { magicNumber = req->langMagicNumber;
145 langEnv = PR_PI__give_lang_env_for( slave, magicNumber );
146 (*req->handler)( req->langReq, slave, langEnv );
147 }
148 }
150 MEAS__endReqHdlr;
151 HOLISTIC__Record_AppResponder_end;
152 } //if have request to be handled
154 if( slot->needsWorkAssigned )
155 {
156 HOLISTIC__Record_Assigner_start;
158 //Pick a process to get this slot
159 process = pickAProcess( slot );
161 //Scan lang environs, looking for langEnv with ready work.
162 // call the Assigner for that lang Env, to get a slave for the slot
163 foundWork =
164 assignWork( process, slot );
166 HOLISTIC__Record_Assigner_end;
167 }//if slot needs slave assigned
169 return foundWork;
170 }
172 /*When several processes exist, use some pattern for picking one to give
173 * the animation slot to.
174 *First, it has to be a process that has work available.
175 *For now, just do a round-robin
176 */
177 inline
178 PRProcess *
179 pickAProcess( AnimSlot *slot )
180 { int32 idx;
181 PRProcess *process;
183 for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++)
184 {
185 process = _PRTopEnv->processes[ idx ];
186 if( process->numEnvsWithWork != 0 )
187 { _PRTopEnv->currProcessIdx = idx;
188 return process;
189 }
190 }
191 for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++)
192 {
193 process = _PRTopEnv->processes[ idx ];
194 if( process->numEnvsWithWork != 0 )
195 { _PRTopEnv->currProcessIdx = idx;
196 return process;
197 }
198 }
199 //none found
200 return NULL;
201 }
203 /*This does:
204 * 1) searches the language environments for one with work ready
205 * if finds one, asks its assigner to return work
206 * 2) checks what kind of work: new task, resuming task, resuming slave
207 * if new task, gets the slot slave and assigns task to it and returns slave
208 * else, gets the slave attached to the metaTask and returns that.
209 * 3) if no work found, then prune former task slaves waiting to be recycled.
210 * If no work and no slaves to prune, check for shutdown conditions.
211 *
212 * language env keeps its own work in its own structures, and has its own
213 * assigner. It chooses
214 * However, include a switch that switches-in an override assigner, which
215 * sees all the work in all the language env's. This is most likely
216 * generated by static tools and included in the executable. That means it
217 * has to be called via a registered pointer from here. The idea is that
218 * the static tools know which languages are grouped together.. and the
219 * override enables them to generate a custom assigner that uses info from
220 * all the languages in a unified way.. Don't really expect this to happen,
221 * but am making it possible.
222 */
223 inline
224 bool32
225 assignWork( PRProcess *process, AnimSlot *slot )
226 { SlaveVP *returnSlv;
227 int32 coreNum, slotNum;
228 PRMetaTask *assignedMetaTask;
230 coreNum = slot->coreSlotIsOn;
232 if( process->overrideAssigner != NULL )
233 { if( process->numEnvsWithWork != 0 )
234 { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot
235 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
236 }
237 else
238 goto NoWork;
239 }
241 //If here, then no override assigner, so search language envs for work
242 int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv;
243 langEnvsList = process->langEnvsList;
244 numEnvs = process->numLangEnvs;
245 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array
246 { langEnv = langEnvsList[envIdx];
247 if( langEnv->hasWork )
248 { (*langEnv->workAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot
249 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
250 //NOTE: bad search alg -- should start where left off, then wrap around
251 }
252 }
253 //If reach here, then have searched all langEnv's & none have work..
255 NoWork: //No work, if end up here..
256 {
257 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
258 returnSlv = process->idleSlv[coreNum][slotNum];
260 //things that would normally happen in resume(), but idle VPs
261 // never go there
262 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
263 Unit newU;
264 newU.vp = returnSlv->slaveNum;
265 newU.task = returnSlv->numTimesAssignedToASlot;
266 addToListOfArrays(Unit,newU,process->unitList);
268 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
269 { Dependency newD; // to this one
270 newD.from_vp = returnSlv->slaveNum;
271 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
272 newD.to_vp = returnSlv->slaveNum;
273 newD.to_task = returnSlv->numTimesAssignedToASlot;
274 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
275 }
276 #endif
277 HOLISTIC__Record_Assigner_end;
278 return FALSE;
279 }
281 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
282 {
283 HOLISTIC__Record_Assigner_end;
284 return TRUE;
285 }
286 }
290 /*This is first thing called when creating a slave.. it hands off to the
291 * langlet's creator, then adds updates of its own..
292 *
293 *There's a question of things like lang data, meta tasks, and such..
294 *In creator, only PR related things happen, and things for the langlet whose
295 * creator construct was used.
296 *
297 *Other langlets still get a chance to create langData -- but by registering a
298 * "createLangData" handler in the langEnv. When a construct of the langlet
299 * calls "PR__give_lang_data()", if there is no langData for that langlet,
300 * the PR will call the creator in the langlet's langEnv, place whatever it
301 * makes as the langData in that slave for that langlet, and return that langData
302 *
303 *So, as far as counting things, a langlet is only allowed to count creation
304 * of slaves it creates itself.. may have to change this later.. add a way for
305 * langlet to register a trigger Fn called each time a slave gets created..
306 * need more experience with what langlets will do at create time.. think Cilk
307 * has interesting create behavior.. not sure how that will differ in light
308 * of true tasks and langlet approach. Look at it after all done and start
309 * modifying the langs to be langlets..
310 *
311 *PR itself needs to create the slave, then update numLiveSlaves in process,
312 * copy processID from requestor to newly created
313 */
314 inline
315 void
316 PRHandle_CreateSlave( PRReqst *req, SlaveVP *slave )
317 { SlaveVP *newSlv;
318 PRProcess *process;
319 PRLangEnv *protoLangEnv;
321 process = slave->processSlaveIsIn;
322 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber );
324 // newSlv = PR_int__create_slave( req->topLevelFn, req->initData );
326 //create slv has diff prototype than standard reqst hdlr
327 newSlv =
328 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv));
330 newSlv->typeOfVP = GenericSlv;
331 newSlv->processSlaveIsIn = process;
332 newSlv->ID = req->ID;
333 process->numLiveGenericSlvs += 1;
334 }
336 /*The dissipate handler has to, update the number of slaves of the type, within
337 * the process, and call the langlet handler linked into the request,
338 * and after that returns, then call the PR function that frees the slave state
339 * (or recycles the slave).
340 *
341 *The PR function that frees the slave state has to also free all of the
342 * langData in the slave.. or else reset all of the langDatas.. by, say, marking
343 * them, then in PR__give_langData( magicNum ) call the langlet registered
344 * "resetLangData" Fn.
345 */
346 inline
347 void
348 PRHandle_EndSlave( PRReqst *req, SlaveVP *slave )
349 { PRProcess *process;
350 PRLangEnv *protoLangEnv;
352 process = slave->processSlaveIsIn;
354 //do the language's dissipate handler
355 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber );
357 if(req->handler != NULL)
358 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
360 process->numLiveGenericSlvs -= 1;
361 PR_int__recycle_slave__ML( slave );
363 //check End Of Process Condition
364 if( process->numLiveTasks == 0 &&
365 process->numLiveGenericSlvs == 0 )
366 PR_SS__shutdown_process__ML( process );
367 }
369 /*Create task is a special form, that has PR behavior in addition to plugin
370 * behavior. Master calls this first, and it then calls the plugin's
371 * create task handler.
372 *
373 *Note: the requesting slave must be either generic slave or free task slave
374 */
375 inline
376 void
377 PRHandle_CreateTask( PRReqst *req, SlaveVP *slave )
378 { PRMetaTask *metaTask;
379 PRProcess *process;
380 PRLangEnv *protoLangEnv;
381 void *task;
383 process = slave->processSlaveIsIn;
385 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave,
386 req->langMagicNumber );
388 //Do the langlet's create-task handler, which keeps the task
389 // inside the langlet's lang env, but returns the langMetaTask
390 // so PR can put stuff into the prolog
391 task =
392 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
393 metaTask = PR_int__give_prolog_of_task( task );
394 metaTask->ID = req->ID; //may be NULL
395 metaTask->topLevelFn = req->topLevelFn;
396 metaTask->initData = req->initData;
398 process->numLiveTasks += 1;
400 return;
401 }
403 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
404 * suspended at some point in its code.
405 *For 1, just decr count of live tasks (and check for end condition) -- the
406 * master loop will decide what goes into the slot freed up by this task end,
407 * so, here, don't worry about assigning a new task to the slot slave.
408 *For 2, the task's slot slave has been converted to a free task slave, which
409 * now has nothing more to do, so send it to the recycle Q (which includes
410 * freeing all the langData and meta task structs alloc'd for it). Then
411 * decrement the live task count and check end condition.
412 *
413 *PR has to update count of live tasks, and check end of process condition.
414 * The "main" can invoke constructs that wait for a process to end, so when
415 * end detected, have to resume what's waiting..
416 *Thing is, that wait involves the main OS thread. That means
417 * PR internals have to do OS thread signaling. Want to do that in the
418 * core controller, which has the original stack of an OS thread. So the
419 * end process handling happens in the core controller.
420 *
421 *So here, when detect process end, signal to the core controller, which will
422 * then do the condition variable notify to the OS thread that's waiting.
423 *
424 *Note: slave may be either a slot slave or a free task slave.
425 */
426 inline
427 void
428 PRHandle_EndTask( PRReqst *req, SlaveVP *requestingSlv )
429 { void *langEnv;
430 PRProcess *process;
431 void *langMetaTask;
433 langEnv = PR_int__give_lang_env_of_req__ML( req, requestingSlv ); //magic num in req
434 langMetaTask = PR_int__give_lang_meta_task_from_slave__ML( requestingSlv, req->langMagicNumber);
436 //Do the langlet's request handler
437 //Want to keep PR structs hidden from plugin, so extract langReq..
438 (*req->handler)( req->langReq, requestingSlv, langEnv );
440 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
441 if( requestingSlv->typeOfVP == FreeTaskSlv )
442 PR_int__recycle_slave__ML( requestingSlv );
444 process->numLiveTasks -= 1;
446 //check End Of Process Condition
447 if( process->numLiveTasks == 0 &&
448 process->numLiveGenericSlvs == 0 )
449 { //Tell the core controller to do wakeup of any waiting OS thread
450 PR_SS__shutdown_process__ML( process );
451 }
452 }
