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