Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
diff AnimationMaster.c @ 261:dafae55597ce
Getting closer -- added PRServ as built-in langlet (but still just copy)
about to rework a lot of the Master code.. possibly eliminate core controller
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Tue, 23 Oct 2012 23:46:17 -0700 |
| parents | 999f2966a3e5 |
| children | a5fa1e087c7e |
line diff
1.1 --- a/AnimationMaster.c Wed Sep 19 23:12:44 2012 -0700 1.2 +++ b/AnimationMaster.c Tue Oct 23 23:46:17 2012 -0700 1.3 @@ -10,7 +10,10 @@ 1.4 #include <stddef.h> 1.5 1.6 #include "PR.h" 1.7 +#include "VSs_impl/VSs.h" 1.8 1.9 +inline void 1.10 +replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv ); 1.11 1.12 1.13 /*The animationMaster embodies most of the animator of the language. The 1.14 @@ -37,7 +40,7 @@ 1.15 * 1.16 */ 1.17 1.18 - 1.19 + 1.20 //===================== The versions of the Animation Master ================= 1.21 // 1.22 //============================================================================== 1.23 @@ -105,11 +108,11 @@ 1.24 *There is a separate masterVP for each core, but a single semantic 1.25 * environment shared by all cores. Each core also has its own scheduling 1.26 * slots, which are used to communicate slaves between animationMaster and 1.27 - * coreController. There is only one global variable, _PRMasterEnv, which 1.28 + * coreController. There is only one global variable, _PRTopEnv, which 1.29 * holds the semantic env and other things shared by the different 1.30 * masterVPs. The request handler and Assigner are registered with 1.31 * the animationMaster by the language's init function, and a pointer to 1.32 - * each is in the _PRMasterEnv. (There are also some pthread related global 1.33 + * each is in the _PRTopEnv. (There are also some pthread related global 1.34 * vars, but they're only used during init of PR). 1.35 *PR gains control over the cores by essentially "turning off" the OS's 1.36 * scheduler, using pthread pin-to-core commands. 1.37 @@ -122,7 +125,7 @@ 1.38 * based application. 1.39 *The masterVPs share a single system-wide master-lock, so only one 1.40 * masterVP may be animated at a time. 1.41 - *The core controllers access _PRMasterEnv to get the masterVP, and when 1.42 + *The core controllers access _PRTopEnv to get the masterVP, and when 1.43 * they start, the slots are all empty, so they run their associated core's 1.44 * masterVP. The first of those to get the master lock sees the seed slave 1.45 * in the shared semantic environment, so when it runs the Assigner, that 1.46 @@ -160,7 +163,7 @@ 1.47 int32 thisCoresIdx; 1.48 1.49 //======================== Initializations ======================== 1.50 - masterEnv = (MasterEnv*)_VMSMasterEnv; 1.51 + masterEnv = (MasterEnv*)_PRTopEnv; 1.52 1.53 thisCoresIdx = masterVP->coreAnimatedBy; 1.54 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; 1.55 @@ -196,12 +199,12 @@ 1.56 SlaveVP *currSlave = currSlot->slaveAssignedToSlot; 1.57 1.58 justAddedReqHdlrChg(); 1.59 - //handle the request, either by VMS or by the language 1.60 + //handle the request, either by PR or by the language 1.61 if( currSlave->requests->reqType != LangReq ) 1.62 - { //The request is a standard VMS one, not one defined by the 1.63 - // language, so VMS handles it, then queues slave to be assigned 1.64 - handleReqInVMS( currSlave ); 1.65 - writePrivQ( currSlave, VMSReadyQ ); //Q slave to be assigned below 1.66 + { //The request is a standard PR one, not one defined by the 1.67 + // language, so PR handles it, then queues slave to be assigned 1.68 + handleReqInPR( currSlave ); 1.69 + writePrivQ( currSlave, PRReadyQ ); //Q slave to be assigned below 1.70 } 1.71 else 1.72 { MEAS__startReqHdlr; 1.73 @@ -272,7 +275,7 @@ 1.74 //#endif 1.75 1.76 //======================== Initializations ======================== 1.77 - masterEnv = (MasterEnv*)_PRMasterEnv; 1.78 + masterEnv = (MasterEnv*)_PRTopEnv; 1.79 1.80 thisCoresIdx = masterVP->coreAnimatedBy; 1.81 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; 1.82 @@ -498,7 +501,7 @@ 1.83 //#endif 1.84 1.85 //======================== Initializations ======================== 1.86 - masterEnv = (MasterEnv*)_PRMasterEnv; 1.87 + masterEnv = (MasterEnv*)_PRTopEnv; 1.88 1.89 thisCoresIdx = masterVP->coreAnimatedBy; 1.90 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; 1.91 @@ -614,37 +617,22 @@ 1.92 //#ifdef MODE__MULTI_PROCESS 1.93 void animationMaster( void *initData, SlaveVP *masterVP ) 1.94 { 1.95 + int32 slotIdx; 1.96 +// int32 numSlotsFilled; 1.97 + AnimSlot *currSlot; 1.98 //Used while scanning and filling animation slots 1.99 - int32 slotIdx, numSlotsFilled; 1.100 - AnimSlot *currSlot, **animSlots; 1.101 - SlaveVP *assignedSlaveVP; //the slave chosen by the assigner 1.102 + AnimSlot **animSlots; 1.103 1.104 //Local copies, for performance 1.105 MasterEnv *masterEnv; 1.106 - SlaveAssigner slaveAssigner; 1.107 - RequestHandler requestHandler; 1.108 - PRSemEnv *semanticEnv; 1.109 int32 thisCoresIdx; 1.110 - 1.111 - SlaveVP *slave; 1.112 - PRProcess *process; 1.113 - PRConstrEnvHolder *constrEnvHolder; 1.114 - int32 langMagicNumber; 1.115 1.116 //======================== Initializations ======================== 1.117 - masterEnv = (MasterEnv*)_PRMasterEnv; 1.118 + masterEnv = (MasterEnv*)_PRTopEnv; 1.119 1.120 thisCoresIdx = masterVP->coreAnimatedBy; 1.121 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; 1.122 - 1.123 - requestHandler = masterEnv->requestHandler; 1.124 - slaveAssigner = masterEnv->slaveAssigner; 1.125 - semanticEnv = masterEnv->semanticEnv; 1.126 - 1.127 - //initialize, for non-multi-lang, non multi-proc case 1.128 - // default handler gets put into master env by a registration call by lang 1.129 - endTaskHandler = masterEnv->defaultTaskHandler; 1.130 - 1.131 + 1.132 HOLISTIC__Insert_Master_Global_Vars; 1.133 1.134 //======================== animationMaster ======================== 1.135 @@ -653,15 +641,36 @@ 1.136 //Having two cases makes this logic complex.. can be finishing either, and 1.137 // then the next available work may be either.. so really have two distinct 1.138 // loops that are inter-twined.. 1.139 - while(1){ 1.140 - 1.141 - MEAS__Capture_Pre_Master_Point 1.142 + while(1) 1.143 + { 1.144 + MEAS__Capture_Pre_Master_Point 1.145 + 1.146 + for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) 1.147 + { 1.148 + currSlot = animSlots[ slotIdx ]; 1.149 1.150 - //Scan the animation slots 1.151 - numSlotsFilled = 0; 1.152 - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) 1.153 - { 1.154 - currSlot = animSlots[ slotIdx ]; 1.155 + masterFunction_multiLang( currSlot ); 1.156 + } 1.157 + 1.158 + MEAS__Capture_Post_Master_Point; 1.159 + 1.160 + masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master 1.161 + flushRegisters(); 1.162 + } 1.163 + } 1.164 +#endif //MODE__MULTI_LANG 1.165 +#endif //MODE__MULTI_PROCESS 1.166 + 1.167 +inline 1.168 +void 1.169 +masterFunction_multiLang( AnimSlot *currSlot ) 1.170 + { //Scan the animation slots 1.171 + int32 magicNumber; 1.172 + SlaveVP *slave; 1.173 + SlaveVP *assignedSlaveVP; 1.174 + PRSemEnv *semanticEnv; 1.175 + PRReqst *req; 1.176 + RequestHandler requestHandler; 1.177 1.178 //Check if newly-done slave in slot, which will need request handled 1.179 if( currSlot->workIsDone ) 1.180 @@ -674,34 +683,71 @@ 1.181 //process the request made by the slave (held inside slave struc) 1.182 slave = currSlot->slaveAssignedToSlot; 1.183 1.184 - //check if the completed work was a task.. 1.185 - if( slave->taskMetaInfo->isATask ) 1.186 - { 1.187 - if( slave->reqst->type == TaskEnd ) 1.188 - { //do task end handler, which is registered separately 1.189 - //note, end hdlr may use semantic data from reqst.. 1.190 - //get end-task handler 1.191 - //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); 1.192 - taskEndHandler = slave->taskMetaInfo->endTaskHandler; 1.193 - 1.194 - (*taskEndHandler)( slave, semanticEnv ); 1.195 - 1.196 - goto AssignWork; 1.197 - } 1.198 - else //is a task, and just suspended 1.199 - { //turn slot slave into free task slave & make replacement 1.200 - if( slave->typeOfVP == TaskSlotSlv ) changeSlvType(); 1.201 - 1.202 - //goto normal slave request handling 1.203 - goto SlaveReqHandling; 1.204 - } 1.205 + //check if the slave was doing a task.. 1.206 + //Action depends on both on the request type, and whether it's on 1.207 + // a generic slave vs a suspended task 1.208 + if( slave->metaTask->taskType == AtomicTask || 1.209 + slave->metaTask->taskType == SuspendedTask ) 1.210 + { 1.211 + switch( slave->request->reqType ) 1.212 + { case TaskEnd: 1.213 + { PRHandle_EndTask( slave ); //if free task slave, update count, put into recycle Q -- do handler before lang's handler 1.214 + 1.215 + //do task end handler, which is registered separately 1.216 + //note, end hdlr may use semantic data from reqst.. 1.217 + //get end-task handler 1.218 + 1.219 + RequestHandler 1.220 + taskEndHandler = slave->metaTask->reqHandler; 1.221 + semanticEnv = PR_int__give_sem_env_for_slave( slave, 1.222 + slave->request->langMagicNumber ); 1.223 + (*taskEndHandler)( slave, semanticEnv ); 1.224 + 1.225 + goto AssignWork; 1.226 + } 1.227 + case TaskCreate: 1.228 + { PRHandle_CreateTask( slave ); 1.229 + justCopied_check; 1.230 + RequestHandler 1.231 + taskCreateHandler = slave->metaTask->reqHandler; 1.232 + semanticEnv = PR_int__give_sem_env_for_slave( slave, 1.233 + slave->request->langMagicNumber ); 1.234 + (*taskCreateHandler)( slave, semanticEnv ); 1.235 + 1.236 + want_to_resume_creating_slave; 1.237 + goto AssignWork; 1.238 + } 1.239 + default: 1.240 + { //is a task, and just suspended, so tied to a free task slave 1.241 + //First turn slot slave into free task slave & make replacement 1.242 + if( slave->typeOfVP == TaskSlotSlv ) 1.243 + replaceWithNewSlotSlv( slave, slave->processSlaveIsIn->processEnv ); 1.244 + 1.245 + //goto normal slave request handling 1.246 + goto SlaveReqHandling; 1.247 + } 1.248 + } 1.249 } 1.250 else //is a slave that suspended 1.251 { 1.252 1.253 SlaveReqHandling: 1.254 - (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) 1.255 - 1.256 + //Q: put the switch in inline call, to clean up code? 1.257 + req = slave->request; 1.258 + switch( req->reqType ) 1.259 + { case SlvCreate: PRHandle_CreateSlave( slave ); break; 1.260 + case SlvDissipate: PRHandle_Dissipate( slave ); break; 1.261 + case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own semantic env 1.262 + case Hardware: //for future expansion 1.263 + case IO: //for future expansion 1.264 + case OSCall: //for future expansion 1.265 + case Language: //normal sem request 1.266 + magicNumber = slave->request->langMagicNumber; 1.267 + semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber ); 1.268 + requestHandler = semanticEnv->requestHdlr; 1.269 + (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) 1.270 + } 1.271 + 1.272 HOLISTIC__Record_AppResponder_end; 1.273 MEAS__endReqHdlr; 1.274 1.275 @@ -709,14 +755,14 @@ 1.276 } 1.277 } //if has suspended slave that needs handling 1.278 1.279 - //if slot empty, hand to Assigner to fill with a slave 1.280 + //End up here when the slot did not have ended work in it (no req) 1.281 + //So, here, if slot empty, look for work to fill the slot 1.282 if( currSlot->needsSlaveAssigned ) 1.283 - { //Scan sem environs, looking for one with ready work. 1.284 - // call the Assigner for that sem Env, to give slot a new slave 1.285 - HOLISTIC__Record_Assigner_start; 1.286 + { HOLISTIC__Record_Assigner_start; 1.287 1.288 AssignWork: 1.289 - 1.290 + //Scan sem environs, looking for semEnv with ready work. 1.291 + // call the Assigner for that sem Env, to get a slave for the slot 1.292 assignedSlaveVP = assignWork( semanticEnv, currSlot ); 1.293 1.294 //put the chosen slave into slot, and adjust flags and state 1.295 @@ -724,185 +770,245 @@ 1.296 { currSlot->slaveAssignedToSlot = assignedSlaveVP; 1.297 assignedSlaveVP->animSlotAssignedTo = currSlot; 1.298 currSlot->needsSlaveAssigned = FALSE; 1.299 - numSlotsFilled += 1; 1.300 } 1.301 else 1.302 - { 1.303 - currSlot->needsSlaveAssigned = TRUE; //local write 1.304 + { currSlot->needsSlaveAssigned = TRUE; //local write 1.305 } 1.306 HOLISTIC__Record_Assigner_end; 1.307 }//if slot needs slave assigned 1.308 - }//for( slotIdx.. 1.309 + } 1.310 1.311 - MEAS__Capture_Post_Master_Point; 1.312 +//========================================================================== 1.313 +/*When a task in a slot slave suspends, the slot slave has to be changed to 1.314 + * a free task slave, then the slot slave replaced. The replacement can be 1.315 + * either a recycled free task slave that finished it's task and has been 1.316 + * idle in the recycle queue, or else create a new slave to be the slot slave. 1.317 + *The master only calls this with a slot slave that needs to be replaced. 1.318 + */ 1.319 +inline void 1.320 +replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv ) 1.321 + { SlaveVP *newSlotSlv; 1.322 + VSsSemData *semData; 1.323 + 1.324 + fixMe__still_VSs_stuff_in_here; 1.325 + //get a new slave to be the slot slave 1.326 + newSlotSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ ); 1.327 + if( newSlotSlv == NULL ) 1.328 + { newSlotSlv = PR_int__create_slaveVP( &idle_fn, NULL, processEnv, 0); 1.329 + //just made a new free task slave, so count it 1.330 + processEnv->numLiveFreeTaskSlvs += 1; 1.331 + } 1.332 1.333 - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master 1.334 - flushRegisters(); 1.335 - }//while(1) 1.336 + //set slave values to make it the slot slave 1.337 + newSlotSlv->metaTask = NULL; 1.338 + newSlotSlv->typeOfVP = TaskSlotSlv; 1.339 + newSlotSlv->needsTaskAssigned = TRUE; 1.340 + 1.341 + //a slot slave is pinned to a particular slot on a particular core 1.342 + //Note, this happens before the request is seen by handler, so nothing 1.343 + // has had a chance to change the coreAnimatedBy or anything else.. 1.344 + newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo; 1.345 + newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy; 1.346 + 1.347 + //put it into the slot slave matrix 1.348 + int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; 1.349 + int32 coreNum = requestingSlv->coreAnimatedBy; 1.350 + processEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv; 1.351 + 1.352 + //Fix up requester, to be an extra slave now (but not an ended one) 1.353 + // because it's active, doesn't go into freeTaskSlvRecycleQ 1.354 + requestingSlv->typeOfVP = FreeTaskSlv; 1.355 } 1.356 -#endif //MODE__MULTI_LANG 1.357 -#endif //MODE__MULTI_PROCESS 1.358 1.359 1.360 -/*This does three things: 1.361 - * 1) ask for a slave ready to resume 1.362 - * 2) if none, then ask for a task, and assign to the slot slave 1.363 - * 3) if none, then prune former task slaves waiting to be recycled. 1.364 - * 1.365 - //Have two separate assigners in each semantic env, 1.366 - // which keeps its own work in its own structures.. the master, here, 1.367 - // searches through the semantic environs, takes the first that has work 1.368 - // available, and whatever it returns is assigned to the slot.. 1.369 - //However, also have an override assigner.. because static analysis tools know 1.370 - // which languages are grouped together.. and the override enables them to 1.371 - // generate a custom assigner that uses info from all the languages in a 1.372 - // unified way.. Don't really expect this to happen, but making it possible. 1.373 + 1.374 +/*This does: 1.375 + * 1) searches the semantic environments for one with work ready 1.376 + * if finds one, asks its assigner to return work 1.377 + * 2) checks what kind of work: new task, resuming task, resuming slave 1.378 + * if new task, gets the slot slave and assigns task to it and returns slave 1.379 + * else, gets the slave attached to the metaTask and returns that. 1.380 + * 3) if no work found, then prune former task slaves waiting to be recycled. 1.381 + * If no work and no slaves to prune, check for shutdown conditions. 1.382 + * 1.383 + * Semantic env keeps its own work in its own structures, and has its own 1.384 + * assigner. It chooses 1.385 + * However, include a switch that switches-in an override assigner, which 1.386 + * sees all the work in all the semantic env's. This is most likely 1.387 + * generated by static tools and included in the executable. That means it 1.388 + * has to be called via a registered pointer from here. The idea is that 1.389 + * the static tools know which languages are grouped together.. and the 1.390 + * override enables them to generate a custom assigner that uses info from 1.391 + * all the languages in a unified way.. Don't really expect this to happen, 1.392 + * but am making it possible. 1.393 */ 1.394 inline SlaveVP * 1.395 -assignWork( PRProcessEnv *processEnv, AnimSlot *slot ) 1.396 - { SlaveVP *returnSlv; 1.397 - //VSsSemEnv *semEnv; 1.398 - //VSsSemData *semData; 1.399 - int32 coreNum, slotNum; 1.400 - PRTaskMetaInfo *newTaskStub; 1.401 - SlaveVP *freeTaskSlv; 1.402 +assignWork( PRProcess *process, AnimSlot *slot ) 1.403 + { SlaveVP *returnSlv; 1.404 + //VSsSemEnv *semEnv; 1.405 + //VSsSemData *semData; 1.406 + int32 coreNum, slotNum; 1.407 + PRMetaTask *newMetaTask, *assignedMetaTask; 1.408 + SlaveVP *freeTaskSlv; 1.409 1.410 + coreNum = slot->coreSlotIsOn; 1.411 1.412 - //master has to handle slot slaves.. so either assigner returns 1.413 - // taskMetaInfo or else two assigners, one for slaves, other for tasks.. 1.414 - semEnvs = processEnv->semEnvs; 1.415 - numEnvs = processEnv->numSemEnvs; 1.416 - for( envIdx = 0; envIdx < numEnvs; envIdx++ ) 1.417 + if( _PRTopEnv->overrideAssigner != NULL ) 1.418 + { assignedMetaTask = (*_PRTopEnv->overrideAssigner)( process, slot ); 1.419 + if( assignedMetaTask != NULL ) 1.420 + { 1.421 + //have work, so reset Done flag (caused by work generated on other core) 1.422 + if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf 1.423 + process->coreIsDone[coreNum] = FALSE; //don't just write always 1.424 + 1.425 + switch( assignedMetaTask->taskType ) 1.426 + { case GenericSlave: goto AssignSlave; 1.427 + case ResumedTask: goto AssignSlave; 1.428 + case NewTask: goto AssignNewTask; 1.429 + case default: PR_int__throw_exception( "unknown task type ret by assigner" ); 1.430 + } 1.431 + } 1.432 + else 1.433 + goto NoWork; 1.434 + } 1.435 + 1.436 + //If here, then no override assigner, so search semantic envs for work 1.437 + int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner; 1.438 + semEnvs = process->semEnvs; 1.439 + numEnvs = process->numSemEnvs; 1.440 + for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash AND array 1.441 { semEnv = semEnvs[envIdx]; 1.442 if( semEnv->hasWork ) 1.443 { assigner = semEnv->assigner; 1.444 - retTaskMetaInfo = (*assigner)( semEnv, slot ); 1.445 + assignedMetaTask = (*assigner)( semEnv, slot ); 1.446 1.447 - return retTaskMetaInfo; //quit, have work 1.448 + //have work, so reset Done flag (caused by work generated on other core) 1.449 + if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf 1.450 + process->coreIsDone[coreNum] = FALSE; //don't just write always 1.451 + 1.452 + switch( assignedMetaTask->taskType ) 1.453 + { case GenericSlave: goto AssignSlave; 1.454 + case ResumedTask: goto AssignSlave; 1.455 + case NewTask: goto AssignNewTask; 1.456 + case default: PR_int__throw_exception( "unknown task type ret by assigner" ); 1.457 + } 1.458 } 1.459 } 1.460 1.461 - coreNum = slot->coreSlotIsOn; 1.462 - slotNum = slot->slotIdx; 1.463 - 1.464 - //first try to get a ready slave 1.465 - returnSlv = getReadySlave(); 1.466 + NoWork: 1.467 + //No work, if reach here.. 1.468 + //no task, so prune the recycle pool of free task slaves 1.469 + freeTaskSlv = readPrivQ( process->freeTaskSlvRecycleQ ); 1.470 + if( freeTaskSlv != NULL ) 1.471 + { //delete, so that bound the num extras, and deliver shutdown cond 1.472 + deleteExtraneousFreeTaskSlv( freeTaskSlv, process ); 1.473 + //then return NULL 1.474 + returnSlv = NULL; 1.475 + 1.476 + goto ReturnTheSlv; 1.477 + } 1.478 + else 1.479 + { //candidate for shutdown.. all extras dissipated, and no tasks 1.480 + // and no ready to resume slaves, so no way to generate 1.481 + // more work (on this core -- other core might have work still) 1.482 + if( process->numLiveFreeTaskSlvs == 0 && 1.483 + process->numLiveGenericSlvs == 0 ) 1.484 + { //This core sees no way to generate more tasks, so say it 1.485 + if( process->coreIsDone[coreNum] == FALSE ) 1.486 + { process->numCoresDone += 1; 1.487 + process->coreIsDone[coreNum] = TRUE; 1.488 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 1.489 + process->shutdownInitiated = TRUE; 1.490 + 1.491 + #else 1.492 + if( process->numCoresDone == NUM_CORES ) 1.493 + { //means no cores have work, and none can generate more 1.494 + process->shutdownInitiated = TRUE; 1.495 + } 1.496 + #endif 1.497 + } 1.498 + } 1.499 + //check if shutdown has been initiated by this or other core 1.500 + if( process->shutdownInitiated ) 1.501 + { returnSlv = PR_SS__create_shutdown_slave(); 1.502 + } 1.503 + else 1.504 + returnSlv = NULL; 1.505 1.506 - if( returnSlv != NULL ) 1.507 - { returnSlv->coreAnimatedBy = coreNum; 1.508 - 1.509 - //have work, so reset Done flag (when work generated on other core) 1.510 - if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf 1.511 - processEnv->coreIsDone[coreNum] = FALSE; //don't just write always 1.512 + goto ReturnTheSlv; 1.513 + } //if( freeTaskSlv != NULL ) 1.514 + 1.515 + 1.516 + AssignSlave: 1.517 + { //get slave pointed to by meta task. 1.518 + returnSlv = assignedMetaTask->slaveAssignedTo; 1.519 + 1.520 + returnSlv->coreAnimatedBy = coreNum; 1.521 1.522 goto ReturnTheSlv; 1.523 } 1.524 - 1.525 - //were no slaves, so try to get a ready task.. 1.526 - newTaskStub = getTaskStub(); 1.527 - 1.528 - if( newTaskStub != NULL ) 1.529 + 1.530 + AssignNewTask: 1.531 { 1.532 //get the slot slave to assign the task to.. 1.533 - returnSlv = processEnv->slotTaskSlvs[coreNum][slotNum]; 1.534 + coreNum = slot->coreSlotIsOn; 1.535 + slotNum = slot->slotIdx; 1.536 + returnSlv = process->slotTaskSlvs[coreNum][slotNum]; 1.537 1.538 //point slave to task's function, and mark slave as having task 1.539 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv, 1.540 - newTaskStub->taskType->fn, newTaskStub->args ); 1.541 - returnSlv->taskStub = newTaskStub; 1.542 - newTaskStub->slaveAssignedTo = returnSlv; 1.543 + assignedMetaTask->topLevelFn, assignedMetaTask->initData ); 1.544 + returnSlv->metaTask = assignedMetaTask; 1.545 + assignedMetaTask->slaveAssignedTo = returnSlv; 1.546 returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type 1.547 1.548 //have work, so reset Done flag, if was set 1.549 - if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf 1.550 - processEnv->coreIsDone[coreNum] = FALSE; //don't just write always 1.551 + if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf 1.552 + process->coreIsDone[coreNum] = FALSE; //don't just write always 1.553 1.554 goto ReturnTheSlv; 1.555 } 1.556 - else 1.557 - { //no task, so prune the recycle pool of free task slaves 1.558 - freeTaskSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ ); 1.559 - if( freeTaskSlv != NULL ) 1.560 - { //delete to bound the num extras, and deliver shutdown cond 1.561 - handleDissipate( freeTaskSlv, processEnv ); 1.562 - //then return NULL 1.563 - returnSlv = NULL; 1.564 - 1.565 - goto ReturnTheSlv; 1.566 - } 1.567 - else 1.568 - { //candidate for shutdown.. if all extras dissipated, and no tasks 1.569 - // and no ready to resume slaves, then no way to generate 1.570 - // more tasks (on this core -- other core might have task still) 1.571 - if( processEnv->numLiveExtraTaskSlvs == 0 && 1.572 - processEnv->numLiveThreadSlvs == 0 ) 1.573 - { //This core sees no way to generate more tasks, so say it 1.574 - if( processEnv->coreIsDone[coreNum] == FALSE ) 1.575 - { processEnv->numCoresDone += 1; 1.576 - processEnv->coreIsDone[coreNum] = TRUE; 1.577 - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 1.578 - processEnv->shutdownInitiated = TRUE; 1.579 - 1.580 - #else 1.581 - if( processEnv->numCoresDone == NUM_CORES ) 1.582 - { //means no cores have work, and none can generate more 1.583 - processEnv->shutdownInitiated = TRUE; 1.584 - } 1.585 - #endif 1.586 - } 1.587 - } 1.588 - //check if shutdown has been initiated by this or other core 1.589 - if(processEnv->shutdownInitiated) 1.590 - { returnSlv = PR_SS__create_shutdown_slave(); 1.591 - } 1.592 - else 1.593 - returnSlv = NULL; 1.594 - 1.595 - goto ReturnTheSlv; //don't need, but completes pattern 1.596 - } //if( freeTaskSlv != NULL ) 1.597 - } //if( newTaskStub == NULL ) 1.598 - //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL 1.599 1.600 1.601 ReturnTheSlv: //All paths goto here.. to provide single point for holistic.. 1.602 1.603 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 1.604 if( returnSlv == NULL ) 1.605 - { returnSlv = processEnv->idleSlv[coreNum][slotNum]; 1.606 + { returnSlv = process->idleSlv[coreNum][slotNum]; 1.607 1.608 //things that would normally happen in resume(), but idle VPs 1.609 // never go there 1.610 - returnSlv->assignCount++; //gives each idle unit a unique ID 1.611 + returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID 1.612 Unit newU; 1.613 newU.vp = returnSlv->slaveID; 1.614 - newU.task = returnSlv->assignCount; 1.615 - addToListOfArrays(Unit,newU,processEnv->unitList); 1.616 + newU.task = returnSlv->numTimesAssignedToASlot; 1.617 + addToListOfArrays(Unit,newU,process->unitList); 1.618 1.619 - if (returnSlv->assignCount > 1) //make a dependency from prev idle unit 1.620 + if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit 1.621 { Dependency newD; // to this one 1.622 newD.from_vp = returnSlv->slaveID; 1.623 - newD.from_task = returnSlv->assignCount - 1; 1.624 + newD.from_task = returnSlv->numTimesAssignedToASlot - 1; 1.625 newD.to_vp = returnSlv->slaveID; 1.626 - newD.to_task = returnSlv->assignCount; 1.627 - addToListOfArrays(Dependency, newD ,processEnv->ctlDependenciesList); 1.628 + newD.to_task = returnSlv->numTimesAssignedToASlot; 1.629 + addToListOfArrays(Dependency, newD ,process->ctlDependenciesList); 1.630 } 1.631 } 1.632 else //have a slave will be assigned to the slot 1.633 { //assignSlv->numTimesAssigned++; 1.634 //get previous occupant of the slot 1.635 Unit prev_in_slot = 1.636 - processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; 1.637 + process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; 1.638 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency 1.639 { Dependency newD; // is a hardware dependency 1.640 newD.from_vp = prev_in_slot.vp; 1.641 newD.from_task = prev_in_slot.task; 1.642 newD.to_vp = returnSlv->slaveID; 1.643 - newD.to_task = returnSlv->assignCount; 1.644 - addToListOfArrays(Dependency,newD,processEnv->hwArcs); 1.645 + newD.to_task = returnSlv->numTimesAssignedToASlot; 1.646 + addToListOfArrays(Dependency,newD,process->hwArcs); 1.647 } 1.648 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous 1.649 - prev_in_slot.task = returnSlv->assignCount; 1.650 - processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = 1.651 + prev_in_slot.task = returnSlv->numTimesAssignedToASlot; 1.652 + process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = 1.653 prev_in_slot; 1.654 } 1.655 #endif 1.656 @@ -910,92 +1016,150 @@ 1.657 return( returnSlv ); 1.658 } 1.659 1.660 - 1.661 -//================================================================= 1.662 - //#else //is MODE__MULTI_LANG 1.663 - //For multi-lang mode, first, get the constraint-env holder out of 1.664 - // the process, which is in the slave. 1.665 - //Second, get the magic number out of the request, use it to look up 1.666 - // the constraint Env within the constraint-env holder. 1.667 - //Then get the request handler out of the constr env 1.668 - constrEnvHolder = slave->process->constrEnvHolder; 1.669 - reqst = slave->request; 1.670 - langMagicNumber = reqst->langMagicNumber; 1.671 - semanticEnv = lookup( langMagicNumber, constrEnvHolder ); //a macro 1.672 - if( slave->reqst->type == taskEnd ) //end-task is special 1.673 - { //need to know what lang's task ended 1.674 - taskEndHandler = semanticEnv->taskEndHandler; 1.675 - (*taskEndHandler)( slave, reqst, semanticEnv ); //can put semantic data into task end reqst, for continuation, etc 1.676 - //this is a slot slave, get a new task for it 1.677 - if( !existsOverrideAssigner )//if exists, is set above, before loop 1.678 - { //search for task assigner that has work 1.679 - for( a = 0; a < num_assigners; a++ ) 1.680 - { if( taskAssigners[a]->hasWork ) 1.681 - { newTaskAssigner = taskAssigners[a]; 1.682 - (*newTaskAssigner)( slave, semanticEnv ); 1.683 - goto GotTask; 1.684 - } 1.685 - } 1.686 - goto NoTasks; 1.687 - } 1.688 - 1.689 - GotTask: 1.690 - continue; //have work, so do next iter of loop, don't call slave assigner 1.691 - } 1.692 - if( slave->typeOfVP == taskSlotSlv ) changeSlvType();//is suspended task 1.693 - //now do normal suspended slave request handler 1.694 - requestHandler = semanticEnv->requestHandler; 1.695 - //#endif 1.696 1.697 - 1.698 - } 1.699 - //If make it here, then was no task for this slot 1.700 - //slot empty, hand to Assigner to fill with a slave 1.701 - if( currSlot->needsSlaveAssigned ) 1.702 - { //Call plugin's Assigner to give slot a new slave 1.703 - HOLISTIC__Record_Assigner_start; 1.704 - 1.705 - //#ifdef MODE__MULTI_LANG 1.706 - NoTasks: 1.707 - //First, choose an Assigner.. 1.708 - //There are several Assigners, one for each langlet.. they all 1.709 - // indicate whether they have work available.. just pick the first 1.710 - // one that has work.. Or, if there's a Unified Assigner, call 1.711 - // that one.. So, go down array, checking.. 1.712 - if( !existsOverrideAssigner ) 1.713 - { for( a = 0; a < num_assigners; a++ ) 1.714 - { if( assigners[a]->hasWork ) 1.715 - { slaveAssigner = assigners[a]; 1.716 - goto GotAssigner; 1.717 - } 1.718 - } 1.719 - //no work, so just continue to next iter of scan loop 1.720 - continue; 1.721 - } 1.722 - //when exists override, the assigner is set, once, above, so do nothing 1.723 - GotAssigner: 1.724 - //#endif 1.725 - 1.726 - assignedSlaveVP = 1.727 - (*slaveAssigner)( semanticEnv, currSlot ); 1.728 - 1.729 - //put the chosen slave into slot, and adjust flags and state 1.730 - if( assignedSlaveVP != NULL ) 1.731 - { currSlot->slaveAssignedToSlot = assignedSlaveVP; 1.732 - assignedSlaveVP->animSlotAssignedTo = currSlot; 1.733 - currSlot->needsSlaveAssigned = FALSE; 1.734 - numSlotsFilled += 1; 1.735 - 1.736 - HOLISTIC__Record_Assigner_end; 1.737 - } 1.738 - }//if slot needs slave assigned 1.739 - }//for( slotIdx.. 1.740 - 1.741 - MEAS__Capture_Post_Master_Point; 1.742 +/*In creator, only PR related things happen, and things in the langlet whose 1.743 + * creator construct was used. 1.744 + *Other langlet still gets a chance to create semData -- but by registering a 1.745 + * "createSemData" handler in the semEnv. When a construct of the langlet 1.746 + * calls "PR__give_sem_data()", if there is no semData for that langlet, 1.747 + * the PR will call the creator in the langlet's semEnv, place whatever it 1.748 + * makes as the semData in that slave for that langlet, and return that semData 1.749 + * 1.750 + *So, as far as counting things, a langlet is only allowed to count creation 1.751 + * of slaves it creates itself.. may have to change this later.. add a way for 1.752 + * langlet to register a trigger Fn called each time a slave gets created.. 1.753 + * need more experience with what langlets will do at create time.. think Cilk 1.754 + * has interesting create behavior.. not sure how that will differ in light 1.755 + * of true tasks and langlet approach. Look at it after all done and start 1.756 + * modifying the langs to be langlets.. 1.757 + * 1.758 + *PR itself needs to create the slave, then update numLiveSlaves in process, 1.759 + * copy processID from requestor to newly created 1.760 + */ 1.761 +PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv ) 1.762 + { SlaveVP *newSlv; 1.763 + PRMetaTask metaTask; 1.764 + PRProcess *process; 1.765 + 1.766 + process = requestingSlv->processSlaveIsIn; 1.767 + newSlv = PR_int__create_slaveVP(); 1.768 + newSlv->typeOfVP = GenericSlv; 1.769 + newSlv->processSlaveIsIn = process; 1.770 + process->numLiveGenericSlaves += 1; 1.771 + metaTask = PR_int__create_slave_meta_task(); 1.772 + metaTask->taskID = req->ID; 1.773 + metaTask->taskType = GenericSlave; 1.774 1.775 - masterSwitchToCoreCtlr( masterVP ); 1.776 - flushRegisters(); 1.777 - DEBUG__printf(FALSE,"came back after switch to core -- so lock released!"); 1.778 - }//while(1) 1.779 + (*req->handler)(newSlv); 1.780 } 1.781 1.782 +/*The dissipate handler has to update the number of slaves of the type, within 1.783 + * the process, and call the langlet handler linked into the request, 1.784 + * and after that returns, then call the PR function that frees the slave state 1.785 + * (or recycles the slave). 1.786 + * 1.787 + *The PR function that frees the slave state has to also free all of the 1.788 + * semData in the slave.. or else reset all of the semDatas.. by, say, marking 1.789 + * them, then in PR__give_semData( magicNum ) call the langlet registered 1.790 + * "resetSemData" Fn. 1.791 + */ 1.792 +PRHandle_Dissipate( SlaveVP *slave ) 1.793 + { PRProcess *process; 1.794 + void *semEnv; 1.795 + 1.796 + process = slave->processSlaveIsIn; 1.797 + 1.798 + //do the language's dissipate handler 1.799 + semEnv = PR_int__give_sem_env_for( slave, slave->request->langMagicNumber ); 1.800 + (*slave->request->handler)( slave, semEnv ); 1.801 + 1.802 + process->numLiveGenericSlaves -= 1; 1.803 + PR_int__dissipate_slaveVP_multilang( slave ); //recycles and resets semDatas 1.804 + 1.805 + //check End Of Process Condition 1.806 + if( process->numLiveTasks == 0 && 1.807 + process->numLiveGenericSlaves == 0 ) 1.808 + signalEndOfProcess; 1.809 + } 1.810 + 1.811 +/*Create task is a special form, that has PR behavior in addition to plugin 1.812 + * behavior. Master calls this first, and this in turn calls the plugin's 1.813 + * create task handler. 1.814 + */ 1.815 +inline void 1.816 +PRHandle_CreateTask( TopLevelFn topLevelFn, void *initData, PRReqst *req, 1.817 + SlaveVP *requestingSlv ) 1.818 + { PRMetaTask *metaTask; 1.819 + PRProcess *process; 1.820 + void *semEnv, _langMetaTask; 1.821 + PRLangMetaTask *langMetaTask; 1.822 + 1.823 + process = requestingSlv->processSlaveIsIn; 1.824 + 1.825 + metaTask = PR_int__create_meta_task( req ); 1.826 + metaTask->taskID = req->ID; //may be NULL 1.827 + metaTask->topLevelFn = topLevelFn; 1.828 + metaTask->initData = initData; 1.829 + 1.830 + process->numLiveTasks += 1; 1.831 + 1.832 + //plugin tracks tasks ready, and has its own assigner, so task doesn't 1.833 + // come back from lang's handler -- it's consumed and stays in semEnv. 1.834 + //But handler gives back the language-specific meta-task it creates, and 1.835 + // then hook that into the PR meta-task 1.836 + //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size 1.837 + // of the lang's metaTask, and alloc's that plus the prolog and returns 1.838 + // ptr to position just above the prolog) 1.839 + semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req 1.840 + _langMetaTask = (*requestingSlv->request->handler)(req, semEnv); 1.841 + langMetaTask = (PRLangMetaTask *)_langMetaTask; 1.842 + metaTask->langMetaTask = langMetaTask; 1.843 + langMetaTask->protoMetaTask = metaTask; 1.844 + 1.845 + return; 1.846 + } 1.847 + 1.848 +/*When a task ends, are two scenarios: 1) task ran to completion, or 2) task 1.849 + * suspended at some point in its code. 1.850 + *For 1, just decr count of live tasks (and check for end condition) -- the 1.851 + * master loop will decide what goes into the slot freed up by this task end, 1.852 + * so, here, don't worry about assigning a new task to the slot slave. 1.853 + *For 2, the task's slot slave has been converted to a free task slave, which 1.854 + * now has nothing more to do, so send it to the recycle Q (which includes 1.855 + * freeing all the semData and meta task structs alloc'd for it). Then 1.856 + * decrement the live task count and check end condition. 1.857 + * 1.858 + *PR has to update count of live tasks, and check end of process condition. 1.859 + * There are constructs that wait for a process to end, so when end detected, 1.860 + * have to resume what's waiting.. 1.861 + *Thing is, the wait is used in "main", so it's an OS thread. That means 1.862 + * PR internals have to do OS thread signaling. Want to do that in the 1.863 + * core controller, which has the original stack of an OS thread. 1.864 + * 1.865 + *So here, when detect process end, signal to the core controller, which will 1.866 + * then do the condition variable notify to the OS thread that's waiting. 1.867 + */ 1.868 +inline void 1.869 +PRHandle_EndTask( SlaveVP *requestingSlv ) 1.870 + { void *semEnv; 1.871 + PRReqst *req; 1.872 + PRMetaTask *metaTask; 1.873 + PRProcess *process; 1.874 + 1.875 + req = requestingSlv->request; 1.876 + semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req 1.877 + metaTask = req->metaTask; 1.878 + //Want to keep PRMetaTask hidden from plugin, so extract semReq.. 1.879 + (*req->handler)( metaTask, req->semReq, semEnv ); 1.880 + 1.881 + recycleFreeTaskSlave( requestingSlv ); 1.882 + 1.883 + process->numLiveTasks -= 1; 1.884 + 1.885 + //check End Of Process Condition 1.886 + if( process->numLiveTasks == 0 && 1.887 + process->numLiveGenericSlaves == 0 ) 1.888 + signalEndOfProcessToCoreCtlr; 1.889 + } 1.890 + 1.891 + 1.892 \ No newline at end of file
