Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
comparison AnimationMaster.c @ 273:40e7625e57bd
Compiles and runs, up to end of process, working on end process and shutdown
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Sat, 02 Mar 2013 09:43:45 -0800 |
| parents | bc5030385120 |
| children | 1d7ea1b0f176 |
comparison
equal
deleted
inserted
replaced
| 17:1f4f559c0919 | 18:cb4417c0c163 |
|---|---|
| 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 /* | 15 //========================= Local Declarations ======================== |
| 16 void PRHandle_CreateTask_SL(SlaveVP *slave); | 16 inline PRProcess * |
| 17 | 17 pickAProcess( AnimSlot *slot ); |
| 18 void PRHandle_CreateSlave_SL(SlaveVP *slave); | 18 inline bool32 |
| 19 void PRHandle_Dissipate_SL(SlaveVP *slave); | 19 assignWork( PRProcess *process, AnimSlot *slot ); |
| 20 void PR_int__handle_PRServiceReq_SL(SlaveVP *slave); | 20 |
| 21 */ | 21 inline void |
| 22 inline void PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); | 22 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); |
| 23 inline void PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); | 23 inline void |
| 24 inline void PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); | 24 PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); |
| 25 void PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); | 25 inline void |
| 26 | 26 PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); |
| 27 | 27 inline void |
| 28 //inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot ); | 28 PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); |
| 29 inline PRProcess * pickAProcess( AnimSlot *slot ); | 29 |
| 30 inline bool32 assignWork( PRProcess *process, AnimSlot *slot ); | 30 inline void |
| 31 | 31 PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ); |
| 32 | |
| 33 inline void | |
| 34 handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); | |
| 35 inline void | |
| 36 handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); | |
| 37 | |
| 38 //=========================================================================== | |
| 32 | 39 |
| 33 /*Note: there used to be a coreController that was another animation | 40 /*Note: there used to be a coreController that was another animation |
| 34 * layer below both the masterVP and the slaveVPs.. in that case, the | 41 * layer below both the masterVP and the slaveVPs.. in that case, the |
| 35 * masterVP was a virtual processor whose processor-state was the same | 42 * masterVP was a virtual processor whose processor-state was the same |
| 36 * as a slaveVP's processor sate, both implemented as a SlaveVP struct. | 43 * as a slaveVP's processor sate, both implemented as a SlaveVP struct. |
| 57 int32 magicNumber; | 64 int32 magicNumber; |
| 58 SlaveVP *slave; | 65 SlaveVP *slave; |
| 59 PRLangEnv *langEnv; | 66 PRLangEnv *langEnv; |
| 60 PRReqst *req; | 67 PRReqst *req; |
| 61 PRProcess *process; | 68 PRProcess *process; |
| 62 bool32 foundWork; | 69 bool32 didAssignWork; |
| 63 | 70 |
| 64 //Check if newly-done slave in slot, which will need request handled | 71 //Check if newly-done slave in slot, which will need request handled |
| 65 //NOTE: left over from when had a coreController & MasterVP managed | 72 //NOTE: left over from when had a coreController & MasterVP managed |
| 66 // several slots | 73 // several slots |
| 67 if( slot->workIsDone ) | 74 if( slot->workIsDone ) |
| 68 { slot->workIsDone = FALSE; | 75 { slot->workIsDone = FALSE; |
| 69 slot->needsWorkAssigned = TRUE; | 76 slot->needsWorkAssigned = TRUE; |
| 70 | 77 |
| 71 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot | 78 //An Idle VP has no request to handle, so skip to assign.. |
| 72 MEAS__startReqHdlr; | 79 if( slot->slaveAssignedToSlot->typeOfVP != IdleVP ) |
| 73 | 80 { |
| 74 | 81 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot |
| 75 //process the request made by the slave (held inside slave struc) | 82 MEAS__startReqHdlr; |
| 76 slave = slot->slaveAssignedToSlot; | 83 |
| 77 req = slave->request; | 84 |
| 78 | 85 //process the request made by the slave (held inside slave struc) |
| 79 //If the requesting slave is a slot slave, and request is not | 86 slave = slot->slaveAssignedToSlot; |
| 80 // task-end, then turn it into a free task slave. | 87 req = slave->request; |
| 81 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) | 88 |
| 82 PR_int__replace_with_new_slot_slv( slave ); | 89 //If the requesting slave is a slot slave, and request is not |
| 83 | 90 // task-end, then turn it into a free task slave & continue |
| 84 //Handle task create and end first -- they're special cases.. | 91 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) |
| 85 switch( req->reqType ) | 92 PR_int__replace_with_new_slot_slv( slave ); |
| 86 { case TaskEnd: | 93 |
| 87 { //do PR handler, which calls lang's hdlr and does recycle of | 94 //Handle task create and end first -- they're special cases.. |
| 88 // free task slave if needed -- PR handler checks for free task Slv | 95 switch( req->reqType ) |
| 89 PRHandle__EndTask( req, slave ); break; | 96 { case TaskEnd: |
| 97 { //do PR handler, which calls lang's hdlr and does recycle of | |
| 98 // free task slave if needed -- PR handler checks for free task Slv | |
| 99 PRHandle__EndTask( req, slave ); break; | |
| 100 } | |
| 101 case TaskCreate: | |
| 102 { //Do PR's create-task handler, which calls the lang's hdlr | |
| 103 // PR handler checks for free task Slv | |
| 104 PRHandle__CreateTask( req, slave ); break; | |
| 105 } | |
| 106 case SlvCreate: PRHandle__CreateSlave( req, slave ); break; | |
| 107 case SlvDissipate: PRHandle__EndSlave( req, slave ); break; | |
| 108 case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env | |
| 109 case Hardware: //for future expansion | |
| 110 case IO: //for future expansion | |
| 111 case OSCall: //for future expansion | |
| 112 PR_int__throw_exception("Not implemented", slave, NULL); break; | |
| 113 case LangShutdown: PRHandle__LangShutdown( req, slave ); break; | |
| 114 case Language: //normal lang request | |
| 115 { magicNumber = req->langMagicNumber; | |
| 116 langEnv = PR_PI__give_lang_env_for_slave( slave, magicNumber ); | |
| 117 (*req->handler)( req->langReq, slave, langEnv ); | |
| 118 } | |
| 90 } | 119 } |
| 91 case TaskCreate: | 120 |
| 92 { //Do PR's create-task handler, which calls the lang's hdlr | |
| 93 // PR handler checks for free task Slv | |
| 94 PRHandle__CreateTask( req, slave ); break; | |
| 95 } | |
| 96 case SlvCreate: PRHandle__CreateSlave( req, slave ); break; | |
| 97 case SlvDissipate: PRHandle__EndSlave( req, slave ); break; | |
| 98 case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env | |
| 99 case Hardware: //for future expansion | |
| 100 case IO: //for future expansion | |
| 101 case OSCall: //for future expansion | |
| 102 PR_int__throw_exception("Not implemented", slave, NULL); break; | |
| 103 case Language: //normal lang request | |
| 104 { magicNumber = req->langMagicNumber; | |
| 105 langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); | |
| 106 (*req->handler)( req->langReq, slave, langEnv ); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 MEAS__endReqHdlr; | 121 MEAS__endReqHdlr; |
| 111 HOLISTIC__Record_AppResponder_end; | 122 HOLISTIC__Record_AppResponder_end; |
| 123 }//if not idleVP | |
| 112 } //if have request to be handled | 124 } //if have request to be handled |
| 113 | 125 |
| 114 //NOTE: IF statement is leftover from when master managed many slots | 126 //NOTE: IF statement is leftover from when master managed many slots |
| 115 foundWork = FALSE; | 127 didAssignWork = FALSE; |
| 116 if( slot->needsWorkAssigned ) //can probably remove IF, not that only one slot | 128 if( slot->needsWorkAssigned ) //can probably remove IF, now that only one slot |
| 117 { | 129 { |
| 118 HOLISTIC__Record_Assigner_start; | 130 HOLISTIC__Record_Assigner_start; |
| 119 | 131 |
| 120 //Pick a process to get this slot | 132 //Pick a process to get this slot |
| 121 process = pickAProcess( slot ); | 133 process = pickAProcess( slot ); |
| 122 | 134 |
| 123 //Scan lang environs, looking for langEnv with ready work. | 135 //Scan lang environs, looking for langEnv with ready work. |
| 124 // call the Assigner for that lang Env, to get a slave for the slot | 136 // call the Assigner for that lang Env, to get a slave for the slot |
| 125 foundWork = | 137 if( process != NULL ) |
| 126 assignWork( process, slot ); | 138 { didAssignWork = |
| 127 | 139 assignWork( process, slot ); |
| 140 } | |
| 128 HOLISTIC__Record_Assigner_end; | 141 HOLISTIC__Record_Assigner_end; |
| 129 | 142 |
| 130 // fixme; //make this a while loop that tries a different process if this one fails | 143 if( !didAssignWork ) //if no work assigned, be sure idle slave is in slot |
| 144 { slot->slaveAssignedToSlot = _PRTopEnv->idleSlv[slot->coreSlotIsOn][0]; | |
| 145 } | |
| 146 // fixme; //make into a loop that tries more processes if fails to assign | |
| 131 }//if slot needs slave assigned | 147 }//if slot needs slave assigned |
| 132 | 148 |
| 133 return foundWork; | 149 return didAssignWork; |
| 134 } | 150 } |
| 135 | 151 |
| 136 /*When several processes exist, use some pattern for picking one to give | 152 /*When several processes exist, use some pattern for picking one to give |
| 137 * the animation slot to. | 153 * the animation slot to. |
| 138 *First, it has to be a process that has work available. | 154 *First, it has to be a process that has work available. |
| 199 else | 215 else |
| 200 goto NoWork; | 216 goto NoWork; |
| 201 } | 217 } |
| 202 | 218 |
| 203 //If here, then no override assigner, so search language envs for work | 219 //If here, then no override assigner, so search language envs for work |
| 204 int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv; | 220 int32 envIdx, numEnvs; PRLangEnv **protoLangEnvsList, *protoLangEnv; |
| 205 langEnvsList = process->langEnvsList; | 221 protoLangEnvsList = process->protoLangEnvsList; |
| 206 numEnvs = process->numLangEnvs; | 222 numEnvs = process->numLangEnvs; |
| 207 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array | 223 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array |
| 208 { langEnv = langEnvsList[envIdx]; | 224 { protoLangEnv = protoLangEnvsList[envIdx]; |
| 209 if( langEnv->numReadyWork > 0 ) | 225 if( protoLangEnv->numReadyWork > 0 ) |
| 210 { bool32 | 226 { bool32 |
| 211 didAssignWork = | 227 didAssignWork = |
| 212 (*langEnv->workAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot | 228 (*protoLangEnv->workAssigner)( PR_int__give_lang_env(protoLangEnv), slot ); //assigner calls PR to put slave/task into slot |
| 213 | 229 |
| 214 if(didAssignWork) | 230 if(didAssignWork) |
| 215 { langEnv->numReadyWork -= 1; | 231 { protoLangEnv->numReadyWork -= 1; |
| 216 if( langEnv->numReadyWork == 0 ) | 232 if( protoLangEnv->numReadyWork == 0 ) |
| 217 { process->numEnvsWithWork -= 1; | 233 { process->numEnvsWithWork -= 1; |
| 218 } | 234 } |
| 219 goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work | 235 goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work |
| 220 } | 236 } |
| 221 else | 237 else |
| 254 | 270 |
| 255 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic.. | 271 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic.. |
| 256 { | 272 { |
| 257 HOLISTIC__Record_Assigner_end; | 273 HOLISTIC__Record_Assigner_end; |
| 258 return TRUE; | 274 return TRUE; |
| 275 } | |
| 276 } | |
| 277 | |
| 278 | |
| 279 //================================= | |
| 280 //=== | |
| 281 //= | |
| 282 /*Create task is a special form, that has PR behavior in addition to plugin | |
| 283 * behavior. Master calls this first, and it then calls the plugin's | |
| 284 * create task handler. | |
| 285 * | |
| 286 *Note: the requesting slave must be either generic slave or free task slave | |
| 287 */ | |
| 288 inline | |
| 289 void | |
| 290 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) | |
| 291 { PRMetaTask *protoMetaTask; | |
| 292 PRProcess *process; | |
| 293 PRLangEnv *protoLangEnv; | |
| 294 void *task; | |
| 295 | |
| 296 process = slave->processSlaveIsIn; | |
| 297 | |
| 298 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, | |
| 299 req->langMagicNumber ); | |
| 300 | |
| 301 //Do the langlet's create-task handler, which keeps the task | |
| 302 // inside the langlet's lang env, but returns the langMetaTask | |
| 303 // so that PR can then put stuff into the prolog | |
| 304 //typedef void * (*CreateHandler)( void *, SlaveVP *, void * ); //req, slv, langEnv | |
| 305 // | |
| 306 task = | |
| 307 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); | |
| 308 protoMetaTask = PR_int__give_prolog_of_lang_meta_task( task ); | |
| 309 protoMetaTask->ID = req->ID; //may be NULL | |
| 310 protoMetaTask->topLevelFn = req->topLevelFn; | |
| 311 protoMetaTask->initData = req->initData; | |
| 312 protoMetaTask->processTaskIsIn = process; | |
| 313 | |
| 314 process->numLiveTasks += 1; | |
| 315 protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead | |
| 316 | |
| 317 return; | |
| 318 } | |
| 319 | |
| 320 /*When a task ends, have two scenarios: 1) task ran to completion, or 2) task | |
| 321 * has been suspended at some point in its code. | |
| 322 *For 1, just decr count of live tasks (and check for end condition) -- the | |
| 323 * master loop will decide what goes into the slot freed up by this task end, | |
| 324 * so, here, don't worry about assigning a new task to the slot slave. | |
| 325 *For 2, the task's slot slave has been converted to a free task slave, which | |
| 326 * now has nothing more to do, so send it to the recycle Q (which includes | |
| 327 * freeing all the langData and meta task structs alloc'd for it). Then | |
| 328 * decrement the live task count and check end condition. | |
| 329 * | |
| 330 *PR has to update count of live tasks, and check end of process condition. | |
| 331 * The "main" can invoke constructs that wait for a process to end, so when | |
| 332 * end detected, have to resume what's waiting.. | |
| 333 *Thing is, that wait involves the main OS thread. That means | |
| 334 * PR internals have to do OS thread signaling. Want to do that in the | |
| 335 * core controller, which has the original stack of an OS thread. So the | |
| 336 * end process handling happens in the core controller. | |
| 337 * | |
| 338 *So here, when detect process end, signal to the core controller, which will | |
| 339 * then do the condition variable notify to the OS thread that's waiting. | |
| 340 * | |
| 341 *Note: slave may be either a slot slave or a free task slave. | |
| 342 */ | |
| 343 inline | |
| 344 void | |
| 345 PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) | |
| 346 { void *langEnv; | |
| 347 PRLangEnv *protoLangEnv; | |
| 348 PRProcess *process; | |
| 349 void *langMetaTask; | |
| 350 | |
| 351 process = requestingSlv->processSlaveIsIn; | |
| 352 langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req | |
| 353 protoLangEnv = PR_int__give_proto_lang_env( langEnv ); | |
| 354 | |
| 355 langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); | |
| 356 | |
| 357 //Do the langlet's request handler | |
| 358 //Want to keep PR structs hidden from plugin, so extract langReq.. | |
| 359 //This is supposed to free any langlet-malloc'd mem, including meta task | |
| 360 (*req->handler)( req->langReq, requestingSlv, langEnv ); | |
| 361 | |
| 362 protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead | |
| 363 if( protoLangEnv->numLiveWork == 0 && | |
| 364 numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) | |
| 365 { SlaveVP * | |
| 366 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); | |
| 367 //can't resume into langlet that just ended its last work! | |
| 368 // and don't have env that the waiter was created in, so resume | |
| 369 // into PRServ env.. | |
| 370 void * | |
| 371 resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); | |
| 372 while( waitingSlave != NULL ) | |
| 373 { //resume a slave that was waiting for work in this env to finish | |
| 374 PR_PI__make_slave_ready( waitingSlave, resumeEnv ); | |
| 375 //get next waiting slave, repeat.. | |
| 376 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 | |
| 381 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv | |
| 382 if( requestingSlv->typeOfVP == FreeTaskSlv ) | |
| 383 PR_int__recycle_slaveVP( requestingSlv ); //Doesn't decr num live slaves | |
| 384 | |
| 385 process->numLiveTasks -= 1; | |
| 386 //NOTE: end-task is unrelated to work available (just in case wondering) | |
| 387 | |
| 388 //check End Of Process Condition | |
| 389 if( process->numLiveTasks == 0 && | |
| 390 process->numLiveGenericSlvs == 0 ) | |
| 391 { //Tell the core controller to do wakeup of any waiting OS thread | |
| 392 PR_SS__end_process_normally( process ); | |
| 259 } | 393 } |
| 260 } | 394 } |
| 261 | 395 |
| 262 | 396 |
| 263 | 397 |
| 291 { SlaveVP *newSlv; | 425 { SlaveVP *newSlv; |
| 292 PRProcess *process; | 426 PRProcess *process; |
| 293 PRLangEnv *protoLangEnv; | 427 PRLangEnv *protoLangEnv; |
| 294 | 428 |
| 295 process = slave->processSlaveIsIn; | 429 process = slave->processSlaveIsIn; |
| 296 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber ); | 430 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, req->langMagicNumber ); |
| 297 | 431 |
| 298 //create handler, or a future request handler will call PR_PI__make_slave_ready | 432 //create handler, or a future request handler will call PR_PI__make_slave_ready |
| 299 // which will in turn handle updating which langlets and which processes have | 433 // which will in turn handle updating which langlets and which processes have |
| 300 // work available. | 434 // work available. |
| 301 //NOTE: create slv has diff prototype than standard reqst hdlr | 435 //NOTE: create slv has diff prototype than standard reqst hdlr |
| 304 | 438 |
| 305 newSlv->typeOfVP = GenericSlv; | 439 newSlv->typeOfVP = GenericSlv; |
| 306 newSlv->processSlaveIsIn = process; | 440 newSlv->processSlaveIsIn = process; |
| 307 newSlv->ID = req->ID; | 441 newSlv->ID = req->ID; |
| 308 process->numLiveGenericSlvs += 1; //not same as work ready! | 442 process->numLiveGenericSlvs += 1; //not same as work ready! |
| 443 protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead | |
| 309 } | 444 } |
| 310 | 445 |
| 311 /*The dissipate handler has to, update the number of slaves of the type, within | 446 /*The dissipate handler has to, update the number of slaves of the type, within |
| 312 * the process, and call the langlet handler linked into the request, | 447 * the process, and call the langlet handler linked into the request, |
| 313 * and after that returns, then call the PR function that frees the slave state | 448 * and after that returns, then call the PR function that frees the slave state |
| 325 PRLangEnv *protoLangEnv; | 460 PRLangEnv *protoLangEnv; |
| 326 | 461 |
| 327 process = slave->processSlaveIsIn; | 462 process = slave->processSlaveIsIn; |
| 328 | 463 |
| 329 //do the language's dissipate handler | 464 //do the language's dissipate handler |
| 330 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber ); | 465 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, slave->request->langMagicNumber ); |
| 331 | 466 |
| 332 if(req->handler != NULL) | 467 if(req->handler != NULL) |
| 333 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); | 468 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); |
| 334 | 469 |
| 470 protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead | |
| 471 if( protoLangEnv->numLiveWork == 0 && | |
| 472 numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) | |
| 473 { SlaveVP * | |
| 474 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); | |
| 475 //can't resume into langlet that just ended its last work! | |
| 476 // and don't have env that the waiter was created in, so resume | |
| 477 // into PRServ env.. | |
| 478 void * | |
| 479 resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); | |
| 480 while( waitingSlave != NULL ) | |
| 481 { //resume a slave that was waiting for work in this env to finish | |
| 482 PR_PI__make_slave_ready( waitingSlave, resumeEnv ); | |
| 483 //get next waiting slave, repeat.. | |
| 484 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); | |
| 485 } | |
| 486 } | |
| 487 | |
| 335 process->numLiveGenericSlvs -= 1; | 488 process->numLiveGenericSlvs -= 1; |
| 336 PR_int__recycle_slave( slave ); | 489 PR_int__recycle_slaveVP( slave ); |
| 337 //NOTE: dissipate is unrelated to work available (just in case wondering) | 490 //NOTE: dissipate is unrelated to work available (just in case wondering) |
| 338 | 491 |
| 339 //check End Of Process Condition | 492 //check End Of Process Condition |
| 340 if( process->numLiveTasks == 0 && | 493 if( process->numLiveTasks == 0 && |
| 341 process->numLiveGenericSlvs == 0 ) | 494 process->numLiveGenericSlvs == 0 ) |
| 342 PR_SS__shutdown_process( process ); | 495 PR_SS__end_process_normally( process ); |
| 343 } | 496 } |
| 344 | 497 |
| 345 /*Create task is a special form, that has PR behavior in addition to plugin | 498 //======================= |
| 346 * behavior. Master calls this first, and it then calls the plugin's | 499 //=== |
| 347 * create task handler. | 500 //= |
| 348 * | 501 /*Langlet shutdown triggers this, which calls the registered shutdown |
| 349 *Note: the requesting slave must be either generic slave or free task slave | 502 * handler for the langlet, and removes the lang's env from the process |
| 350 */ | 503 */ |
| 351 inline | 504 inline |
| 352 void | 505 void |
| 353 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) | 506 PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ) |
| 354 { PRMetaTask *metaTask; | |
| 355 PRProcess *process; | |
| 356 PRLangEnv *protoLangEnv; | |
| 357 void *task; | |
| 358 | |
| 359 process = slave->processSlaveIsIn; | |
| 360 | |
| 361 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, | |
| 362 req->langMagicNumber ); | |
| 363 | |
| 364 //Do the langlet's create-task handler, which keeps the task | |
| 365 // inside the langlet's lang env, but returns the langMetaTask | |
| 366 // so PR can put stuff into the prolog | |
| 367 task = | |
| 368 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); | |
| 369 metaTask = PR_int__give_prolog_of_task( task ); | |
| 370 metaTask->ID = req->ID; //may be NULL | |
| 371 metaTask->topLevelFn = req->topLevelFn; | |
| 372 metaTask->initData = req->initData; | |
| 373 | |
| 374 process->numLiveTasks += 1; | |
| 375 | |
| 376 return; | |
| 377 } | |
| 378 | |
| 379 /*When a task ends, have two scenarios: 1) task ran to completion, or 2) task | |
| 380 * has been suspended at some point in its code. | |
| 381 *For 1, just decr count of live tasks (and check for end condition) -- the | |
| 382 * master loop will decide what goes into the slot freed up by this task end, | |
| 383 * so, here, don't worry about assigning a new task to the slot slave. | |
| 384 *For 2, the task's slot slave has been converted to a free task slave, which | |
| 385 * now has nothing more to do, so send it to the recycle Q (which includes | |
| 386 * freeing all the langData and meta task structs alloc'd for it). Then | |
| 387 * decrement the live task count and check end condition. | |
| 388 * | |
| 389 *PR has to update count of live tasks, and check end of process condition. | |
| 390 * The "main" can invoke constructs that wait for a process to end, so when | |
| 391 * end detected, have to resume what's waiting.. | |
| 392 *Thing is, that wait involves the main OS thread. That means | |
| 393 * PR internals have to do OS thread signaling. Want to do that in the | |
| 394 * core controller, which has the original stack of an OS thread. So the | |
| 395 * end process handling happens in the core controller. | |
| 396 * | |
| 397 *So here, when detect process end, signal to the core controller, which will | |
| 398 * then do the condition variable notify to the OS thread that's waiting. | |
| 399 * | |
| 400 *Note: slave may be either a slot slave or a free task slave. | |
| 401 */ | |
| 402 inline | |
| 403 void | |
| 404 PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) | |
| 405 { void *langEnv; | 507 { void *langEnv; |
| 508 PRLangEnv *protoLangEnv; | |
| 406 PRProcess *process; | 509 PRProcess *process; |
| 407 void *langMetaTask; | 510 |
| 408 | 511 process = requestingSlv->processSlaveIsIn; |
| 409 langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req | 512 protoLangEnv = PR_int__give_proto_lang_env_from_process( process, req->langMagicNumber ); |
| 410 langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); | 513 langEnv = PR_int__give_lang_env( protoLangEnv ); |
| 411 | 514 |
| 412 //Do the langlet's request handler | 515 //call the langlet's registered handler |
| 413 //Want to keep PR structs hidden from plugin, so extract langReq.. | 516 (*protoLangEnv->shutdownHdlr)( langEnv ); |
| 414 (*req->handler)( req->langReq, requestingSlv, langEnv ); | 517 |
| 415 | 518 PR_int__remove_lang_env_from_process_and_free( langEnv ); //removes from process and frees |
| 416 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv | |
| 417 if( requestingSlv->typeOfVP == FreeTaskSlv ) | |
| 418 PR_int__recycle_slave( requestingSlv ); //Doesn't decr num live slaves | |
| 419 | |
| 420 process->numLiveTasks -= 1; | |
| 421 //NOTE: end-task is unrelated to work available (just in case wondering) | |
| 422 | |
| 423 //check End Of Process Condition | |
| 424 if( process->numLiveTasks == 0 && | |
| 425 process->numLiveGenericSlvs == 0 ) | |
| 426 { //Tell the core controller to do wakeup of any waiting OS thread | |
| 427 PR_SS__shutdown_process( process ); | |
| 428 } | |
| 429 } | 519 } |
| 430 | 520 |
| 431 | 521 |
| 432 /*This is for OS requests and PR infrastructure requests, which are not | 522 /*This is for OS requests and PR infrastructure requests, which are not |
| 433 * part of the PRServ language -- this is for things that have to be in the | 523 * part of the PRServ language -- this is for things that have to be in the |
| 436 * | 526 * |
| 437 *As of Jan 2013, doesn't do much of anything.. | 527 *As of Jan 2013, doesn't do much of anything.. |
| 438 */ | 528 */ |
| 439 void inline | 529 void inline |
| 440 PRHandle__ServiceReq( SlaveVP *requestingSlv ) | 530 PRHandle__ServiceReq( SlaveVP *requestingSlv ) |
| 441 { PRReqst *req; | 531 { PRReqst *req; |
| 442 PRServReq *langReq; | 532 PRServiceReq *langReq; |
| 443 void *langEnv; | 533 PRLangEnv *protoLangEnv; |
| 444 int32 magicNumber; | 534 int32 magicNumber; |
| 445 | 535 |
| 446 | 536 |
| 447 req = requestingSlv->request; | 537 req = requestingSlv->request; |
| 448 | 538 |
| 449 magicNumber = req->langMagicNumber; | 539 magicNumber = req->langMagicNumber; |
| 450 langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); | 540 protoLangEnv = PR_int__give_proto_lang_env_for_slave( requestingSlv, magicNumber ); |
| 451 | 541 |
| 452 langReq = PR_PI__take_lang_reqst_from(req); | 542 langReq = PR_PI__take_lang_reqst_from(req); |
| 453 if( langReq == NULL ) return; | 543 if( langReq == NULL ) return; |
| 454 switch( langReq->reqType ) //lang handlers are all in other file | 544 switch( langReq->reqType ) //lang handlers are all in other file |
| 455 { | 545 { |
| 456 case make_probe: handleMakeProbe( langReq, langEnv ); | 546 case make_probe: handleMakeProbe( langReq, protoLangEnv ); |
| 457 break; | 547 break; |
| 458 case throw_excp: handleThrowException( langReq, langEnv ); | 548 case throw_excp: handleThrowException( langReq, protoLangEnv ); |
| 459 break; | 549 break; |
| 460 } | 550 } |
| 461 } | 551 } |
| 552 | |
| 553 | |
| 554 /*These handlers are special -- they don't belong to a language, because they | |
| 555 * deal with things internal to PR, so put them here.. | |
| 556 */ | |
| 557 inline | |
| 558 void | |
| 559 handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) | |
| 560 { IntervalProbe *newProbe; | |
| 561 | |
| 562 newProbe = PR_int__malloc( sizeof(IntervalProbe) ); | |
| 563 newProbe->nameStr = PR_int__strDup( langReq->nameStr ); | |
| 564 newProbe->hist = NULL; | |
| 565 newProbe->schedChoiceWasRecorded = FALSE; | |
| 566 | |
| 567 //This runs in masterVP, so no race-condition worries | |
| 568 //BUG: move to process | |
| 569 newProbe->probeID = | |
| 570 addToDynArray( newProbe, _PRTopEnv->dynIntervalProbesInfo ); | |
| 571 | |
| 572 langReq->requestingSlv->dataRetFromReq = newProbe; | |
| 573 | |
| 574 (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); | |
| 575 } | |
| 576 | |
| 577 inline | |
| 578 void | |
| 579 handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) | |
| 580 { | |
| 581 PR_int__throw_exception( langReq->msgStr, langReq->requestingSlv, langReq->exceptionData ); | |
| 582 | |
| 583 (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); | |
| 584 } | |
| 585 |
