Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
changeset 273:40e7625e57bd Dev_ML
Compiles and runs, up to end of process, working on end process and shutdown
line diff
1.1 --- a/AnimationMaster.c Tue Feb 05 20:23:27 2013 -0800 1.2 +++ b/AnimationMaster.c Sat Mar 02 09:43:45 2013 -0800 1.3 @@ -12,23 +12,30 @@ 1.4 #include "PR.h" 1.5 #include "VSs_impl/VSs.h" 1.6 1.7 -/* 1.8 -void PRHandle_CreateTask_SL(SlaveVP *slave); 1.9 +//========================= Local Declarations ======================== 1.10 +inline PRProcess * 1.11 +pickAProcess( AnimSlot *slot ); 1.12 +inline bool32 1.13 +assignWork( PRProcess *process, AnimSlot *slot ); 1.14 1.15 -void PRHandle_CreateSlave_SL(SlaveVP *slave); 1.16 -void PRHandle_Dissipate_SL(SlaveVP *slave); 1.17 -void PR_int__handle_PRServiceReq_SL(SlaveVP *slave); 1.18 -*/ 1.19 -inline void PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); 1.20 -inline void PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); 1.21 -inline void PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); 1.22 -void PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); 1.23 +inline void 1.24 +PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); 1.25 +inline void 1.26 +PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); 1.27 +inline void 1.28 +PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); 1.29 +inline void 1.30 +PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); 1.31 1.32 +inline void 1.33 +PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ); 1.34 1.35 -//inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot ); 1.36 -inline PRProcess * pickAProcess( AnimSlot *slot ); 1.37 -inline bool32 assignWork( PRProcess *process, AnimSlot *slot ); 1.38 +inline void 1.39 +handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); 1.40 +inline void 1.41 +handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); 1.42 1.43 +//=========================================================================== 1.44 1.45 /*Note: there used to be a coreController that was another animation 1.46 * layer below both the masterVP and the slaveVPs.. in that case, the 1.47 @@ -59,7 +66,7 @@ 1.48 PRLangEnv *langEnv; 1.49 PRReqst *req; 1.50 PRProcess *process; 1.51 - bool32 foundWork; 1.52 + bool32 didAssignWork; 1.53 1.54 //Check if newly-done slave in slot, which will need request handled 1.55 //NOTE: left over from when had a coreController & MasterVP managed 1.56 @@ -67,53 +74,58 @@ 1.57 if( slot->workIsDone ) 1.58 { slot->workIsDone = FALSE; 1.59 slot->needsWorkAssigned = TRUE; 1.60 + 1.61 + //An Idle VP has no request to handle, so skip to assign.. 1.62 + if( slot->slaveAssignedToSlot->typeOfVP != IdleVP ) 1.63 + { 1.64 + HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot 1.65 + MEAS__startReqHdlr; 1.66 1.67 - HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot 1.68 - MEAS__startReqHdlr; 1.69 1.70 + //process the request made by the slave (held inside slave struc) 1.71 + slave = slot->slaveAssignedToSlot; 1.72 + req = slave->request; 1.73 1.74 - //process the request made by the slave (held inside slave struc) 1.75 - slave = slot->slaveAssignedToSlot; 1.76 - req = slave->request; 1.77 + //If the requesting slave is a slot slave, and request is not 1.78 + // task-end, then turn it into a free task slave & continue 1.79 + if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) 1.80 + PR_int__replace_with_new_slot_slv( slave ); 1.81 1.82 - //If the requesting slave is a slot slave, and request is not 1.83 - // task-end, then turn it into a free task slave. 1.84 - if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) 1.85 - PR_int__replace_with_new_slot_slv( slave ); 1.86 - 1.87 - //Handle task create and end first -- they're special cases.. 1.88 - switch( req->reqType ) 1.89 - { case TaskEnd: 1.90 - { //do PR handler, which calls lang's hdlr and does recycle of 1.91 - // free task slave if needed -- PR handler checks for free task Slv 1.92 - PRHandle__EndTask( req, slave ); break; 1.93 + //Handle task create and end first -- they're special cases.. 1.94 + switch( req->reqType ) 1.95 + { case TaskEnd: 1.96 + { //do PR handler, which calls lang's hdlr and does recycle of 1.97 + // free task slave if needed -- PR handler checks for free task Slv 1.98 + PRHandle__EndTask( req, slave ); break; 1.99 + } 1.100 + case TaskCreate: 1.101 + { //Do PR's create-task handler, which calls the lang's hdlr 1.102 + // PR handler checks for free task Slv 1.103 + PRHandle__CreateTask( req, slave ); break; 1.104 + } 1.105 + case SlvCreate: PRHandle__CreateSlave( req, slave ); break; 1.106 + case SlvDissipate: PRHandle__EndSlave( req, slave ); break; 1.107 + case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env 1.108 + case Hardware: //for future expansion 1.109 + case IO: //for future expansion 1.110 + case OSCall: //for future expansion 1.111 + PR_int__throw_exception("Not implemented", slave, NULL); break; 1.112 + case LangShutdown: PRHandle__LangShutdown( req, slave ); break; 1.113 + case Language: //normal lang request 1.114 + { magicNumber = req->langMagicNumber; 1.115 + langEnv = PR_PI__give_lang_env_for_slave( slave, magicNumber ); 1.116 + (*req->handler)( req->langReq, slave, langEnv ); 1.117 + } 1.118 } 1.119 - case TaskCreate: 1.120 - { //Do PR's create-task handler, which calls the lang's hdlr 1.121 - // PR handler checks for free task Slv 1.122 - PRHandle__CreateTask( req, slave ); break; 1.123 - } 1.124 - case SlvCreate: PRHandle__CreateSlave( req, slave ); break; 1.125 - case SlvDissipate: PRHandle__EndSlave( req, slave ); break; 1.126 - case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env 1.127 - case Hardware: //for future expansion 1.128 - case IO: //for future expansion 1.129 - case OSCall: //for future expansion 1.130 - PR_int__throw_exception("Not implemented", slave, NULL); break; 1.131 - case Language: //normal lang request 1.132 - { magicNumber = req->langMagicNumber; 1.133 - langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); 1.134 - (*req->handler)( req->langReq, slave, langEnv ); 1.135 - } 1.136 - } 1.137 - 1.138 + 1.139 MEAS__endReqHdlr; 1.140 HOLISTIC__Record_AppResponder_end; 1.141 + }//if not idleVP 1.142 } //if have request to be handled 1.143 1.144 //NOTE: IF statement is leftover from when master managed many slots 1.145 - foundWork = FALSE; 1.146 - if( slot->needsWorkAssigned ) //can probably remove IF, not that only one slot 1.147 + didAssignWork = FALSE; 1.148 + if( slot->needsWorkAssigned ) //can probably remove IF, now that only one slot 1.149 { 1.150 HOLISTIC__Record_Assigner_start; 1.151 1.152 @@ -122,15 +134,19 @@ 1.153 1.154 //Scan lang environs, looking for langEnv with ready work. 1.155 // call the Assigner for that lang Env, to get a slave for the slot 1.156 - foundWork = 1.157 - assignWork( process, slot ); 1.158 - 1.159 + if( process != NULL ) 1.160 + { didAssignWork = 1.161 + assignWork( process, slot ); 1.162 + } 1.163 HOLISTIC__Record_Assigner_end; 1.164 1.165 -// fixme; //make this a while loop that tries a different process if this one fails 1.166 + if( !didAssignWork ) //if no work assigned, be sure idle slave is in slot 1.167 + { slot->slaveAssignedToSlot = _PRTopEnv->idleSlv[slot->coreSlotIsOn][0]; 1.168 + } 1.169 +// fixme; //make into a loop that tries more processes if fails to assign 1.170 }//if slot needs slave assigned 1.171 1.172 - return foundWork; 1.173 + return didAssignWork; 1.174 } 1.175 1.176 /*When several processes exist, use some pattern for picking one to give 1.177 @@ -201,19 +217,19 @@ 1.178 } 1.179 1.180 //If here, then no override assigner, so search language envs for work 1.181 - int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv; 1.182 - langEnvsList = process->langEnvsList; 1.183 + int32 envIdx, numEnvs; PRLangEnv **protoLangEnvsList, *protoLangEnv; 1.184 + protoLangEnvsList = process->protoLangEnvsList; 1.185 numEnvs = process->numLangEnvs; 1.186 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array 1.187 - { langEnv = langEnvsList[envIdx]; 1.188 - if( langEnv->numReadyWork > 0 ) 1.189 + { protoLangEnv = protoLangEnvsList[envIdx]; 1.190 + if( protoLangEnv->numReadyWork > 0 ) 1.191 { bool32 1.192 didAssignWork = 1.193 - (*langEnv->workAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot 1.194 + (*protoLangEnv->workAssigner)( PR_int__give_lang_env(protoLangEnv), slot ); //assigner calls PR to put slave/task into slot 1.195 1.196 if(didAssignWork) 1.197 - { langEnv->numReadyWork -= 1; 1.198 - if( langEnv->numReadyWork == 0 ) 1.199 + { protoLangEnv->numReadyWork -= 1; 1.200 + if( protoLangEnv->numReadyWork == 0 ) 1.201 { process->numEnvsWithWork -= 1; 1.202 } 1.203 goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work 1.204 @@ -260,6 +276,124 @@ 1.205 } 1.206 1.207 1.208 +//================================= 1.209 +//=== 1.210 +//= 1.211 +/*Create task is a special form, that has PR behavior in addition to plugin 1.212 + * behavior. Master calls this first, and it then calls the plugin's 1.213 + * create task handler. 1.214 + * 1.215 + *Note: the requesting slave must be either generic slave or free task slave 1.216 + */ 1.217 +inline 1.218 +void 1.219 +PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) 1.220 + { PRMetaTask *protoMetaTask; 1.221 + PRProcess *process; 1.222 + PRLangEnv *protoLangEnv; 1.223 + void *task; 1.224 + 1.225 + process = slave->processSlaveIsIn; 1.226 + 1.227 + protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, 1.228 + req->langMagicNumber ); 1.229 + 1.230 + //Do the langlet's create-task handler, which keeps the task 1.231 + // inside the langlet's lang env, but returns the langMetaTask 1.232 + // so that PR can then put stuff into the prolog 1.233 + //typedef void * (*CreateHandler)( void *, SlaveVP *, void * ); //req, slv, langEnv 1.234 + // 1.235 + task = 1.236 + (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); 1.237 + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( task ); 1.238 + protoMetaTask->ID = req->ID; //may be NULL 1.239 + protoMetaTask->topLevelFn = req->topLevelFn; 1.240 + protoMetaTask->initData = req->initData; 1.241 + protoMetaTask->processTaskIsIn = process; 1.242 + 1.243 + process->numLiveTasks += 1; 1.244 + protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead 1.245 + 1.246 + return; 1.247 + } 1.248 + 1.249 +/*When a task ends, have two scenarios: 1) task ran to completion, or 2) task 1.250 + * has been suspended at some point in its code. 1.251 + *For 1, just decr count of live tasks (and check for end condition) -- the 1.252 + * master loop will decide what goes into the slot freed up by this task end, 1.253 + * so, here, don't worry about assigning a new task to the slot slave. 1.254 + *For 2, the task's slot slave has been converted to a free task slave, which 1.255 + * now has nothing more to do, so send it to the recycle Q (which includes 1.256 + * freeing all the langData and meta task structs alloc'd for it). Then 1.257 + * decrement the live task count and check end condition. 1.258 + * 1.259 + *PR has to update count of live tasks, and check end of process condition. 1.260 + * The "main" can invoke constructs that wait for a process to end, so when 1.261 + * end detected, have to resume what's waiting.. 1.262 + *Thing is, that wait involves the main OS thread. That means 1.263 + * PR internals have to do OS thread signaling. Want to do that in the 1.264 + * core controller, which has the original stack of an OS thread. So the 1.265 + * end process handling happens in the core controller. 1.266 + * 1.267 + *So here, when detect process end, signal to the core controller, which will 1.268 + * then do the condition variable notify to the OS thread that's waiting. 1.269 + * 1.270 + *Note: slave may be either a slot slave or a free task slave. 1.271 + */ 1.272 +inline 1.273 +void 1.274 +PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) 1.275 + { void *langEnv; 1.276 + PRLangEnv *protoLangEnv; 1.277 + PRProcess *process; 1.278 + void *langMetaTask; 1.279 + 1.280 + process = requestingSlv->processSlaveIsIn; 1.281 + langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req 1.282 + protoLangEnv = PR_int__give_proto_lang_env( langEnv ); 1.283 + 1.284 + langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); 1.285 + 1.286 + //Do the langlet's request handler 1.287 + //Want to keep PR structs hidden from plugin, so extract langReq.. 1.288 + //This is supposed to free any langlet-malloc'd mem, including meta task 1.289 + (*req->handler)( req->langReq, requestingSlv, langEnv ); 1.290 + 1.291 + protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead 1.292 + if( protoLangEnv->numLiveWork == 0 && 1.293 + numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) 1.294 + { SlaveVP * 1.295 + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); 1.296 + //can't resume into langlet that just ended its last work! 1.297 + // and don't have env that the waiter was created in, so resume 1.298 + // into PRServ env.. 1.299 + void * 1.300 + resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); 1.301 + while( waitingSlave != NULL ) 1.302 + { //resume a slave that was waiting for work in this env to finish 1.303 + PR_PI__make_slave_ready( waitingSlave, resumeEnv ); 1.304 + //get next waiting slave, repeat.. 1.305 + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); 1.306 + } 1.307 + } 1.308 + 1.309 + 1.310 + //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv 1.311 + if( requestingSlv->typeOfVP == FreeTaskSlv ) 1.312 + PR_int__recycle_slaveVP( requestingSlv ); //Doesn't decr num live slaves 1.313 + 1.314 + process->numLiveTasks -= 1; 1.315 + //NOTE: end-task is unrelated to work available (just in case wondering) 1.316 + 1.317 + //check End Of Process Condition 1.318 + if( process->numLiveTasks == 0 && 1.319 + process->numLiveGenericSlvs == 0 ) 1.320 + { //Tell the core controller to do wakeup of any waiting OS thread 1.321 + PR_SS__end_process_normally( process ); 1.322 + } 1.323 + } 1.324 + 1.325 + 1.326 1.327 /*This is first thing called when creating a slave.. it hands off to the 1.328 * langlet's creator, then adds updates of its own.. 1.329 @@ -293,7 +427,7 @@ 1.330 PRLangEnv *protoLangEnv; 1.331 1.332 process = slave->processSlaveIsIn; 1.333 - protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber ); 1.334 + protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, req->langMagicNumber ); 1.335 1.336 //create handler, or a future request handler will call PR_PI__make_slave_ready 1.337 // which will in turn handle updating which langlets and which processes have 1.338 @@ -306,6 +440,7 @@ 1.339 newSlv->processSlaveIsIn = process; 1.340 newSlv->ID = req->ID; 1.341 process->numLiveGenericSlvs += 1; //not same as work ready! 1.342 + protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead 1.343 } 1.344 1.345 /*The dissipate handler has to, update the number of slaves of the type, within 1.346 @@ -327,105 +462,60 @@ 1.347 process = slave->processSlaveIsIn; 1.348 1.349 //do the language's dissipate handler 1.350 - protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber ); 1.351 + protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, slave->request->langMagicNumber ); 1.352 1.353 if(req->handler != NULL) 1.354 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); 1.355 1.356 + protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead 1.357 + if( protoLangEnv->numLiveWork == 0 && 1.358 + numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) 1.359 + { SlaveVP * 1.360 + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); 1.361 + //can't resume into langlet that just ended its last work! 1.362 + // and don't have env that the waiter was created in, so resume 1.363 + // into PRServ env.. 1.364 + void * 1.365 + resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); 1.366 + while( waitingSlave != NULL ) 1.367 + { //resume a slave that was waiting for work in this env to finish 1.368 + PR_PI__make_slave_ready( waitingSlave, resumeEnv ); 1.369 + //get next waiting slave, repeat.. 1.370 + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); 1.371 + } 1.372 + } 1.373 + 1.374 process->numLiveGenericSlvs -= 1; 1.375 - PR_int__recycle_slave( slave ); 1.376 + PR_int__recycle_slaveVP( slave ); 1.377 //NOTE: dissipate is unrelated to work available (just in case wondering) 1.378 1.379 //check End Of Process Condition 1.380 if( process->numLiveTasks == 0 && 1.381 process->numLiveGenericSlvs == 0 ) 1.382 - PR_SS__shutdown_process( process ); 1.383 + PR_SS__end_process_normally( process ); 1.384 } 1.385 1.386 -/*Create task is a special form, that has PR behavior in addition to plugin 1.387 - * behavior. Master calls this first, and it then calls the plugin's 1.388 - * create task handler. 1.389 - * 1.390 - *Note: the requesting slave must be either generic slave or free task slave 1.391 +//======================= 1.392 +//=== 1.393 +//= 1.394 +/*Langlet shutdown triggers this, which calls the registered shutdown 1.395 + * handler for the langlet, and removes the lang's env from the process 1.396 */ 1.397 inline 1.398 void 1.399 -PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) 1.400 - { PRMetaTask *metaTask; 1.401 - PRProcess *process; 1.402 - PRLangEnv *protoLangEnv; 1.403 - void *task; 1.404 - 1.405 - process = slave->processSlaveIsIn; 1.406 +PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ) 1.407 + { void *langEnv; 1.408 + PRLangEnv *protoLangEnv; 1.409 + PRProcess *process; 1.410 1.411 - protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, 1.412 - req->langMagicNumber ); 1.413 + process = requestingSlv->processSlaveIsIn; 1.414 + protoLangEnv = PR_int__give_proto_lang_env_from_process( process, req->langMagicNumber ); 1.415 + langEnv = PR_int__give_lang_env( protoLangEnv ); 1.416 1.417 - //Do the langlet's create-task handler, which keeps the task 1.418 - // inside the langlet's lang env, but returns the langMetaTask 1.419 - // so PR can put stuff into the prolog 1.420 - task = 1.421 - (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); 1.422 - metaTask = PR_int__give_prolog_of_task( task ); 1.423 - metaTask->ID = req->ID; //may be NULL 1.424 - metaTask->topLevelFn = req->topLevelFn; 1.425 - metaTask->initData = req->initData; 1.426 - 1.427 - process->numLiveTasks += 1; 1.428 - 1.429 - return; 1.430 - } 1.431 - 1.432 -/*When a task ends, have two scenarios: 1) task ran to completion, or 2) task 1.433 - * has been suspended at some point in its code. 1.434 - *For 1, just decr count of live tasks (and check for end condition) -- the 1.435 - * master loop will decide what goes into the slot freed up by this task end, 1.436 - * so, here, don't worry about assigning a new task to the slot slave. 1.437 - *For 2, the task's slot slave has been converted to a free task slave, which 1.438 - * now has nothing more to do, so send it to the recycle Q (which includes 1.439 - * freeing all the langData and meta task structs alloc'd for it). Then 1.440 - * decrement the live task count and check end condition. 1.441 - * 1.442 - *PR has to update count of live tasks, and check end of process condition. 1.443 - * The "main" can invoke constructs that wait for a process to end, so when 1.444 - * end detected, have to resume what's waiting.. 1.445 - *Thing is, that wait involves the main OS thread. That means 1.446 - * PR internals have to do OS thread signaling. Want to do that in the 1.447 - * core controller, which has the original stack of an OS thread. So the 1.448 - * end process handling happens in the core controller. 1.449 - * 1.450 - *So here, when detect process end, signal to the core controller, which will 1.451 - * then do the condition variable notify to the OS thread that's waiting. 1.452 - * 1.453 - *Note: slave may be either a slot slave or a free task slave. 1.454 - */ 1.455 -inline 1.456 -void 1.457 -PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) 1.458 - { void *langEnv; 1.459 - PRProcess *process; 1.460 - void *langMetaTask; 1.461 + //call the langlet's registered handler 1.462 + (*protoLangEnv->shutdownHdlr)( langEnv ); 1.463 1.464 - langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req 1.465 - langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); 1.466 - 1.467 - //Do the langlet's request handler 1.468 - //Want to keep PR structs hidden from plugin, so extract langReq.. 1.469 - (*req->handler)( req->langReq, requestingSlv, langEnv ); 1.470 - 1.471 - //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv 1.472 - if( requestingSlv->typeOfVP == FreeTaskSlv ) 1.473 - PR_int__recycle_slave( requestingSlv ); //Doesn't decr num live slaves 1.474 - 1.475 - process->numLiveTasks -= 1; 1.476 - //NOTE: end-task is unrelated to work available (just in case wondering) 1.477 - 1.478 - //check End Of Process Condition 1.479 - if( process->numLiveTasks == 0 && 1.480 - process->numLiveGenericSlvs == 0 ) 1.481 - { //Tell the core controller to do wakeup of any waiting OS thread 1.482 - PR_SS__shutdown_process( process ); 1.483 - } 1.484 + PR_int__remove_lang_env_from_process_and_free( langEnv ); //removes from process and frees 1.485 } 1.486 1.487 1.488 @@ -438,24 +528,58 @@ 1.489 */ 1.490 void inline 1.491 PRHandle__ServiceReq( SlaveVP *requestingSlv ) 1.492 - { PRReqst *req; 1.493 - PRServReq *langReq; 1.494 - void *langEnv; 1.495 - int32 magicNumber; 1.496 + { PRReqst *req; 1.497 + PRServiceReq *langReq; 1.498 + PRLangEnv *protoLangEnv; 1.499 + int32 magicNumber; 1.500 1.501 1.502 req = requestingSlv->request; 1.503 1.504 magicNumber = req->langMagicNumber; 1.505 - langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); 1.506 + protoLangEnv = PR_int__give_proto_lang_env_for_slave( requestingSlv, magicNumber ); 1.507 1.508 langReq = PR_PI__take_lang_reqst_from(req); 1.509 if( langReq == NULL ) return; 1.510 switch( langReq->reqType ) //lang handlers are all in other file 1.511 { 1.512 - case make_probe: handleMakeProbe( langReq, langEnv ); 1.513 + case make_probe: handleMakeProbe( langReq, protoLangEnv ); 1.514 break; 1.515 - case throw_excp: handleThrowException( langReq, langEnv ); 1.516 + case throw_excp: handleThrowException( langReq, protoLangEnv ); 1.517 break; 1.518 } 1.519 } 1.520 + 1.521 + 1.522 +/*These handlers are special -- they don't belong to a language, because they 1.523 + * deal with things internal to PR, so put them here.. 1.524 + */ 1.525 +inline 1.526 +void 1.527 +handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) 1.528 + { IntervalProbe *newProbe; 1.529 + 1.530 + newProbe = PR_int__malloc( sizeof(IntervalProbe) ); 1.531 + newProbe->nameStr = PR_int__strDup( langReq->nameStr ); 1.532 + newProbe->hist = NULL; 1.533 + newProbe->schedChoiceWasRecorded = FALSE; 1.534 + 1.535 + //This runs in masterVP, so no race-condition worries 1.536 + //BUG: move to process 1.537 + newProbe->probeID = 1.538 + addToDynArray( newProbe, _PRTopEnv->dynIntervalProbesInfo ); 1.539 + 1.540 + langReq->requestingSlv->dataRetFromReq = newProbe; 1.541 + 1.542 + (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); 1.543 + } 1.544 + 1.545 +inline 1.546 +void 1.547 +handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) 1.548 + { 1.549 + PR_int__throw_exception( langReq->msgStr, langReq->requestingSlv, langReq->exceptionData ); 1.550 + 1.551 + (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); 1.552 + } 1.553 +
2.1 --- a/CoreController.c Tue Feb 05 20:23:27 2013 -0800 2.2 +++ b/CoreController.c Sat Mar 02 09:43:45 2013 -0800 2.3 @@ -74,7 +74,7 @@ 2.4 bool32 foundWork; 2.5 AnimSlot *animSlot; 2.6 volatile int32 *addrOfMasterLock; //thing pointed to is volatile, not ptr 2.7 - SlaveVP *thisCoresMasterVP; 2.8 +// SlaveVP *thisCoresMasterVP; 2.9 //Variables used for pthread related things 2.10 ThdParams *thisCoresThdParams; 2.11 cpu_set_t coreMask; //used during pinning pthread to CPU core 2.12 @@ -95,9 +95,11 @@ 2.13 2.14 //TODO: DEBUG: check get correct pointer here 2.15 animSlot = _PRTopEnv->allAnimSlots[ thisCoresIdx ][0]; 2.16 + animSlot->slaveAssignedToSlot = _PRTopEnv->idleSlv[thisCoresIdx][ZERO]; 2.17 + 2.18 numRepetitionsWithNoWork = 0; 2.19 addrOfMasterLock = &(_PRTopEnv->masterLock); 2.20 - thisCoresMasterVP = _PRTopEnv->masterVPs[ thisCoresIdx ]; 2.21 +// thisCoresMasterVP = _PRTopEnv->masterVPs[ thisCoresIdx ]; 2.22 2.23 //==================== pthread related stuff ====================== 2.24 //pin the pthread to the core -- takes away Linux control 2.25 @@ -135,7 +137,7 @@ 2.26 //Alternatively, the VP suspend primitive could just not bother 2.27 // returning from switchToSlv, and instead jmp directly to here. 2.28 2.29 - if(animSlot->slaveAssignedToSlot->typeOfVP == Idle) 2.30 + if(animSlot->slaveAssignedToSlot->typeOfVP == IdleVP) 2.31 { //The Holistic stuff turns on idle slaves.. but can also be in mode 2.32 // where have no idle slaves.. so, this IF statement can only be true 2.33 // executed when HOLISTIC is turned on.. 2.34 @@ -212,7 +214,7 @@ 2.35 terminateCoreCtlr(SlaveVP *currSlv) 2.36 { 2.37 //first, free shutdown Slv that jumped here, then end the pthread 2.38 - PR_int__dissipate_slaveVP__SL( currSlv ); 2.39 + PR_int__recycle_slaveVP( currSlv ); 2.40 pthread_exit( NULL ); 2.41 } 2.42 2.43 @@ -275,60 +277,141 @@ 2.44 */ 2.45 void * 2.46 coreCtlr_Seq( void *paramsIn ) 2.47 - { 2.48 + { 2.49 int32 thisCoresIdx; 2.50 int32 numRepetitionsWithNoWork; 2.51 - SlaveVP *currVP; 2.52 - AnimSlot *currSlot, **animSlots; 2.53 - int32 currSlotIdx; 2.54 - int32 *addrOfMasterLock; 2.55 - SlaveVP *thisCoresMasterVP; 2.56 + bool32 foundWork; 2.57 + AnimSlot *animSlot; 2.58 + volatile int32 *addrOfMasterLock; //thing pointed to is volatile, not ptr 2.59 + //Variables used for pthread related things 2.60 + ThdParams *thisCoresThdParams; 2.61 + cpu_set_t coreMask; //used during pinning pthread to CPU core 2.62 + int32 errorCode; 2.63 + //Variables used during measurements (inside macro!) 2.64 + TSCountLowHigh endSusp; 2.65 + //Variables used in random-backoff, for master-lock and waiting for work 2.66 + uint32_t seed1 = rand()%1000; // init random number generator for backoffs 2.67 + uint32_t seed2 = rand()%1000; 2.68 + 2.69 2.70 //=============== Initializations =================== 2.71 - thisCoresIdx = 0; //sequential version 2.72 - animSlots = _PRTopEnv->allAnimSlots[thisCoresIdx]; 2.73 - currSlotIdx = 0; //start at slot 0, go up until one empty, then do master 2.74 +// thisCoresThdParams = (ThdParams *)paramsIn; 2.75 +// thisCoresIdx = thisCoresThdParams->coreNum; 2.76 + thisCoresIdx = 0; 2.77 + 2.78 + //Assembly that saves addr of label of return instr -- addr used in assmbly 2.79 + recordCoreCtlrReturnLabelAddr((void**)&(_PRTopEnv->coreCtlrReturnPt)); 2.80 + 2.81 + //TODO: DEBUG: check get correct pointer here 2.82 + animSlot = _PRTopEnv->allAnimSlots[ thisCoresIdx ][0]; 2.83 + animSlot->slaveAssignedToSlot = _PRTopEnv->idleSlv[thisCoresIdx][ZERO]; 2.84 + 2.85 numRepetitionsWithNoWork = 0; 2.86 addrOfMasterLock = &(_PRTopEnv->masterLock); 2.87 - thisCoresMasterVP = _PRTopEnv->masterVPs[thisCoresIdx]; 2.88 2.89 - //Assembly that saves addr of label of return instr -- label in assmbly 2.90 - recordCoreCtlrReturnLabelAddr((void**)&(_PRTopEnv->coreCtlrReturnPt)); 2.91 + //==================== pthread related stuff ====================== 2.92 + //pin the pthread to the core -- takes away Linux control 2.93 + //Linux requires pinning to be done inside the thread-function 2.94 + //Designate a core by a 1 in bit-position corresponding to the core 2.95 +/* 2.96 + CPU_ZERO(&coreMask); //initialize mask bits to zero 2.97 + CPU_SET(thisCoresThdParams->coreNum,&coreMask); //set bit repr the coreNum 2.98 + pthread_t selfThd = pthread_self(); 2.99 + errorCode = 2.100 + pthread_setaffinity_np( selfThd, sizeof(coreMask), &coreMask); 2.101 + if(errorCode){ printf("\n pinning thd to core failed \n"); exit(0); } 2.102 2.103 + //make sure the controllers all start at same time, by making them wait 2.104 + pthread_mutex_lock( &suspendLock ); 2.105 + while( !(_PRTopEnv->firstProcessReady) ) 2.106 + { pthread_cond_wait( &suspendCond, &suspendLock ); 2.107 + } 2.108 + pthread_mutex_unlock( &suspendLock ); 2.109 2.110 + HOLISTIC__CoreCtrl_Setup; 2.111 + 2.112 + DEBUG__printf1(TRUE, "started coreCtrlr", thisCoresIdx ); 2.113 + */ 2.114 //====================== The Core Controller ====================== 2.115 - while(1) 2.116 - { 2.117 - if( currSlotIdx >= NUM_ANIM_SLOTS ) goto switchToMaster; 2.118 - currSlot = animSlots[ currSlotIdx ]; 2.119 + while(1) 2.120 + { //Assembly code switches the core between animating a VP and 2.121 + // animating this core controller. The switch is done by 2.122 + // changing the stack-pointer and frame-pointer and then doing 2.123 + // an assembly jmp. When reading this code, the effect is 2.124 + // that the "switchToSlv()" at the end of the loop is sort of a 2.125 + // "warp in time" -- the core disappears inside this, jmps to 2.126 + // animating a VP, and when that VP suspends, the suspend 2.127 + // jmps back. This has the effect of "returning" from the 2.128 + // switchToSlv() call. Then control loops back to here. 2.129 + //Alternatively, the VP suspend primitive could just not bother 2.130 + // returning from switchToSlv, and instead jmp directly to here. 2.131 + //core controller top of loop 2.132 + if(animSlot->slaveAssignedToSlot->typeOfVP == IdleVP) 2.133 + { //The Holistic stuff turns on idle slaves.. but can also be in mode 2.134 + // where have no idle slaves.. so, this IF statement can only be true 2.135 + // executed when HOLISTIC is turned on.. 2.136 + numRepetitionsWithNoWork ++; 2.137 + HOLISTIC__Record_last_work; 2.138 + } 2.139 + 2.140 2.141 - if( ! currSlot->needsSlaveAssigned ) //slot does have slave assigned 2.142 - { numRepetitionsWithNoWork = 0; //reset B2B master count 2.143 - currSlotIdx ++; 2.144 - currVP = currSlot->slaveAssignedToSlot; 2.145 - } 2.146 - else //slot is empty, so switch to master 2.147 - { 2.148 - switchToMaster: 2.149 - currSlotIdx = 0; //doing switch to master, so start over at slot 0 2.150 + 2.151 + HOLISTIC__Record_AppResponderInvocation_start; 2.152 + MEAS__Capture_Pre_Master_Lock_Point; 2.153 + 2.154 + int numTriesToGetLock = 0; int gotLock = 0; 2.155 + while( gotLock == FALSE ) //keep going until get master lock 2.156 + { 2.157 + //want to 2.158 + // reduce lock contention from cores with no work, so first 2.159 + // check if this is a core with no work, and busy wait if so. 2.160 + //Then, if it's been way too long without work, yield pthread 2.161 + if( numRepetitionsWithNoWork > NUM_REPS_W_NO_WORK_BEFORE_BACKOFF) 2.162 + doBackoff_for_TooLongWithNoWork( numRepetitionsWithNoWork, &seed1, &seed2 ); 2.163 + if( numRepetitionsWithNoWork > NUM_REPS_W_NO_WORK_BEFORE_YIELD ) 2.164 + { numRepetitionsWithNoWork = 0; pthread_yield(); } 2.165 + 2.166 + 2.167 + //Try to get the lock 2.168 + gotLock = __sync_bool_compare_and_swap( addrOfMasterLock, 2.169 + UNLOCKED, LOCKED ); 2.170 + if( gotLock ) 2.171 + { //At this point, have successfully gotten master lock. 2.172 + //So, break out of get-lock loop. 2.173 + break; 2.174 + } 2.175 + //Get here only when failed to get lock -- check in should do backoff 2.176 + 2.177 + numTriesToGetLock++; //if too many, means too much contention 2.178 + if( numTriesToGetLock > NUM_TRIES_BEFORE_DO_BACKOFF ) 2.179 + doBackoff_for_TooLongToGetLock( numTriesToGetLock, &seed1, &seed2 ); 2.180 + if( numTriesToGetLock > MASTERLOCK_RETRIES_BEFORE_YIELD ) 2.181 + { numTriesToGetLock = 0; pthread_yield(); } 2.182 + } //while( currVP == NULL ) 2.183 + MEAS__Capture_Post_Master_Lock_Point; 2.184 + 2.185 + //have master lock, perform master function, which manages request 2.186 + // handling and assigning work to this core's slot 2.187 + foundWork = 2.188 2.189 - currVP = thisCoresMasterVP; 2.190 - 2.191 - MEAS__Capture_Pre_Master_Lock_Point; //back to back because 2.192 - MEAS__Capture_Post_Master_Lock_Point; // sequential version 2.193 - 2.194 - if( numRepetitionsWithNoWork > NUM_REPS_W_NO_WORK_BEFORE_YIELD ) 2.195 - { printf("Lots of reps w/o work\n"); 2.196 - exit(0); //if no work, no way to ever get it in sequential! 2.197 - } 2.198 + masterFunction( animSlot ); 2.199 + 2.200 + PR_int__release_master_lock(); 2.201 + 2.202 + if( foundWork ) 2.203 + numRepetitionsWithNoWork = 0; 2.204 + else 2.205 numRepetitionsWithNoWork += 1; 2.206 - } 2.207 2.208 - switchToSlv(currVP); //Slave suspend makes core "return" from this call 2.209 + //now that master is done, have work in the slot, so switch to it 2.210 + HOLISTIC__Record_Work_start; 2.211 + 2.212 + switchToSlv(animSlot->slaveAssignedToSlot); //Slave suspend makes core "return" from this call 2.213 flushRegisters(); //prevent GCC optimization from doing bad things 2.214 2.215 MEAS__Capture_End_Susp_in_CoreCtlr_ForSys; 2.216 - 2.217 - } //while(1) 2.218 + HOLISTIC__Record_Work_end; 2.219 + }//while(1) 2.220 } 2.221 + 2.222 #endif
3.1 --- a/Defines/MEAS__macros_to_be_moved_to_langs.h Tue Feb 05 20:23:27 2013 -0800 3.2 +++ b/Defines/MEAS__macros_to_be_moved_to_langs.h Sat Mar 02 09:43:45 2013 -0800 3.3 @@ -22,30 +22,37 @@ 3.4 3.5 #ifdef VCILK 3.6 3.7 +/*These defines are used in the macros below*/ 3.8 #define spawnHistIdx 1 //note: starts at 1 3.9 #define syncHistIdx 2 3.10 3.11 -#define MEAS__Make_Meas_Hists_for_Language() \ 3.12 - _PRTopEnv->measHistsInfo = \ 3.13 +#define MEAS__Make_Meas_Hists_for_VCilk( slave, magicNum ) \ 3.14 + do \ 3.15 + { VCilkLangEnv * \ 3.16 + langEnv = PR_PI__get_lang_env_from_slave( slave, magicNum ); \ 3.17 + langEnv->measHistsInfo = \ 3.18 makePrivDynArrayOfSize( (void***)&(_PRTopEnv->measHists), 200); \ 3.19 - makeAMeasHist( spawnHistIdx, "Spawn", 50, 0, 200 ) \ 3.20 - makeAMeasHist( syncHistIdx, "Sync", 50, 0, 200 ) 3.21 + histInfo = langEnv->measHistsInfo; 3.22 + makeAMeasHist( histInfo, spawnHistIdx, "Spawn", 50, 0, 200 ) \ 3.23 + makeAMeasHist( histInfo, syncHistIdx, "Sync", 50, 0, 200 ) \ 3.24 + }while(FALSE); /* macro magic to protect local vars from name collision */ 3.25 3.26 - 3.27 -#define Meas_startSpawn \ 3.28 +#define Meas_startSpawn fixme; /* changed names -- added __Cilk to end*/ 3.29 + 3.30 +#define Meas_startSpawn__Cilk \ 3.31 int32 startStamp, endStamp; \ 3.32 saveLowTimeStampCountInto( startStamp ); \ 3.33 3.34 -#define Meas_endSpawn \ 3.35 +#define Meas_endSpawn__Cilk \ 3.36 saveLowTimeStampCountInto( endStamp ); \ 3.37 addIntervalToHist( startStamp, endStamp, \ 3.38 _PRTopEnv->measHists[ spawnHistIdx ] ); 3.39 3.40 -#define Meas_startSync \ 3.41 +#define Meas_startSync__Cilk \ 3.42 int32 startStamp, endStamp; \ 3.43 saveLowTimeStampCountInto( startStamp ); \ 3.44 3.45 -#define Meas_endSync \ 3.46 +#define Meas_endSync__Cilk \ 3.47 saveLowTimeStampCountInto( endStamp ); \ 3.48 addIntervalToHist( startStamp, endStamp, \ 3.49 _PRTopEnv->measHists[ syncHistIdx ] );
4.1 --- a/HW_Dependent_Primitives/PR__primitives.h Tue Feb 05 20:23:27 2013 -0800 4.2 +++ b/HW_Dependent_Primitives/PR__primitives.h Sat Mar 02 09:43:45 2013 -0800 4.3 @@ -31,8 +31,10 @@ 4.4 void 4.5 jmpToTwoParamFn(); 4.6 4.7 -void * 4.8 +void 4.9 asmTerminateCoreCtlr(SlaveVP *currSlv); 4.10 +void 4.11 +asmTerminateCoreCtlrSeq(SlaveVP *animatingSlv); 4.12 4.13 #define flushRegisters() \ 4.14 asm volatile ("":::"%rbx", "%r12", "%r13","%r14","%r15")
5.1 --- a/HW_Dependent_Primitives/PR__primitives_asm.s Tue Feb 05 20:23:27 2013 -0800 5.2 +++ b/HW_Dependent_Primitives/PR__primitives_asm.s Sat Mar 02 09:43:45 2013 -0800 5.3 @@ -156,7 +156,7 @@ 5.4 5.5 /* 5.6 * This one for the sequential version is special. It discards the current stack 5.7 - * and returns directly from the coreCtlr after PR_WL__dissipate_slaveVP was called 5.8 + * and returns directly from the coreCtlr 5.9 */ 5.10 .globl asmTerminateCoreCtlrSeq 5.11 asmTerminateCoreCtlrSeq: 5.12 @@ -164,7 +164,7 @@ 5.13 movq 0x20(%rdi), %rsp #restore stack pointer 5.14 movq 0x18(%rdi), %rbp #restore frame pointer 5.15 #argument is in %rdi 5.16 - call PR_int__dissipate_slaveVP__SL 5.17 + call PR_int__free_slaveVP 5.18 movq %rbp , %rsp #goto the coreCtlrs stack 5.19 pop %rbp #restore the old framepointer 5.20 ret #return from core controller
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/PR.c Sat Mar 02 09:43:45 2013 -0800 6.3 @@ -0,0 +1,314 @@ 6.4 +/* 6.5 + * Copyright 2010 OpenSourceResearchInstitute 6.6 + * 6.7 + * Licensed under BSD 6.8 + */ 6.9 + 6.10 +#include <stdio.h> 6.11 +#include <stdlib.h> 6.12 +#include <string.h> 6.13 +#include <malloc.h> 6.14 +#include <inttypes.h> 6.15 +#include <sys/time.h> 6.16 +#include <pthread.h> 6.17 + 6.18 +#include "PR.h" 6.19 + 6.20 + 6.21 +#define thdAttrs NULL 6.22 + 6.23 + 6.24 +/* MEANING OF WL PI SS int 6.25 + * These indicate which places the function is safe to use. They stand for: 6.26 + * WL: Wrapper Library 6.27 + * PI: Plugin 6.28 + * SS: Startup and Shutdown 6.29 + * int: internal to the PR implementation 6.30 + */ 6.31 + 6.32 + 6.33 +//=========================================================================== 6.34 + 6.35 +//=========================================================================== 6.36 + 6.37 +/*Setup has two phases: 6.38 + * 1) Semantic layer first calls init_PR, which creates masterEnv, and puts 6.39 + * the master Slv into the work-queue, ready for first "call" 6.40 + * 2) Semantic layer then does its own init, which creates the seed virt 6.41 + * slave inside the semantic layer, ready to assign it when 6.42 + * asked by the first run of the animationMaster. 6.43 + * 6.44 + *This part is bit weird because PR really wants to be "always there", and 6.45 + * have applications attach and detach.. for now, this PR is part of 6.46 + * the app, so the PR system starts up as part of running the app. 6.47 + * 6.48 + *The semantic layer is isolated from the PR internals by making the 6.49 + * semantic layer do setup to a state that it's ready with its 6.50 + * initial Slvs, ready to assign them to slots when the animationMaster 6.51 + * asks. Without this pattern, the semantic layer's setup would 6.52 + * have to modify slots directly to assign the initial virt-procrs, and put 6.53 + * them into the readyToAnimateQ itself, breaking the isolation completely. 6.54 + * 6.55 + * 6.56 + *The semantic layer creates the initial Slv(s), and adds its 6.57 + * own environment to masterEnv, and fills in the pointers to 6.58 + * the requestHandler and slaveAssigner plug-in functions 6.59 + */ 6.60 + 6.61 +//Check the comments above -- likely out of sync 6.62 + 6.63 +/*This allocates PR data structures, populates the top environments. After 6.64 + * this call, processes can be started. 6.65 + */ 6.66 +void 6.67 +PR__start() 6.68 + { 6.69 + PR_SS__create_topEnv(); 6.70 + 6.71 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 6.72 + printf( "\n\n Running in SEQUENTIAL mode \n\n" ); 6.73 + //Only difference between version with an OS thread pinned to each core and 6.74 + // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. 6.75 + 6.76 + //Don't do anything here -- using main thread for all PR activity, so 6.77 + // do PR activity when main thread calls "wait for process to end" 6.78 + #else 6.79 + DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(TopEnv,masterLock) ); 6.80 + PR_SS__create_the_coreCtlr_OS_threads(); 6.81 + 6.82 + #endif 6.83 + } 6.84 + 6.85 + 6.86 +/*For now, this is ONLY called from the main thread -- seems this can be relaxed 6.87 + * at some point, but want to reduce complexity to get the first version working 6.88 + * so making this restriction for now.. 6.89 + * 6.90 + *It creates a seed slave, from the top-level fn and initial data passed into 6.91 + * this fn. 6.92 + *The only langlet in the created process is the default PRServ. The rest 6.93 + * must be started up via calls made by the seed VP's top-level fn (passed in 6.94 + * to this call). 6.95 + *That places the information about which langlets are used within the process 6.96 + * into the seed Fn of that process, where all the langlet start() calls are 6.97 + * made. 6.98 + * 6.99 + *A process is represented by a structure that holds all the process-specific 6.100 + * information: 6.101 + *-] The hash-array containing the language environs of any langlets started 6.102 + * inside the process. 6.103 + *-] Counter of num live slaves and num live tasks in the process 6.104 + * 6.105 + */ 6.106 +PRProcess * 6.107 +PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ) 6.108 + { SlaveVP *seedSlv; 6.109 + PRProcess *process; 6.110 + PRLangEnv **langEnvs, **langEnvsList; 6.111 + 6.112 + //This runs outside of the master lock, so use PR_WL form of malloc 6.113 + process = PR_WL__malloc( sizeof(PRProcess) ); 6.114 + _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; 6.115 + _PRTopEnv->numProcesses += 1; 6.116 + 6.117 + langEnvs = 6.118 + (PRLangEnv **)PR_int__make_collection_of_size( NUM_IN_COLLECTION ); 6.119 + langEnvsList = PR_WL__malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); 6.120 + process->langEnvs = langEnvs; 6.121 + process->protoLangEnvsList = langEnvsList; 6.122 + process->numLangEnvs = 0; 6.123 + 6.124 + //A Process starts with one slave, the seed slave 6.125 + seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); 6.126 + seedSlv->typeOfVP = SeedSlv; 6.127 + seedSlv->processSlaveIsIn = process; 6.128 + process->numLiveGenericSlvs = 1; //count the seed 6.129 + process->numLiveTasks = 0; 6.130 + 6.131 + PRServLangEnv * 6.132 + servicesLangEnv = 6.133 + PRServ__start(seedSlv); 6.134 + 6.135 + //resume seedVP into PR's built-in services language's lang env 6.136 + process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this 6.137 + PR_PI__make_slave_ready( seedSlv, servicesLangEnv ); 6.138 + 6.139 + 6.140 + //The first process created has to unblock the core controllers. 6.141 + // This is the "magic" that starts the activity of PR going. 6.142 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 6.143 + //Do nothing here.. in sequential mode, are using the main thread, so 6.144 + // don't use it to do anything yet.. do the PR activity when main thread 6.145 + // calls "wait for process to end" 6.146 + #else 6.147 + if( _PRTopEnv->numProcesses == 1 ) 6.148 + { 6.149 + //tell the core controller threads that a process is ready to be animated 6.150 + //get lock, to lock out any threads still starting up -- they'll see 6.151 + // that firstProcessReady is true before entering while loop, and so never 6.152 + // wait on the condition 6.153 + pthread_mutex_lock( &suspendLock ); 6.154 + _PRTopEnv->firstProcessReady = 1; 6.155 + pthread_mutex_unlock( &suspendLock ); 6.156 + pthread_cond_broadcast( &suspendCond ); 6.157 + } 6.158 + #endif 6.159 + pthread_mutex_init( &(process->doneLock), NULL ); 6.160 + pthread_cond_init( &(process->doneCond), NULL ); 6.161 + process->executionIsComplete = FALSE; 6.162 + 6.163 + return process; 6.164 + } 6.165 + 6.166 +PR__end_seedVP( SlaveVP *seedSlv ) 6.167 + { 6.168 + PR_WL__send_end_slave_req( NULL, (RequestHandler)&PRServ__handleDissipateSeed, seedSlv, 6.169 + PRServ_MAGIC_NUMBER ); 6.170 + } 6.171 + 6.172 +PR__end_process_from_inside( SlaveVP *seedSlv ) 6.173 + { 6.174 + PR_WL__send_lang_request( NULL, (RequestHandler)&PRServ__handle_end_process_from_inside, 6.175 + seedSlv, PRServ_MAGIC_NUMBER ); 6.176 + } 6.177 + 6.178 + 6.179 + 6.180 +/*When all work in the process has completed, then return from this call. 6.181 + * The seedVP of the process may still exist, but it has no work, nor do any 6.182 + * other VPs.. 6.183 + *The process must be shutdown via a separate call. That shutdown frees the 6.184 + * process struct and bookkeeping structs. 6.185 + *First checks whether the process is done, if yes, calls the clean-up fn then 6.186 + * returns the result extracted from the PRProcess struct. 6.187 + *If process not done yet, then performs a wait (in a loop to be sure the 6.188 + * wakeup is not spurious, which can happen). PR registers the wait, and upon 6.189 + * the process ending (last SlaveVP owned by it dissipates), then PR signals 6.190 + * this to wakeup. This then calls the cleanup fn and returns the result. 6.191 + */ 6.192 +void * 6.193 +PR__give_results_from_process_when_ready( PRProcess *process ) 6.194 + { void *result; 6.195 + //First get the "ACK" lock, then do normal wait for signal, then release 6.196 + // ACK lock, to let end-process know it can free the process struct 6.197 + pthread_mutex_lock( &(process->doneAckLock) ); 6.198 + 6.199 + pthread_mutex_lock( &(process->doneLock) ); 6.200 + while( process->executionIsComplete != TRUE ) 6.201 + { 6.202 + pthread_cond_wait( &(process->doneCond), 6.203 + &(process->doneLock) ); 6.204 + } 6.205 + pthread_mutex_unlock( &(process->doneLock) ); 6.206 + result = process->resultToReturn; 6.207 + 6.208 + //now send "ACK" signal to process_end Fn, that it may proceed 6.209 + pthread_mutex_unlock( &(process->doneAckLock) ); 6.210 + 6.211 + return result; 6.212 + //TODO: BUG? -- can process be created and end, before this acquires the 6.213 + // first lock? Can see some rare code that creates a bunch, before getting 6.214 + // to waiting.. leave for now.. pain to fix.. 6.215 + } 6.216 + 6.217 + 6.218 +void 6.219 +PR__wait_for_process_to_end( PRProcess *process ) 6.220 + { 6.221 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 6.222 + // call the one and only core ctlr (sequential version), in the main thread. 6.223 + coreCtlr_Seq( NULL ); 6.224 + flushRegisters(); //Not sure why here, but leaving to be safe 6.225 + 6.226 + #else 6.227 + //First get the "ACK" lock, then do normal wait for signal, then release 6.228 + // ACK lock, to let end-process know it can free the process struct 6.229 + pthread_mutex_lock( &(process->doneAckLock) ); 6.230 + pthread_mutex_lock( &(process->doneLock) ); 6.231 + while( process->executionIsComplete != TRUE ) 6.232 + { 6.233 + pthread_cond_wait( &(process->doneCond), 6.234 + &(process->doneLock) ); 6.235 + } 6.236 + pthread_mutex_unlock( &(process->doneLock) ); 6.237 + //now send "ACK" signal to process_end Fn, that it may proceed 6.238 + pthread_mutex_unlock( &(process->doneAckLock) ); 6.239 + 6.240 + //TODO: BUG? -- can process be created and end, before this acquires the 6.241 + // first lock? Can see some rare code that creates a bunch, before getting 6.242 + // to waiting.. leave for now.. pain to fix.. 6.243 + #endif 6.244 + } 6.245 + 6.246 + 6.247 +void 6.248 +PR__wait_for_all_activity_to_end() 6.249 + { 6.250 + pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); 6.251 + while( !(_PRTopEnv->allActivityIsDone) ) 6.252 + { 6.253 + pthread_cond_wait( &(_PRTopEnv->activityDoneCond), 6.254 + &(_PRTopEnv->activityDoneLock) ); 6.255 + } 6.256 + pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); 6.257 + } 6.258 + 6.259 + 6.260 +/*This info is retrieved by PRServ's "give environ string" function 6.261 + *These Fn s are meant to be called from main, or possibly the seed slave. 6.262 + */ 6.263 +void 6.264 +PR__set_app_info( char *info ) 6.265 + { int32 len; 6.266 + char *copy; 6.267 + len = strlen(info) +1; 6.268 + copy = PR_int__malloc(len); 6.269 + strcpy(copy, info); 6.270 + _PRTopEnv->metaInfo->appInfo = copy; 6.271 + } 6.272 +void 6.273 +PR__set_input_info( char *info ) 6.274 + { int32 len; 6.275 + char *copy; 6.276 + len = strlen(info) +1; 6.277 + copy = PR_int__malloc(len); 6.278 + strcpy(copy, info); 6.279 + _PRTopEnv->metaInfo->inputInfo = copy; 6.280 + } 6.281 + 6.282 + 6.283 + 6.284 + 6.285 +//========================== SHUT DOWN =========================== 6.286 + 6.287 +/*This is called from the main thread, and causes PR's OS threads to stop 6.288 + * then cleans up any memory allocated by PR from the OS. 6.289 + * 6.290 + *The main thread has a separate call it can use to wait for all work to 6.291 + * finish, so when this is called, it just shuts down, whether there's 6.292 + * unfinished work or not. 6.293 + * 6.294 + *However, cores that are performing work won't see this shutdown until 6.295 + * they finish their current work-unit. 6.296 + */ 6.297 +void 6.298 +PR__shutdown() 6.299 + { int32 coreIdx; 6.300 + 6.301 + PR_SS__shutdown_OS_threads(); 6.302 + 6.303 + //wait for the OS threads to exit 6.304 + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 6.305 + { 6.306 + pthread_join( coreCtlrThdHandles[coreIdx], NULL ); 6.307 + } 6.308 + 6.309 + //Before getting rid of everything, print out any measurements made 6.310 + PR_SS__print_out_measurements(); 6.311 + 6.312 + //free all memory allocated from the OS 6.313 + PR_SS__cleanup_at_end_of_shutdown(); 6.314 + } 6.315 + 6.316 + 6.317 +
7.1 --- a/PR.h Tue Feb 05 20:23:27 2013 -0800 7.2 +++ b/PR.h Sat Mar 02 09:43:45 2013 -0800 7.3 @@ -86,7 +86,7 @@ 7.4 #include "PR__WL.h" 7.5 7.6 //================================= 7.7 -#define implement_me printf("Unimpl Fn: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) 7.8 +#define implement_me() printf("Unimpl Fn: \n%s \n%s : %d\n", __FILE__, __FUNCTION__, __LINE__) 7.9 //#define fix_me printf("Fix me at: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) 7.10 7.11
8.1 --- a/PR__PI.c Tue Feb 05 20:23:27 2013 -0800 8.2 +++ b/PR__PI.c Sat Mar 02 09:43:45 2013 -0800 8.3 @@ -49,6 +49,16 @@ 8.4 } 8.5 } 8.6 8.7 +/*Any langlet can transfer slaves over to be resumed in PRServ.. the resume Fn 8.8 + * is registered in the PRServ lang env during process creation. 8.9 + */ 8.10 +void 8.11 +PR_PI__resume_slave_in_PRServ( SlaveVP *slave ) 8.12 + { void *langEnv; 8.13 + langEnv = PR_PI__give_lang_env_for_slave( slave, PRServ_MAGIC_NUMBER ); 8.14 + PR_PI__make_slave_ready( slave, langEnv ); 8.15 + } 8.16 + 8.17 void 8.18 PR_PI__make_task_ready( void *_task, void *_langEnv ) 8.19 { PRLangEnv *protoLangEnv; 8.20 @@ -57,7 +67,7 @@ 8.21 { 8.22 //put task into override readyQ 8.23 8.24 - //update override hasWork flag ? 8.25 + //update numWorkReady 8.26 } 8.27 else 8.28 { //call langlet's registered make ready 8.29 @@ -72,7 +82,84 @@ 8.30 } 8.31 } 8.32 8.33 + 8.34 +/*This is used by langlets.. the intent is that they provide a wrapper 8.35 + * lib call for a "wait" command, and then call this PR service inside their 8.36 + * request handler. 8.37 + *Note: PRServ doesn't offer a "wait for work to end".. it also doesn't have any 8.38 + * create work calls.. and there is no way to end PRServ, except by ending the 8.39 + * process. Therefore, this can safely use the PRServ env to 8.40 + * resume any waiting slaves (incl free task slaves, which are one-to-one 8.41 + * with a task). 8.42 + */ 8.43 +void 8.44 +PR_PI__handle_wait_for_langlets_work_to_end( SlaveVP *slave, void *langEnv ) 8.45 + { PRLangEnv *protoLangEnv; 8.46 8.47 + protoLangEnv = PR_int__give_proto_lang_env( langEnv ); 8.48 + 8.49 + if( protoLangEnv->numLiveWork == 0 ) 8.50 + { //resume into different env than one with no work, as it may be shut down 8.51 + void * 8.52 + resumeEnv = PR_PI__give_lang_env_from_process( slave->processSlaveIsIn, PRServ_MAGIC_NUMBER ); 8.53 + PR_PI__make_slave_ready( slave, resumeEnv ); 8.54 + return; 8.55 + } 8.56 + else 8.57 + { 8.58 + writePrivQ( slave, protoLangEnv->waitingForWorkToEndQ ); 8.59 + } 8.60 + } 8.61 + 8.62 +SlaveVP * 8.63 +PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ) 8.64 + { PRMetaTask *metaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); 8.65 + return metaTask->slaveAssignedTo; 8.66 + } 8.67 + 8.68 +void 8.69 +PR_PI__set_no_del_flag_in_lang_meta_task( void *langMetaTask ) 8.70 + { PRMetaTask *protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); 8.71 + protoMetaTask->goAheadAndFree = FALSE; 8.72 + } 8.73 + 8.74 +void 8.75 +PR_PI__clear_no_del_flag_in_lang_meta_task( void *langMetaTask ) 8.76 + { PRMetaTask *protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); 8.77 + protoMetaTask->goAheadAndFree = TRUE; 8.78 + } 8.79 + 8.80 +/*Two use-cases for freeing a meta-task.. one is the langlet has control 8.81 + * over the meta tasks's life-line it may differ from the task-work-unit's 8.82 + * lifeline.. the other is PR controls, for example when a langlet or 8.83 + * process gets pre-maturely shutdown due to outside influences, or exception, 8.84 + * and so on.. 8.85 + *In the first case, the langlet has two choices.. it can free all the langlet 8.86 + * malloc'd data owned by the meta-task, then as PR to free the remaining 8.87 + * proto meta-task.. or, it can just call PR's full-service "free meta-task" 8.88 + * which in turn calls the langlet's "free just langlet-malloc'd data" Fn, which 8.89 + * was given to the meta-task creator.. 8.90 + * 8.91 + *In the second case, PR calls the langlet's "free just langlet malloc'd data" 8.92 + * Fn, which was given to the meta-task creator. The langlet has no other 8.93 + * involvement. 8.94 + * 8.95 + *This is used by the langlet when it separately frees its own 8.96 + * portion of the meta-task. 8.97 + * 8.98 + *PR uses "PR_int__free_lang_meta_task", which calls the langlet's freer, which 8.99 + * was given to the meta task creator 8.100 + */ 8.101 +void 8.102 +PR_PI__free_proto_meta_task_by_langlet( PRMetaTask *protoMetaTask ) 8.103 + { 8.104 + PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber, 8.105 + (PRCollElem **) protoMetaTask->slaveAssignedTo->metaTasks ); 8.106 + 8.107 + PR_int__free( protoMetaTask ); 8.108 + } 8.109 + 8.110 + 8.111 PRReqst * 8.112 PR_PI__take_next_request_out_of( SlaveVP *slaveWithReq ) 8.113 { PRReqst *req;
9.1 --- a/PR__PI.h Tue Feb 05 20:23:27 2013 -0800 9.2 +++ b/PR__PI.h Sat Mar 02 09:43:45 2013 -0800 9.3 @@ -36,28 +36,159 @@ 9.4 * wrapper-library calls! 9.5 */ 9.6 9.7 -#define PR_PI__create_slaveVP PR_int__create_slaveVP_helper 9.8 +#define \ 9.9 +PR_PI__create_slaveVP PR_int__create_slaveVP_helper 9.10 9.11 -inline 9.12 +//============== 9.13 +//=== Lang Data 9.14 +//= 9.15 +#define \ 9.16 +PR_PI__give_lang_data_from_slave PR_int__give_lang_data_from_slave 9.17 +#define \ 9.18 +PR_SS__give_lang_data_from_slave PR_int__give_lang_data_from_slave 9.19 + 9.20 + 9.21 +//============ 9.22 +//=== Lang Env 9.23 +//= 9.24 +#define \ 9.25 +PR_PI__give_proto_lang_env_for_slave PR_int__give_proto_lang_env_for_slave 9.26 +#define \ 9.27 +PR_PI__give_lang_env_for_slave PR_int__give_lang_env_for_slave 9.28 +#define \ 9.29 +PR_PI__give_lang_env_from_process PR_int__give_lang_env_from_process 9.30 + 9.31 + 9.32 +//========= 9.33 +//=== Meta Task 9.34 +//= 9.35 +#define \ 9.36 +PR_PI__give_lang_meta_task_from_slave PR_int__give_lang_meta_task_from_slave 9.37 +#define \ 9.38 +PR_PI__give_prolog_of_lang_meta_task PR_int__give_prolog_of_lang_meta_task 9.39 + 9.40 SlaveVP * 9.41 PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ); 9.42 9.43 +#define \ 9.44 +PR_PI__free_lang_meta_task_and_remove_from_slave PR_int__free_lang_meta_task_and_remove_from_coll 9.45 + 9.46 +#define \ 9.47 +PR_PI__free_lang_meta_task PR_int__free_lang_meta_task 9.48 + 9.49 +void 9.50 +PR_PI__set_no_del_flag_in_lang_meta_task( void *langMetaTask ); 9.51 +void 9.52 +PR_PI__clear_no_del_flag_in_lang_meta_task( void *langMetaTask ); 9.53 + 9.54 +//========== 9.55 +//=== 9.56 +//= 9.57 +#define \ 9.58 +PR_PI__give_ID_from_lang_meta_task PR__give_ID_from_lang_meta_task 9.59 +#define \ 9.60 +PR_PI__give_ID_from_slave PR__give_ID_from_slave 9.61 + 9.62 +//============= 9.63 +//=== 9.64 +//= 9.65 +#define \ 9.66 +PR_PI__put_slave_into_slot PR_int__put_slave_into_slot 9.67 +#define \ 9.68 +PR_PI__put_task_into_slot PR_int__put_task_into_slot 9.69 9.70 PRReqst * 9.71 PR_PI__take_next_request_out_of( SlaveVP *slaveWithReq ); 9.72 -//#define PR_PI__take_next_request_out_of( slave ) slave->requests 9.73 9.74 -//inline void * 9.75 -//PR_PI__take_lang_reqst_from( PRReqst *req ); 9.76 -#define PR_PI__take_lang_reqst_from( req ) req->langReqData 9.77 +#define \ 9.78 +PR_PI__take_lang_reqst_from( req ) req->langReq 9.79 + 9.80 +void 9.81 +PR_PI__resume_slave_in_PRServ( SlaveVP *slave ); 9.82 + 9.83 +#define \ 9.84 +PR_PI__malloc PR_int__malloc 9.85 +#define \ 9.86 +PR_PI__malloc_aligned PR_int__malloc_aligned 9.87 +#define \ 9.88 +PR_PI__free PR_int__free 9.89 + 9.90 + 9.91 +#define \ 9.92 +PR_PI__throw_exception PR_int__throw_exception 9.93 9.94 //=============== Startup and Shutdown ================ 9.95 +//=== 9.96 +//= 9.97 +void 9.98 +PR_SS__create_topEnv(); 9.99 + 9.100 +AnimSlot ** 9.101 +PR_SS__create_anim_slots( int32 coreSlotsAreOn ); 9.102 + 9.103 +void 9.104 +PR_SS__create_the_coreCtlr_OS_threads(); 9.105 + 9.106 +//=================== 9.107 +void * 9.108 +PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum ); 9.109 + 9.110 +void 9.111 +PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ); 9.112 +void 9.113 +PR_SS__register_lang_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP, 9.114 + int32 magicNum ); 9.115 +void 9.116 +PR_SS__register_lang_data_creator( LangDataCreator langDataCreator, 9.117 + SlaveVP *seedVP, int32 magicNum ); 9.118 +void 9.119 +PR_SS__register_lang_meta_task_creator( LangDataCreator langMetaTaskCreator, 9.120 + SlaveVP *seedVP, int32 magicNum ); 9.121 +void 9.122 +PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP, 9.123 + int32 magicNum ); 9.124 +void 9.125 +PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP, 9.126 + int32 magicNum ); 9.127 +//=================== 9.128 + 9.129 +void 9.130 +PR_SS__end_process_normally( PRProcess *process ); 9.131 + 9.132 void 9.133 PR_SS__shutdown_OS_threads(); 9.134 + 9.135 +SlaveVP* 9.136 +PR_SS__create_shutdown_slave(); 9.137 + 9.138 +void 9.139 +PR_SS__cleanup_at_end_of_shutdown(); 9.140 9.141 void 9.142 PR_SS__print_out_measurements(); 9.143 9.144 +void 9.145 +PR_SS__wait_for_PR_to_shutdown(); 9.146 + 9.147 + 9.148 +//============================= 9.149 +//=== 9.150 +//= 9.151 + 9.152 +#define \ 9.153 +PR_SS__give_proto_lang_env_for_slave PR_int__give_proto_lang_env_for_slave 9.154 + 9.155 +#define \ 9.156 +PR_SS__give_lang_meta_task_from_slave PR_int__give_lang_meta_task_from_slave 9.157 +#define \ 9.158 +PR_SS__give_lang_env_for_slave PR_int__give_lang_env_for_slave 9.159 +#define \ 9.160 +PR_SS__give_lang_env_from_process PR_int__give_lang_env_from_process 9.161 + 9.162 +#define \ 9.163 +PR_SS__malloc PR_WL__malloc /*SS happens outside the Master*/ 9.164 +#define \ 9.165 +PR_SS__free PR_WL__free 9.166 9.167 //================================================ 9.168 #endif /* _PR__PI_H */
10.1 --- a/PR__SS.c Tue Feb 05 20:23:27 2013 -0800 10.2 +++ b/PR__SS.c Sat Mar 02 09:43:45 2013 -0800 10.3 @@ -28,14 +28,6 @@ 10.4 10.5 10.6 //=========================================================================== 10.7 -AnimSlot ** 10.8 -create_anim_slots( int32 coreSlotsAreOn ); 10.9 - 10.10 -void 10.11 -create_topEnv(); 10.12 - 10.13 -void 10.14 -create_the_coreCtlr_OS_threads(); 10.15 10.16 MallocProlog * 10.17 create_free_list(); 10.18 @@ -45,571 +37,8 @@ 10.19 10.20 10.21 //=========================================================================== 10.22 - 10.23 -/*Setup has two phases: 10.24 - * 1) Semantic layer first calls init_PR, which creates masterEnv, and puts 10.25 - * the master Slv into the work-queue, ready for first "call" 10.26 - * 2) Semantic layer then does its own init, which creates the seed virt 10.27 - * slave inside the semantic layer, ready to assign it when 10.28 - * asked by the first run of the animationMaster. 10.29 - * 10.30 - *This part is bit weird because PR really wants to be "always there", and 10.31 - * have applications attach and detach.. for now, this PR is part of 10.32 - * the app, so the PR system starts up as part of running the app. 10.33 - * 10.34 - *The semantic layer is isolated from the PR internals by making the 10.35 - * semantic layer do setup to a state that it's ready with its 10.36 - * initial Slvs, ready to assign them to slots when the animationMaster 10.37 - * asks. Without this pattern, the semantic layer's setup would 10.38 - * have to modify slots directly to assign the initial virt-procrs, and put 10.39 - * them into the readyToAnimateQ itself, breaking the isolation completely. 10.40 - * 10.41 - * 10.42 - *The semantic layer creates the initial Slv(s), and adds its 10.43 - * own environment to masterEnv, and fills in the pointers to 10.44 - * the requestHandler and slaveAssigner plug-in functions 10.45 - */ 10.46 - 10.47 -//Check the comments above -- likely out of sync 10.48 - 10.49 -/*This allocates PR data structures, populates the top environments. After 10.50 - * this call, processes can be started. 10.51 - */ 10.52 void 10.53 -PR__start() 10.54 - { 10.55 - create_topEnv(); 10.56 - 10.57 - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 10.58 - printf( "\n\n Running in SEQUENTIAL mode \n\n" ); 10.59 - #else 10.60 - DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(TopEnv,masterLock) ); 10.61 - create_the_coreCtlr_OS_threads(); 10.62 - 10.63 - #endif 10.64 - } 10.65 - 10.66 - 10.67 -/*This creates a new process and sets the mode to single lang for it 10.68 - *It creates a seed slave, from the top-level fn and initial data passed into 10.69 - * this fn. 10.70 - *The only langlet in the created process is the default PRServ. The rest 10.71 - * must b e started up via calls made by the seed VP's top-level fn (passed in 10.72 - * to this call). 10.73 - * 10.74 - *A process is represented by a structure that holds all the process-specific 10.75 - * information: 10.76 - *-] The hash-array containing the language environs of any langlets started 10.77 - * inside the process. 10.78 - *-] Counter of num live slaves and num live tasks in the process 10.79 - * 10.80 - */ 10.81 -/* 10.82 -PRProcess * 10.83 -PR__create_process__SL( TopLevelFnPtr seed_Fn, void *seedData ) 10.84 - { SlaveVP *seedSlv; 10.85 - PRProcess *process; 10.86 - PRLangEnv **langEnvs, **langEnvsList; 10.87 - 10.88 - _PRTopEnv->mode = SingleLang; 10.89 - 10.90 - 10.91 - process = malloc( sizeof(PRProcess) ); 10.92 - _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; 10.93 - _PRTopEnv->numProcesses += 1; 10.94 - 10.95 - langEnvs = malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRCollElem *) ); 10.96 - ((int32 *)langEnvs)[0] = NUM_IN_COLLECTION; 10.97 - langEnvsList = malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); 10.98 - process->langEnvs = langEnvs; 10.99 - process->langEnvsList = langEnvsList; 10.100 - process->numLangEnvs = 0; 10.101 - 10.102 - //A Process starts with one slave, the seed slave 10.103 - seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); 10.104 - seedSlv->typeOfVP = SeedSlv; 10.105 - seedSlv->processSlaveIsIn = process; 10.106 - process->numLiveGenericSlvs = 1; //count the seed 10.107 - process->numLiveTasks = 0; 10.108 - 10.109 - PRServLangEnv * 10.110 - servicesLangEnv = 10.111 - PR_int__create_lang_env_in_process( sizeof(PRServLangEnv), process, PRServ_MAGIC_NUMBER ); 10.112 - 10.113 - servicesLangEnv->slavesReadyToResumeQ = makePrivQ(); 10.114 - servicesLangEnv->taskReadyQ = makePrivQ(); 10.115 - 10.116 - //resume seedVP into PR's built-in services language's language env 10.117 - process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this 10.118 - PRServ__resume_slaveVP( seedSlv, servicesLangEnv ); 10.119 - 10.120 - 10.121 - //The first process created has to unblock the core controllers. 10.122 - if( _PRTopEnv->numProcesses == 1 ) 10.123 - { 10.124 - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 10.125 - //Only difference between version with an OS thread pinned to each core and 10.126 - // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. 10.127 - 10.128 - // call the one and only core ctlr (sequential version), in the main thread. 10.129 - coreCtlr_Seq( NULL ); 10.130 - flushRegisters(); //Not sure why here, but leaving to be safe 10.131 - #else 10.132 - //tell the core controller threads that a process is ready to be animated 10.133 - //get lock, to lock out any threads still starting up -- they'll see 10.134 - // that firstProcessReady is true before entering while loop, and so never 10.135 - // wait on the condition 10.136 - pthread_mutex_lock( &suspendLock ); 10.137 - _PRTopEnv->firstProcessReady = 1; 10.138 - pthread_mutex_unlock( &suspendLock ); 10.139 - pthread_cond_broadcast( &suspendCond ); 10.140 - #endif 10.141 - } 10.142 - pthread_mutex_init( process->doneLock, NULL ); 10.143 - pthread_cond_init( process->doneCond, NULL ); 10.144 - process->executionIsComplete = FALSE; 10.145 - 10.146 - return process; 10.147 - } 10.148 - */ 10.149 - 10.150 -/*This is only called in multi-lang mode. 10.151 - *It creates a seed slave, from the top-level fn and initial data passed into 10.152 - * this fn. 10.153 - *The only langlet in the created process is the default PRServ. The rest 10.154 - * must be started up via calls made by the seed VP's top-level fn (passed in 10.155 - * to this call). 10.156 - * 10.157 - *A process is represented by a structure that holds all the process-specific 10.158 - * information: 10.159 - *-] The hash-array containing the language environs of any langlets started 10.160 - * inside the process. 10.161 - *-] Counter of num live slaves and num live tasks in the process 10.162 - * 10.163 - */ 10.164 -PRProcess * 10.165 -PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ) 10.166 - { SlaveVP *seedSlv; 10.167 - PRProcess *process; 10.168 - PRLangEnv **langEnvs, **langEnvsList; 10.169 - 10.170 - _PRTopEnv->mode = MultiLang; //leftover, not used, but reminder 10.171 - 10.172 - //This runs outside of the master lock, so use PR_WL form of malloc 10.173 - process = PR_WL__malloc( sizeof(PRProcess) ); 10.174 - _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; 10.175 - _PRTopEnv->numProcesses += 1; 10.176 - 10.177 - langEnvs = PR_WL__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRCollElem *) ); 10.178 - ((int32 *)langEnvs)[0] = NUM_IN_COLLECTION; 10.179 - langEnvsList = PR_WL__malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); 10.180 - process->langEnvs = langEnvs; 10.181 - process->langEnvsList = langEnvsList; 10.182 - process->numLangEnvs = 0; 10.183 - 10.184 - //A Process starts with one slave, the seed slave 10.185 - seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); 10.186 - seedSlv->typeOfVP = SeedSlv; 10.187 - seedSlv->processSlaveIsIn = process; 10.188 - process->numLiveGenericSlvs = 1; //count the seed 10.189 - process->numLiveTasks = 0; 10.190 - 10.191 - PRServLangEnv * 10.192 - servicesLangEnv = 10.193 - PR_int__create_lang_env_in_process( sizeof(PRServLangEnv), process, 10.194 - PRServ_MAGIC_NUMBER ); 10.195 - 10.196 - servicesLangEnv->slavesReadyToResumeQ = makePrivQ(); 10.197 - servicesLangEnv->taskReadyQ = makePrivQ(); 10.198 - 10.199 - //resume seedVP into PR's built-in services language's language env 10.200 - process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this 10.201 - PRServ__resume_slaveVP( seedSlv, servicesLangEnv ); 10.202 - 10.203 - 10.204 - //The first process created has to unblock the core controllers. 10.205 - if( _PRTopEnv->numProcesses == 1 ) 10.206 - { 10.207 - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 10.208 - //Only difference between version with an OS thread pinned to each core and 10.209 - // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. 10.210 - 10.211 - // call the one and only core ctlr (sequential version), in the main thread. 10.212 - coreCtlr_Seq( NULL ); 10.213 - flushRegisters(); //Not sure why here, but leaving to be safe 10.214 - #else 10.215 - //tell the core controller threads that a process is ready to be animated 10.216 - //get lock, to lock out any threads still starting up -- they'll see 10.217 - // that firstProcessReady is true before entering while loop, and so never 10.218 - // wait on the condition 10.219 - pthread_mutex_lock( &suspendLock ); 10.220 - _PRTopEnv->firstProcessReady = 1; 10.221 - pthread_mutex_unlock( &suspendLock ); 10.222 - pthread_cond_broadcast( &suspendCond ); 10.223 - #endif 10.224 - } 10.225 - pthread_mutex_init( &(process->doneLock), NULL ); 10.226 - pthread_cond_init( &(process->doneCond), NULL ); 10.227 - process->executionIsComplete = FALSE; 10.228 - 10.229 - return process; 10.230 - } 10.231 - 10.232 - 10.233 -/*are already in Master when detect, inside end-task or dissipate, so call "PR_SS__shutdown_process" 10.234 - */ 10.235 -void 10.236 -PR_SS__shutdown_process( PRProcess *process ) 10.237 - { int32 i, processIdx; 10.238 - PRProcess **processes; 10.239 - 10.240 - //remove process from PR's list of processes.. 10.241 - processes = _PRTopEnv->processes; 10.242 - //find the process within the list 10.243 - for( i = 0; i < _PRTopEnv->numProcesses; i++ ) 10.244 - { if( processes[i] == process ) 10.245 - { processIdx = i; 10.246 - break; 10.247 - } 10.248 - } 10.249 - //move all the higher processes down, overwriting the target 10.250 - for( i = processIdx +1; i < _PRTopEnv->numProcesses; i++ ) 10.251 - { processes[i-1] = processes[i]; 10.252 - } 10.253 - _PRTopEnv->numProcesses -= 1; 10.254 - 10.255 - //remove process from the process-to-slot chooser 10.256 - _PRTopEnv->currProcessIdx = 0; //start choosing starting at process 0 10.257 - 10.258 - //call shutdown on each langlet started in process (which frees any 10.259 - // langlet-allocd data in langEnv); 10.260 - //Then free the lang env 10.261 - PRLangEnv *protoLangEnv; 10.262 - for( i = 0; i < process->numLangEnvs; i++ ) 10.263 - { protoLangEnv = PR_int__give_proto_lang_env(process->langEnvsList[i]); 10.264 - //The lang shutdowns should free any slaves or tasks in the langEnv 10.265 - (*protoLangEnv->shutdownHdlr)(&(protoLangEnv[1])); 10.266 - PR_int__free( protoLangEnv ); 10.267 - } 10.268 - PR_int__free( process->langEnvsList ); //list array 10.269 - PR_int__free( &(((int32 *)process->langEnvs)[-1]) ); //the collection array 10.270 - 10.271 - //any slaves from this process still in slots will finish executing, but 10.272 - // have no lang env for the request handlers to use! 10.273 - //So, have to mark each slave, so the request handling isn't done 10.274 - AnimSlot *slot, **animSlots; 10.275 - int32 core; 10.276 - for( core = 0; core < NUM_CORES; core++ ) 10.277 - { animSlots = _PRTopEnv->allAnimSlots[core]; 10.278 - for( i = 0; i < NUM_ANIM_SLOTS; i++ ) 10.279 - { slot = animSlots[i]; 10.280 - if( slot->slaveAssignedToSlot->processSlaveIsIn == process ) 10.281 - { //turn off req handling by disallowing slave from chging slot flag 10.282 - slot->slaveAssignedToSlot->animSlotAssignedTo = NULL; 10.283 - slot->workIsDone = FALSE; //just in case, make sure req hdling off 10.284 - slot->needsWorkAssigned = TRUE; //make new slave be assigned 10.285 - } 10.286 - } 10.287 - } 10.288 - 10.289 - //cause resume of "PR__wait_for_process_to_end()" call 10.290 - pthread_mutex_lock( &(process->doneLock) ); 10.291 - process->executionIsComplete = TRUE; 10.292 - pthread_mutex_unlock( &(process->doneLock) ); 10.293 - pthread_cond_broadcast( &(process->doneCond) ); 10.294 - //now wait for woken waiter to Ack, then free the process struct 10.295 - pthread_mutex_lock( &(process->doneAckLock) ); //BUG:? may be a race 10.296 - pthread_mutex_unlock( &(process->doneAckLock) ); 10.297 - PR_int__free(process); 10.298 - 10.299 - //if no more processes, cause resume of "PR__wait_for_all_activity_to_end" 10.300 - if( _PRTopEnv->numProcesses == 0) 10.301 - { 10.302 - pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); 10.303 - _PRTopEnv->allActivityIsDone = TRUE; 10.304 - pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); 10.305 - pthread_cond_broadcast( &(_PRTopEnv->activityDoneCond) ); 10.306 - } 10.307 - } 10.308 - 10.309 -/*This waits for the OS threads in the PR system to end. Causing them to end 10.310 - * has to be done separately (haven't worked out details as of this comment) 10.311 - */ 10.312 -void 10.313 -PR_SS__wait_for_PR_to_shutdown() 10.314 - { 10.315 - //wait for all to complete 10.316 - int coreIdx; 10.317 - for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 10.318 - { 10.319 - pthread_join( coreCtlrThdHandles[coreIdx], NULL ); 10.320 - } 10.321 - } 10.322 - 10.323 -void 10.324 -PR__wait_for_all_activity_to_end() 10.325 - { 10.326 - pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); 10.327 - while( !(_PRTopEnv->allActivityIsDone) ) 10.328 - { 10.329 - pthread_cond_wait( &(_PRTopEnv->activityDoneCond), 10.330 - &(_PRTopEnv->activityDoneLock) ); 10.331 - } 10.332 - pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); 10.333 - } 10.334 - 10.335 - 10.336 -void 10.337 -PR__wait_for_process_to_end( PRProcess *process ) 10.338 - { //First get the "ACK" lock, then do normal wait for signal, then release 10.339 - // ACK lock, to let end-process know it can free the process struct 10.340 - pthread_mutex_lock( &(process->doneAckLock) ); 10.341 - pthread_mutex_lock( &(process->doneLock) ); 10.342 - while( process->executionIsComplete != TRUE ) 10.343 - { 10.344 - pthread_cond_wait( &(process->doneCond), 10.345 - &(process->doneLock) ); 10.346 - } 10.347 - pthread_mutex_unlock( &(process->doneLock) ); 10.348 - //now send "ACK" signal to process_end Fn, that it may proceed 10.349 - pthread_mutex_unlock( &(process->doneAckLock) ); 10.350 - 10.351 - //TODO: BUG? -- can process be created and end, before this acquires the 10.352 - // first lock? Can see some rare code that creates a bunch, before getting 10.353 - // to waiting.. leave for now.. pain to fix.. 10.354 - } 10.355 - 10.356 -/*When all work in the process has completed, then return from this call. 10.357 - * The seedVP of the process may still exist, but it has no work, nor do any 10.358 - * other VPs.. 10.359 - *The process must be shutdown via a separate call. That shutdown frees the 10.360 - * process struct and bookkeeping structs. 10.361 - *First checks whether the process is done, if yes, calls the clean-up fn then 10.362 - * returns the result extracted from the PRProcess struct. 10.363 - *If process not done yet, then performs a wait (in a loop to be sure the 10.364 - * wakeup is not spurious, which can happen). PR registers the wait, and upon 10.365 - * the process ending (last SlaveVP owned by it dissipates), then PR signals 10.366 - * this to wakeup. This then calls the cleanup fn and returns the result. 10.367 - */ 10.368 -void * 10.369 -PR__give_results_from_process_when_ready( PRProcess *process ) 10.370 - { void *result; 10.371 - //First get the "ACK" lock, then do normal wait for signal, then release 10.372 - // ACK lock, to let end-process know it can free the process struct 10.373 - pthread_mutex_lock( &(process->doneAckLock) ); 10.374 - 10.375 - pthread_mutex_lock( &(process->doneLock) ); 10.376 - while( process->executionIsComplete != TRUE ) 10.377 - { 10.378 - pthread_cond_wait( &(process->doneCond), 10.379 - &(process->doneLock) ); 10.380 - } 10.381 - pthread_mutex_unlock( &(process->doneLock) ); 10.382 - result = process->resultToReturn; 10.383 - 10.384 - //now send "ACK" signal to process_end Fn, that it may proceed 10.385 - pthread_mutex_unlock( &(process->doneAckLock) ); 10.386 - 10.387 - return result; 10.388 - //TODO: BUG? -- can process be created and end, before this acquires the 10.389 - // first lock? Can see some rare code that creates a bunch, before getting 10.390 - // to waiting.. leave for now.. pain to fix.. 10.391 - } 10.392 - 10.393 - 10.394 -inline 10.395 -void * 10.396 -PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum ) 10.397 - { 10.398 - return PR_int__create_lang_env_in_process( size, slave->processSlaveIsIn, magicNum ); 10.399 - } 10.400 - 10.401 - 10.402 -/*These store the pointer to handler into the language env -- language env 10.403 - * found by using magic num to look it up in the process that the seedVP 10.404 - * is inside of. 10.405 - */ 10.406 -void 10.407 -PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ) 10.408 - { PRLangEnv *langEnv; 10.409 - 10.410 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.411 - langEnv->workAssigner = assigner; 10.412 - } 10.413 -void 10.414 -PR_SS__register_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP, 10.415 - int32 magicNum ) 10.416 - { PRLangEnv *langEnv; 10.417 - 10.418 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.419 - langEnv->shutdownHdlr = shutdownHdlr; 10.420 - } 10.421 -void 10.422 -PR_SS__register_lang_data_creator( LangDataCreator langDataCreator, 10.423 - SlaveVP *seedVP, int32 magicNum ) 10.424 - { PRLangEnv *langEnv; 10.425 - 10.426 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.427 - langEnv->langDataCreator = langDataCreator; 10.428 - } 10.429 -void 10.430 -PR_SS__register_lang_meta_task_creator( LangDataCreator langMetaTaskCreator, 10.431 - SlaveVP *seedVP, int32 magicNum ) 10.432 - { PRLangEnv *langEnv; 10.433 - 10.434 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.435 - langEnv->langMetaTaskCreator = langMetaTaskCreator; 10.436 - } 10.437 -void 10.438 -PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP, 10.439 - int32 magicNum ) 10.440 - { PRLangEnv *langEnv; 10.441 - 10.442 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.443 - langEnv->makeSlaveReadyFn = fn; 10.444 - } 10.445 -void 10.446 -PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP, 10.447 - int32 magicNum ) 10.448 - { PRLangEnv *langEnv; 10.449 - 10.450 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.451 - langEnv->makeTaskReadyFn = fn; 10.452 - } 10.453 - 10.454 -/* 10.455 -void 10.456 -PR_SS__register_create_task_handler( RequestHandler createTaskHandler, SlaveVP *seedVP, int32 magicNum ) 10.457 - { PRLangEnv *langEnv; 10.458 - 10.459 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.460 - langEnv->createTaskHdlr = createTaskHandler; 10.461 - } 10.462 -void 10.463 -PR_SS__register_end_task_handler( RequestHandler endTaskHandler, SlaveVP *seedVP, int32 magicNum ) 10.464 - { PRLangEnv *langEnv; 10.465 - 10.466 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.467 - langEnv->endTaskHdlr = endTaskHandler; 10.468 - } 10.469 -void 10.470 -PR_SS__register_create_slave_handler( RequestHandler createSlvHandler, SlaveVP *seedVP, int32 magicNum ) 10.471 - { PRLangEnv *langEnv; 10.472 - 10.473 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.474 - langEnv->createSlaveHdlr = createSlvHandler; 10.475 - } 10.476 -void 10.477 -PR_SS__register_dissipate_slave_handler( RequestHandler dissipateHandler, SlaveVP *seedVP, int32 magicNum ) 10.478 - { PRLangEnv *langEnv; 10.479 - 10.480 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.481 - langEnv->dissipateSlaveHdlr = dissipateHandler; 10.482 - } 10.483 -void 10.484 -PR_SS__register_request_handler( RequestHandler reqHandler, SlaveVP *seedVP, int32 magicNum ) 10.485 - { PRLangEnv *langEnv; 10.486 - 10.487 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.488 - langEnv->requestHdlr = reqHandler; 10.489 - } 10.490 - */ 10.491 -/* 10.492 -void 10.493 -PR_SS__register_lang_data_initializer( LangDataInitializer langDataInitializer, 10.494 - SlaveVP *seedVP, int32 magicNum ) 10.495 - { PRLangEnv *langEnv; 10.496 - 10.497 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.498 - langEnv->langDataInitializer = langDataInitializer; 10.499 - } 10.500 -void 10.501 -PR_SS__register_lang_data_freer( LangDataFreer langDataFreer, 10.502 - SlaveVP *seedVP, int32 magicNum ) 10.503 - { PRLangEnv *langEnv; 10.504 - 10.505 - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.506 - langEnv->langDataFreer = langDataFreer; 10.507 - } 10.508 -*/ 10.509 - 10.510 - 10.511 - 10.512 - 10.513 -/* 10.514 - *This function returns information about the version of PR, the language 10.515 - * the program is being run in, its version, and information on the 10.516 - * hardware. 10.517 - */ 10.518 -char * 10.519 -PRServ___give_environment_string() 10.520 - { char *buffer = PR_WL__malloc(10000); 10.521 - int32 j; 10.522 - 10.523 - j = sizeof(int32); //put total num chars here when done 10.524 - //-------------------------- 10.525 - j += sprintf(buffer+j, "#\n# >> Build information <<\n"); 10.526 - j += sprintf(buffer+j, "# GCC VERSION: %d.%d.%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__); 10.527 - j += sprintf(buffer+j, "# Build Date: %s %s\n", __DATE__, __TIME__); 10.528 - 10.529 - j += sprintf(buffer+j, "#\n# >> Hardware information <<\n"); 10.530 - j += sprintf(buffer+j, "# Hardware Architecture: "); 10.531 - #ifdef __x86_64 10.532 - j += sprintf(buffer+j, "x86_64"); 10.533 - #endif //__x86_64 10.534 - #ifdef __i386 10.535 - j += sprintf(buffer+j, "x86"); 10.536 - #endif //__i386 10.537 - j += sprintf(buffer+j, "\n"); 10.538 - j += sprintf(buffer+j, "# Number of Cores: %d\n", NUM_CORES); 10.539 - //-------------------------- 10.540 - 10.541 - //PR Plugins 10.542 - j += sprintf(buffer+j, "#\n# >> PR Plugins <<\n"); 10.543 - j += sprintf(buffer+j, "# Language : "); 10.544 - j += sprintf(buffer+j, _LANG_NAME_); 10.545 - j += sprintf(buffer+j, "\n"); 10.546 - //Meta info gets set by calls from the language during its init, 10.547 - // and info registered by calls from inside the application 10.548 - j += sprintf(buffer+j, "# Assigner: %s\n", _PRTopEnv->metaInfo->assignerInfo); 10.549 - 10.550 - //-------------------------- 10.551 - //Application 10.552 - j += sprintf(buffer+j, "#\n# >> Application <<\n"); 10.553 - j += sprintf(buffer+j, "# Name: %s\n", _PRTopEnv->metaInfo->appInfo); 10.554 - j += sprintf(buffer+j, "# Data Set:\n%s\n",_PRTopEnv->metaInfo->inputInfo); 10.555 - 10.556 - ((int32 *)buffer)[0] = j - sizeof(int32); //insert the number of chars 10.557 - //-------------------------- 10.558 - return (char *) &(((int32 *)buffer)[1]); //return pointer to first char 10.559 - } 10.560 - 10.561 -void 10.562 -PR__set_app_info( char *info ) 10.563 - { int32 len; 10.564 - char *copy; 10.565 - len = strlen(info) +1; 10.566 - copy = PR_int__malloc(len); 10.567 - strcpy(copy, info); 10.568 - _PRTopEnv->metaInfo->appInfo = copy; 10.569 - } 10.570 -void 10.571 -PR__set_input_info( char *info ) 10.572 - { int32 len; 10.573 - char *copy; 10.574 - len = strlen(info) +1; 10.575 - copy = PR_int__malloc(len); 10.576 - strcpy(copy, info); 10.577 - _PRTopEnv->metaInfo->inputInfo = copy; 10.578 - } 10.579 - 10.580 - 10.581 - 10.582 - 10.583 - 10.584 - 10.585 -void 10.586 -create_topEnv() 10.587 +PR_SS__create_topEnv() 10.588 { TopEnv *masterEnv; 10.589 PRQueueStruc **readyToAnimateQs; 10.590 int32 coreIdx; 10.591 @@ -640,16 +69,18 @@ 10.592 allAnimSlots = PR_int__malloc( NUM_CORES * sizeof(AnimSlot *) ); 10.593 _PRTopEnv->allAnimSlots = allAnimSlots; 10.594 10.595 - //Make the master VPs 10.596 + //Make the animation slots and similar per-core structs.. 10.597 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 10.598 { 10.599 - readyToAnimateQs[ coreIdx ] = makePRQ(); 10.600 + //readyToAnimateQs[ coreIdx ] = makePRQ(); 10.601 10.602 - //Q: should give masterVP core-specific info as its init data? 10.603 +/* //Q: should give masterVP core-specific info as its init data? 10.604 + Don't have masterVPs anymore -- the pinned pthread takes that role 10.605 masterVPs[ coreIdx ] = PR_int__create_slaveVP_helper( (TopLevelFnPtr)&animationMaster, (void*)_PRTopEnv ); 10.606 masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx; 10.607 masterVPs[ coreIdx ]->typeOfVP = Master; 10.608 - allAnimSlots[ coreIdx ] = create_anim_slots( coreIdx ); //makes for one core 10.609 + */ 10.610 + allAnimSlots[ coreIdx ] = PR_SS__create_anim_slots( coreIdx ); //makes for one core 10.611 } 10.612 10.613 //For each animation slot, there is an idle slave, and an initial 10.614 @@ -659,10 +90,11 @@ 10.615 10.616 for( coreNum = 0; coreNum < NUM_CORES; coreNum++ ) 10.617 { //langEnv->coreIsDone[coreNum] = FALSE; //use during shutdown 10.618 - 10.619 + //Still have multiple slots -- left over from prev incarnation 10.620 for( slotNum = 0; slotNum < NUM_ANIM_SLOTS; ++slotNum ) 10.621 { idleSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL ); 10.622 idleSlv->coreAnimatedBy = coreNum; 10.623 + idleSlv->typeOfVP = IdleVP; 10.624 idleSlv->animSlotAssignedTo = 10.625 _PRTopEnv->allAnimSlots[coreNum][slotNum]; 10.626 _PRTopEnv->idleSlv[coreNum][slotNum] = idleSlv; 10.627 @@ -688,6 +120,7 @@ 10.628 10.629 _PRTopEnv->numSlavesCreated = 0; //used by create slave to set slave ID 10.630 10.631 + //TODO: remove this, and the vars from TopEnv 10.632 //=================== single lang only vars ================== 10.633 // 10.634 // 10.635 @@ -704,6 +137,7 @@ 10.636 // 10.637 readyToAnimateQs = PR_int__malloc( NUM_CORES * sizeof(PRQueueStruc *) ); 10.638 10.639 + //BUG: have a fixed max num processes, but never check whether exceeded 10.640 _PRTopEnv->processes = PR_int__malloc( NUM_IN_COLLECTION * sizeof(PRProcess *) ); 10.641 _PRTopEnv->numProcesses = 0; 10.642 _PRTopEnv->currProcessIdx = 0; 10.643 @@ -731,7 +165,7 @@ 10.644 } 10.645 10.646 AnimSlot ** 10.647 -create_anim_slots( int32 coreSlotsAreOn ) 10.648 +PR_SS__create_anim_slots( int32 coreSlotsAreOn ) 10.649 { AnimSlot **animSlots; 10.650 int i; 10.651 10.652 @@ -751,7 +185,7 @@ 10.653 } 10.654 10.655 void 10.656 -freeAnimSlots( AnimSlot **animSlots ) 10.657 +PR_SS__freeAnimSlots( AnimSlot **animSlots ) 10.658 { int i; 10.659 for( i = 0; i < NUM_ANIM_SLOTS; i++ ) 10.660 { 10.661 @@ -769,7 +203,7 @@ 10.662 * all the core controller threads when the first process is created. 10.663 */ 10.664 void 10.665 -create_the_coreCtlr_OS_threads() 10.666 +PR_SS__create_the_coreCtlr_OS_threads() 10.667 { 10.668 //======================================================================== 10.669 // Create the Threads 10.670 @@ -800,34 +234,149 @@ 10.671 } 10.672 10.673 10.674 -//========================== SHUT DOWN =========================== 10.675 +//====================== 10.676 +//=== 10.677 +//= 10.678 +//inline 10.679 +void * 10.680 +PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum ) 10.681 + { 10.682 + return PR_int__create_lang_env_in_process( size, slave->processSlaveIsIn, magicNum ); 10.683 + } 10.684 10.685 -/*This is called from the main thread, and causes PR's OS threads to stop 10.686 - * then cleans up any memory allocated by PR from the OS. 10.687 - * 10.688 - *The main thread has a separate call it can use to wait for all work to 10.689 - * finish, so when this is called, it just shuts down, whether there's 10.690 - * unfinished work or not. 10.691 - * 10.692 - *However, cores that are performing work won't see this shutdown until 10.693 - * they finish their current work-unit. 10.694 + 10.695 +/*These store the pointer to handler into the language env -- language env 10.696 + * found by using magic num to look it up in the process that the seedVP 10.697 + * is inside of. 10.698 */ 10.699 -PR__shutdown() 10.700 - { int32 coreIdx; 10.701 +void 10.702 +PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ) 10.703 + { PRLangEnv *langEnv; 10.704 + 10.705 + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.706 + langEnv->workAssigner = assigner; 10.707 + } 10.708 +void 10.709 +PR_SS__register_lang_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP, 10.710 + int32 magicNum ) 10.711 + { PRLangEnv *langEnv; 10.712 + 10.713 + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.714 + langEnv->shutdownHdlr = shutdownHdlr; 10.715 + } 10.716 +void 10.717 +PR_SS__register_lang_data_creator( LangDataCreator langDataCreator, 10.718 + SlaveVP *seedVP, int32 magicNum ) 10.719 + { PRLangEnv *langEnv; 10.720 + 10.721 + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.722 + langEnv->langDataCreator = langDataCreator; 10.723 + } 10.724 +void 10.725 +PR_SS__register_lang_meta_task_creator( LangMetaTaskCreator langMetaTaskCreator, 10.726 + SlaveVP *seedVP, int32 magicNum ) 10.727 + { PRLangEnv *protoLangEnv; 10.728 + 10.729 + protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.730 + protoLangEnv->langMetaTaskCreator = langMetaTaskCreator; 10.731 + } 10.732 +void 10.733 +PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP, 10.734 + int32 magicNum ) 10.735 + { PRLangEnv *langEnv; 10.736 + 10.737 + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.738 + langEnv->makeSlaveReadyFn = fn; 10.739 + } 10.740 +void 10.741 +PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP, 10.742 + int32 magicNum ) 10.743 + { PRLangEnv *langEnv; 10.744 + 10.745 + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); 10.746 + langEnv->makeTaskReadyFn = fn; 10.747 + } 10.748 + 10.749 +//======== 10.750 + 10.751 + 10.752 +/*are in Master when call this.. due to detecting end-of-work, from inside 10.753 + * end-task or dissipate.. or, call this when app calls "end process" 10.754 + */ 10.755 +void 10.756 +PR_SS__end_process_normally( PRProcess *process ) 10.757 + { int32 i, processIdx; 10.758 + PRProcess **processes; 10.759 10.760 - PR_SS__shutdown_OS_threads(); 10.761 + //remove process from PR's list of processes.. 10.762 + processes = _PRTopEnv->processes; 10.763 + //find the process within the list 10.764 + for( i = 0; i < _PRTopEnv->numProcesses; i++ ) 10.765 + { if( processes[i] == process ) 10.766 + { processIdx = i; 10.767 + break; 10.768 + } 10.769 + } 10.770 + //move all the higher processes down, overwriting the target 10.771 + for( i = processIdx +1; i < _PRTopEnv->numProcesses; i++ ) 10.772 + { processes[i-1] = processes[i]; 10.773 + } 10.774 + _PRTopEnv->numProcesses -= 1; 10.775 10.776 - //wait for the OS threads to exit 10.777 - for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 10.778 + //remove process from the process-to-slot chooser 10.779 + _PRTopEnv->currProcessIdx = 0; //start choosing starting at process 0 10.780 + 10.781 + //call shutdown on each langlet started in process (which frees any 10.782 + // langlet-allocd data in langEnv); 10.783 + //Then free the lang env 10.784 + PRLangEnv *protoLangEnv; 10.785 + for( i = 0; i < process->numLangEnvs; i++ ) 10.786 + { protoLangEnv = PR_int__give_proto_lang_env(process->protoLangEnvsList[i]); 10.787 + //The lang shutdowns should free any slaves or tasks in the langEnv 10.788 + (*protoLangEnv->shutdownHdlr)(&(protoLangEnv[1])); 10.789 + PR_int__free( protoLangEnv ); 10.790 + } 10.791 + PR_int__free( process->protoLangEnvsList ); //list array 10.792 + PR_int__free( &(((int32 *)process->langEnvs)[-1]) ); //the collection array 10.793 + 10.794 + //any slaves from this process still in slots will finish executing, but 10.795 + // have no lang env for the request handlers to use! 10.796 + //So, have to mark each slave, so the request handling isn't done 10.797 + AnimSlot *slot, **animSlots; 10.798 + int32 core; 10.799 + for( core = 0; core < NUM_CORES; core++ ) 10.800 + { animSlots = _PRTopEnv->allAnimSlots[core]; 10.801 + for( i = 0; i < NUM_ANIM_SLOTS; i++ ) 10.802 + { slot = animSlots[i]; 10.803 + if( slot->slaveAssignedToSlot->processSlaveIsIn == process ) 10.804 + { //turn off req handling by disallowing slave from chging slot flag 10.805 + slot->slaveAssignedToSlot->animSlotAssignedTo = NULL; 10.806 + slot->workIsDone = FALSE; //just in case, make sure req hdling off 10.807 + slot->needsWorkAssigned = TRUE; //make new slave be assigned 10.808 + } 10.809 + } 10.810 + } 10.811 + 10.812 + //cause resume of "PR__wait_for_process_to_end()" call 10.813 + if( process->hasWaitingToEnd ) 10.814 { 10.815 - pthread_join( coreCtlrThdHandles[coreIdx], NULL ); 10.816 + pthread_mutex_lock( &(process->doneLock) ); 10.817 + process->executionIsComplete = TRUE; 10.818 + pthread_mutex_unlock( &(process->doneLock) ); 10.819 + pthread_cond_broadcast( &(process->doneCond) ); 10.820 + //now wait for woken waiter to Ack, then free the process struct 10.821 + pthread_mutex_lock( &(process->doneAckLock) ); //BUG:? may be a race 10.822 + pthread_mutex_unlock( &(process->doneAckLock) ); 10.823 + PR_int__free(process); 10.824 + } 10.825 + //if no more processes, cause resume of "PR__wait_for_all_activity_to_end" 10.826 + if( _PRTopEnv->numProcesses == 0) 10.827 + { 10.828 + pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); 10.829 + _PRTopEnv->allActivityIsDone = TRUE; 10.830 + pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); 10.831 + pthread_cond_broadcast( &(_PRTopEnv->activityDoneCond) ); 10.832 } 10.833 - 10.834 - //Before getting rid of everything, print out any measurements made 10.835 - PR_SS__print_out_measurements(); 10.836 - 10.837 - //free all memory allocated from the OS 10.838 - PR_SS__cleanup_at_end_of_shutdown(); 10.839 } 10.840 10.841 10.842 @@ -868,12 +417,26 @@ 10.843 SlaveVP* shutdownVP; 10.844 10.845 shutdownVP = PR_int__create_slaveVP_helper( &endOSThreadFn, NULL ); 10.846 - shutdownVP->typeOfVP = Shutdown; 10.847 + shutdownVP->typeOfVP = ShutdownVP; 10.848 10.849 return shutdownVP; 10.850 } 10.851 10.852 10.853 +/*This is run in the main thread, as part of the PR__shutdown() call 10.854 + * It frees any memory allocated from the OS 10.855 + */ 10.856 +void 10.857 +PR_SS__cleanup_at_end_of_shutdown() 10.858 + { 10.859 + //All the environment data has been allocated with PR__malloc, so just 10.860 + // free the memory obtained by PR__malloc, then free the top env. 10.861 + //These are the only two that use system free 10.862 + PR_ext__free_free_list( _PRTopEnv->freeLists ); 10.863 + free( (void *)_PRTopEnv ); 10.864 + } 10.865 + 10.866 + 10.867 10.868 void 10.869 PR_SS__print_out_measurements() 10.870 @@ -891,20 +454,23 @@ 10.871 MEAS__Print_Hists_for_Plugin_Meas; 10.872 } 10.873 10.874 -/*This is run in the main thread, as part of the PR__shutdown() call 10.875 - * It frees any memory allocated from the OS 10.876 +/*This waits for the OS threads in the PR system to end. Causing them to end 10.877 + * has to be done separately (haven't worked out details as of this comment) 10.878 */ 10.879 void 10.880 -PR_SS__cleanup_at_end_of_shutdown() 10.881 - { 10.882 - //All the environment data has been allocated with PR__malloc, so just 10.883 - // free the memory obtained by PR__malloc, then free the top env. 10.884 - //These are the only two that use system free 10.885 - PR_ext__free_free_list( _PRTopEnv->freeLists ); 10.886 - free( (void *)_PRTopEnv ); 10.887 +PR_SS__wait_for_PR_to_shutdown() 10.888 + { 10.889 + //wait for all to complete 10.890 + int coreIdx; 10.891 + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 10.892 + { 10.893 + pthread_join( coreCtlrThdHandles[coreIdx], NULL ); 10.894 + } 10.895 } 10.896 10.897 10.898 +//============================ 10.899 + 10.900 /*Am trying to be cute, avoiding IF statement in coreCtlr that checks for 10.901 * a special shutdown slaveVP. Ended up with extra-complex shutdown sequence. 10.902 *This function has the sole purpose of setting the stack and framePtr
11.1 --- a/PR__WL.c Tue Feb 05 20:23:27 2013 -0800 11.2 +++ b/PR__WL.c Sat Mar 02 09:43:45 2013 -0800 11.3 @@ -24,8 +24,10 @@ 11.4 11.5 11.6 11.7 - 11.8 -inline 11.9 +/*As of Feb 2013, doesn't use magic number -- only one ID shared across all 11.10 + * langlets 11.11 + */ 11.12 +inline 11.13 int32 * 11.14 PR__give_ID_from_slave( SlaveVP *animSlv, int32 magicNumber ) 11.15 { 11.16 @@ -34,9 +36,9 @@ 11.17 11.18 inline 11.19 int32 * 11.20 -PR__give_ID_from_task( void *_task ) 11.21 - { PRMetaTask task; 11.22 - task = ((PRMetaTask *)_task)[-1]; 11.23 +PR__give_ID_from_lang_meta_task( void *_task ) 11.24 + { PRMetaTask *task; 11.25 + task = PR_int__give_prolog_of_lang_meta_task(_task); 11.26 return task->ID; 11.27 } 11.28 11.29 @@ -99,8 +101,8 @@ 11.30 * pears -- making that suspend the last thing in the Slv's trace. 11.31 */ 11.32 void 11.33 -PR_WL__send_end_slave_req( RequestHandler handler, SlaveVP *slaveToDissipate, 11.34 - int32 magicNum ) 11.35 +PR_WL__send_end_slave_req( void *langReq, RequestHandler handler, 11.36 + SlaveVP *slaveToDissipate, int32 magicNum ) 11.37 { PRReqst req; 11.38 11.39 req.reqType = SlvDissipate; 11.40 @@ -136,11 +138,11 @@ 11.41 SlaveVP *animSlv, int32 magicNum ) 11.42 { PRReqst req; 11.43 11.44 - req.reqType = TaskEnd; 11.45 - req.langReq = langReq; 11.46 - req.handler = handler; 11.47 + req.reqType = TaskEnd; 11.48 + req.langReq = langReq; 11.49 + req.handler = handler; 11.50 req.langMagicNumber = magicNum; 11.51 - animSlv->request = &req; 11.52 + animSlv->request = &req; 11.53 11.54 PR_WL__suspend_slaveVP_and_send_req( animSlv ); 11.55 } 11.56 @@ -160,7 +162,7 @@ 11.57 PR_WL__add_lang_request_in_mallocd_PRReqst( void *langReqData, 11.58 SlaveVP *callingSlv ) 11.59 { PRReqst *req; 11.60 -//WARNING: not update.. may be buggy 11.61 +//WARNING: not updated.. may be buggy 11.62 req = PR_int__malloc( sizeof(PRReqst) ); 11.63 req->reqType = Language; 11.64 req->langReq = langReqData; 11.65 @@ -168,7 +170,8 @@ 11.66 callingSlv->request = req; 11.67 } 11.68 11.69 -inline int32 * 11.70 +inline 11.71 +int32 * 11.72 PR_WL__create_taskID_of_size( int32 numInts ) 11.73 { int32 *taskID; 11.74 11.75 @@ -182,7 +185,8 @@ 11.76 * to plugin 11.77 *Then it does suspend, to cause request to be sent. 11.78 */ 11.79 -inline void 11.80 +inline 11.81 +void 11.82 PR_WL__send_lang_request( void *langReqData, RequestHandler handler, 11.83 SlaveVP *callingSlv, int32 magicNum ) 11.84 { PRReqst req; 11.85 @@ -197,6 +201,19 @@ 11.86 PR_WL__suspend_slaveVP_and_send_req( callingSlv ); 11.87 } 11.88 11.89 +inline 11.90 +void 11.91 +PR_WL__send_lang_shutdown_request( SlaveVP *callingSlv, int32 magicNum ) 11.92 + { PRReqst req; 11.93 + 11.94 + req.reqType = LangShutdown; 11.95 + req.langMagicNumber = magicNum; 11.96 + req.nextReqst = NULL; 11.97 + callingSlv->request = &req; 11.98 + 11.99 + PR_WL__suspend_slaveVP_and_send_req( callingSlv ); 11.100 + } 11.101 + 11.102 11.103 /*This sends a PRLang request -- for probe, exception, and so on.. 11.104 * 11.105 @@ -221,7 +238,7 @@ 11.106 void 11.107 PR_WL__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ) 11.108 { PRReqst req; 11.109 - PRServReq langReq; 11.110 + PRServiceReq langReq; 11.111 11.112 req.reqType = Language; 11.113 req.langReq = &langReq;
12.1 --- a/PR__WL.h Tue Feb 05 20:23:27 2013 -0800 12.2 +++ b/PR__WL.h Sat Mar 02 09:43:45 2013 -0800 12.3 @@ -34,33 +34,64 @@ 12.4 * aren't meant for use in wrapper libraries, because they are themselves 12.5 * wrapper-library calls! 12.6 */ 12.7 -//========== Startup and shutdown ========== 12.8 + 12.9 +//============== Top level Fns called from main =============== 12.10 void 12.11 PR__start(); 12.12 12.13 -SlaveVP* 12.14 -PR_SS__create_shutdown_slave(); 12.15 +PRProcess * 12.16 +PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ); 12.17 12.18 void 12.19 -PR_SS__shutdown(); 12.20 +PR__end_seedVP( SlaveVP *seedSlv ); 12.21 12.22 void 12.23 -PR_SS__cleanup_at_end_of_shutdown(); 12.24 +PR__end_process_from_inside( SlaveVP *seedSlv ); 12.25 + 12.26 +void * 12.27 +PR__give_results_from_process_when_ready( PRProcess *process ); 12.28 12.29 void 12.30 -PR_SS__register_langlets_langEnv( PRLangEnv *langEnv, SlaveVP *seedVP, int32 VSs_MAGIC_NUMBER ); 12.31 +PR__wait_for_process_to_end( PRProcess *process ); 12.32 +fixme; //process->hasWaitingToEnd 12.33 + 12.34 +void 12.35 +PR__wait_for_all_activity_to_end(); 12.36 + 12.37 +void 12.38 +PR__shutdown(); 12.39 + 12.40 +#define \ 12.41 +PR__create_taskID_of_size PR_WL__create_taskID_of_size 12.42 + 12.43 +inline 12.44 +int32 * 12.45 +PR__give_ID_from_slave( SlaveVP *animSlv, int32 magicNumber ); 12.46 + 12.47 +inline 12.48 +int32 * 12.49 +PR__give_ID_from_lang_meta_task( void *_task ); 12.50 + 12.51 +#define \ 12.52 +PR__malloc PR_WL__malloc 12.53 + 12.54 +#define \ 12.55 +PR__free PR_WL__free 12.56 + 12.57 + 12.58 12.59 //============== include internally used fn prototypes ================ 12.60 #include "PR__int.h" 12.61 12.62 -//============== =============== 12.63 12.64 -inline 12.65 -SlaveVP * 12.66 -PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ); 12.67 +#define \ 12.68 +PR_WL__create_slaveVP PR_int__create_slaveVP_helper 12.69 12.70 +#define \ 12.71 +PR_WL__give_lang_meta_task_from_slave PR_int__give_lang_meta_task_from_slave 12.72 12.73 -#define PR_WL__create_slaveVP PR_int__create_slaveVP_helper 12.74 +#define \ 12.75 +PR_WL__give_prolog_of_lang_meta_task PR_int__give_prolog_of_lang_meta_task 12.76 12.77 //============== Request Related =============== 12.78 12.79 @@ -86,13 +117,12 @@ 12.80 inline void 12.81 PR_WL__send_service_request( void *langReqData, SlaveVP *callingSlv ); 12.82 12.83 -PRReqst * 12.84 -PR_PI__take_next_request_out_of( SlaveVP *slaveWithReq ); 12.85 -//#define PR_PI__take_next_request_out_of( slave ) slave->requests 12.86 +inline void 12.87 +PR_WL__send_lang_shutdown_request( SlaveVP *callingSlv, int32 magicNum ); 12.88 12.89 -//inline void * 12.90 -//PR_PI__take_lang_reqst_from( PRReqst *req ); 12.91 -#define PR_PI__take_lang_reqst_from( req ) req->langReqData 12.92 +inline 12.93 +int32 * 12.94 +PR_WL__create_taskID_of_size( int32 numInts ); 12.95 12.96 //======================== MEASUREMENT ====================== 12.97 uint64 12.98 @@ -106,15 +136,7 @@ 12.99 PR_WL__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); 12.100 #define PR_App__throw_exception PR_WL__throw_exception 12.101 12.102 -#define implement_me printf("Unimpl Fn: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) 12.103 -//#define fix_me printf("Fix me at: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) 12.104 12.105 -//========================= PR request handlers ======================== 12.106 -void inline 12.107 -handleMakeProbe( PRServReq *langReq, void *langEnv ); 12.108 - 12.109 -void inline 12.110 -handleThrowException( PRServReq *langReq, void *langEnv ); 12.111 //======================================================================= 12.112 12.113 //========================= Services =======================
13.1 --- a/PR__int.c Tue Feb 05 20:23:27 2013 -0800 13.2 +++ b/PR__int.c Sat Mar 02 09:43:45 2013 -0800 13.3 @@ -73,17 +73,15 @@ 13.4 13.5 newSlv = PR_int__create_slaveVP_helper( fnPtr, dataParam ); 13.6 13.7 - int32 * 13.8 - langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); 13.9 - langDatas[0] = NUM_IN_COLLECTION; //size held in prolog 13.10 - newSlv->langDatas = &(langDatas[1]); //skip over the size 13.11 + newSlv->langDatas = 13.12 + (PRLangData **)PR_int__make_collection_of_size( NUM_IN_COLLECTION ); 13.13 13.14 - int32 * 13.15 - metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); 13.16 - metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog 13.17 - newSlv->metaTasks = &(metaTasks[1]); 13.18 + newSlv->metaTasks = 13.19 + (PRMetaTask **) PR_int__make_collection_of_size( NUM_IN_COLLECTION ); 13.20 13.21 process->numLiveGenericSlvs += 1; 13.22 + 13.23 + return newSlv; 13.24 } 13.25 13.26 13.27 @@ -98,16 +96,13 @@ 13.28 retSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL ); 13.29 retSlv->typeOfVP = SlotTaskSlv; 13.30 13.31 - int32 * 13.32 - langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); 13.33 - langDatas[0] = NUM_IN_COLLECTION; //size held in prolog 13.34 - retSlv->langDatas = &(langDatas[1]); //skip over the size 13.35 + 13.36 + retSlv->langDatas = 13.37 + (PRLangData **) PR_int__make_collection_of_size( NUM_IN_COLLECTION ); 13.38 13.39 - int32 * 13.40 - metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); 13.41 - metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog 13.42 - retSlv->metaTasks = &(metaTasks[1]); 13.43 - 13.44 + retSlv->metaTasks = 13.45 + (PRMetaTask **) PR_int__make_collection_of_size( NUM_IN_COLLECTION ); 13.46 + 13.47 return retSlv; 13.48 } 13.49 13.50 @@ -145,29 +140,34 @@ 13.51 * either a recycled free task slave that finished it's task and has been 13.52 * idle in the recycle queue, or else create a new slave to be the slot slave. 13.53 *The master only calls this with a slot slave that needs to be replaced. 13.54 + * 13.55 + *The master continues after this call, handing the converted Free task slave 13.56 + * to a request handler, which places the converted slave into the langlet's 13.57 + * env, so it will eventually resume 13.58 */ 13.59 -inline void 13.60 -PR_int__replace_with_new_slot_slv( SlaveVP *requestingSlv, PRProcess *process ) 13.61 +inline 13.62 +void 13.63 +PR_int__replace_with_new_slot_slv( SlaveVP *oldSlotSlv ) 13.64 { SlaveVP *newSlotSlv; 13.65 - 13.66 + 13.67 //get a new slave to be the slot slave 13.68 - newSlotSlv = PR_int__get_recycled_slot_slave( process ); 13.69 + newSlotSlv = PR_int__get_recycled_slot_slave(); 13.70 13.71 //a slot slave is pinned to a particular slot on a particular core 13.72 //Note, this happens before the request is seen by handler, so nothing 13.73 // has had a chance to change the coreAnimatedBy or anything else.. 13.74 - newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo; 13.75 - newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy; 13.76 + newSlotSlv->animSlotAssignedTo = oldSlotSlv->animSlotAssignedTo; 13.77 + newSlotSlv->coreAnimatedBy = oldSlotSlv->coreAnimatedBy; 13.78 13.79 //put it into the slot slave matrix 13.80 - int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; 13.81 - int32 coreNum = requestingSlv->coreAnimatedBy; 13.82 + int32 slotNum = oldSlotSlv->animSlotAssignedTo->slotIdx; 13.83 + int32 coreNum = oldSlotSlv->coreAnimatedBy; 13.84 _PRTopEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv; 13.85 13.86 //Fix up requester, to be an extra slave now (but not an ended one) 13.87 // because it's active, doesn't go into freeTaskSlvRecycleQ 13.88 - requestingSlv->typeOfVP = FreeTaskSlv; 13.89 - requestingSlv->processSlaveIsIn = process; 13.90 + //Note that process was set when task was assigned to the slot slave.. 13.91 + oldSlotSlv->typeOfVP = FreeTaskSlv; 13.92 } 13.93 13.94 void idle_fn(void* data, SlaveVP *animatingSlv) 13.95 @@ -241,31 +241,42 @@ 13.96 PR_int__free( slave ); 13.97 } 13.98 13.99 -/*This calls recycle handler registered for each langlet's lang data and meta 13.100 - * task. It also recycles the slave struct. 13.101 +/*This calls the freer registered for each langlet's lang data and meta 13.102 + * task. Then it makes the collections empty. It also recycles the slave 13.103 + * struct. 13.104 + *Note: it does not clear "next in coll" pointers in the coll elements! 13.105 * 13.106 *DOES NOT DECREMENT NUMBER OF LIVE SLAVES IN PROCESS 13.107 - * 13.108 - *This assumes that each slave has an array of 13.109 + * 13.110 + *Note, the fn applied to all elements of collections checks the "don't delete" 13.111 + * flag in the lang data and the meta task.. so, if an alternative way of 13.112 + * freeing the slaveVP struct is created, it should handle the "don't delete" 13.113 + * flag. (although, an "abort" cleanup should ignore the don't delete flag) 13.114 */ 13.115 void 13.116 -PR_int__recycle_slave( SlaveVP *slave ) 13.117 +PR_int__recycle_slaveVP( SlaveVP *slave ) 13.118 { 13.119 PR_int__apply_Fn_to_all_in_collection( &freeLangDataAsElem, 13.120 (PRCollElem**) slave->langDatas ); 13.121 PR_int__apply_Fn_to_all_in_collection( &freeMetaTaskAsElem, 13.122 (PRCollElem**) slave->metaTasks ); 13.123 + //now, set the collections to "empty" 13.124 + PR_int__set_collection_to_empty((PRCollElem**) slave->langDatas); 13.125 + PR_int__set_collection_to_empty((PRCollElem**) slave->metaTasks); 13.126 13.127 writePrivQ( slave, _PRTopEnv->slaveRecycleQ ); 13.128 } 13.129 13.130 /*Receives a protoLangData, but in the form of a void, so have to cast 13.131 + *First checks the "no delete" flag.. 13.132 */ 13.133 void 13.134 freeLangDataAsElem( void *elem ) 13.135 { PRLangData *protoLangData; 13.136 13.137 protoLangData = (PRLangData *)elem; //recycler actually receives the prolog. 13.138 + if( protoLangData->goAheadAndFree == FALSE ) 13.139 + return; 13.140 13.141 //apply the free fn that's stored in the lang data prolog 13.142 //Note: freeing whole slave, so no need to remove from collection 13.143 @@ -285,6 +296,9 @@ 13.144 protoMetaTask = (PRMetaTask *)elem; //recycler receives the prolog, and must call 13.145 //a PR Fn to convert prolog to lang-specific version. 13.146 13.147 + if( protoMetaTask->goAheadAndFree == FALSE ) 13.148 + return; 13.149 + 13.150 //apply the free fn that's stored in the meta task prolog 13.151 (*(protoMetaTask->freer))( PR_int__give_lang_meta_task_of_prolog(protoMetaTask) ); 13.152 } 13.153 @@ -305,29 +319,34 @@ 13.154 return (PRLangEnv *) &(((PRLangEnv *)langEnv)[-1]); 13.155 } 13.156 13.157 -inline 13.158 +//inline 13.159 void * 13.160 -PR_int__create_lang_env_in_process( int32 size, PRProcess process, int32 magicNum ) 13.161 +PR_int__create_lang_env_in_process( int32 numBytes, PRProcess *process, int32 magicNum ) 13.162 { PRLangEnv *retEnv; 13.163 PRCollElem **langEnvs; 13.164 13.165 //make the new lang env, with room for the prolog 13.166 - retEnv = PR_int__malloc( sizeof(PRLangEnv) + size ); 13.167 + retEnv = PR_int__malloc( sizeof(PRLangEnv) + numBytes ); 13.168 + retEnv->chainedLangEnv = NULL; //used while inserting into langEnvs 13.169 + retEnv->langMagicNumber = magicNum; //used while inserting into langEnvs 13.170 + retEnv->processEnvIsIn = process; 13.171 + retEnv->numLiveWork = 0; 13.172 + retEnv->waitingForWorkToEndQ = makePrivQ(); 13.173 13.174 //process has a PR Collection of lang envs -- get it and insert into it 13.175 langEnvs = (PRCollElem **)process->langEnvs; 13.176 PR_int__insert_elem_into_collection( (PRCollElem *)retEnv, langEnvs, magicNum); 13.177 - int32 idxInProcess = process->numLangEnvs; 13.178 - process->langEnvsList[idxInProcess] = retEnv; 13.179 + int32 idxInProcess = process->numLangEnvs; //index starts at 0 for first lang 13.180 + process->protoLangEnvsList[idxInProcess] = retEnv; 13.181 retEnv->idxInProcess = idxInProcess; 13.182 process->numLangEnvs += 1; 13.183 13.184 - return &(retEnv[1]); //skip over prolog 13.185 + return (void *)&(retEnv[1]); //skip over prolog 13.186 } 13.187 13.188 inline 13.189 void * 13.190 -PR_int__free_lang_env( void *langEnv ) 13.191 +PR_int__remove_lang_env_from_process_and_free( void *langEnv ) 13.192 { PRLangEnv *protoLangEnv = PR_int__give_proto_lang_env( langEnv ); 13.193 PRCollElem **langEnvs; 13.194 PRLangEnv **langEnvsList; 13.195 @@ -335,11 +354,11 @@ 13.196 //process has a PR Collection of lang envs -- get it and remove env 13.197 PRProcess *process = protoLangEnv->processEnvIsIn; 13.198 langEnvs = (PRCollElem **)process->langEnvs; 13.199 - PR_int__remove_elem_from_collection( (PRCollElem *)protoLangEnv, langEnvs ); 13.200 + PR_int__remove_elem_from_collection( protoLangEnv->langMagicNumber, langEnvs ); 13.201 int32 count, idx; 13.202 idx = protoLangEnv->idxInProcess; 13.203 - count = (process->numLangEnvs - idx - 1) * sizeof(PRLangEnv *); 13.204 - memmove( langEnvsList[idx], langEnvsList[idx+1], count); 13.205 + count = (process->numLangEnvs - idx) * sizeof(PRLangEnv *);//idx starts at 0 13.206 + memmove( &(langEnvsList[idx]), &(langEnvsList[idx+1]), count); 13.207 13.208 PR_int__free( protoLangEnv ); 13.209 } 13.210 @@ -362,7 +381,7 @@ 13.211 PRLangEnv * 13.212 PR_int__give_proto_lang_env_for_slave( SlaveVP *slave, int32 magicNum ) 13.213 { 13.214 - return PR_int__give_proto_lang_env_for_process( slave->processSlaveIsIn, magicNum ); 13.215 + return PR_int__give_proto_lang_env_from_process( slave->processSlaveIsIn, magicNum ); 13.216 } 13.217 13.218 inline 13.219 @@ -380,7 +399,7 @@ 13.220 } 13.221 inline 13.222 PRLangEnv * 13.223 -PR_int__give_proto_lang_env_for_process( PRProcess *process, int32 magicNum ) 13.224 +PR_int__give_proto_lang_env_from_process( PRProcess *process, int32 magicNum ) 13.225 { PRLangEnv *retLangEnv; 13.226 PRCollElem **langEnvs; 13.227 13.228 @@ -453,25 +472,29 @@ 13.229 */ 13.230 inline 13.231 void 13.232 -PR_int__put_task_into_slot( PRMetaTask *task, PRProcess *process, AnimSlot *slot ) 13.233 +PR_int__put_task_into_slot( void *langMetaTask, AnimSlot *slot ) 13.234 { int32 slotNum, coreNum; 13.235 SlaveVP *slotSlv; 13.236 + PRMetaTask *protoMetaTask; 13.237 13.238 + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); 13.239 + 13.240 //get the slot slave to assign the task to.. 13.241 slotNum = slot->slotIdx; 13.242 coreNum = slot->coreSlotIsOn; 13.243 slotSlv = _PRTopEnv->slotTaskSlvs[coreNum][slotNum]; 13.244 13.245 //point slave to task's function 13.246 - PR_int__reset_slaveVP_to_TopLvlFn( slotSlv, task->topLevelFn, task->initData ); 13.247 - PR_int__insert_meta_task_into_slave( task, slotSlv ); 13.248 + PR_int__reset_slaveVP_to_TopLvlFn( slotSlv, protoMetaTask->topLevelFn, protoMetaTask->initData ); 13.249 + PR_int__insert_meta_task_into_slave( protoMetaTask, slotSlv ); 13.250 + slotSlv->processSlaveIsIn = protoMetaTask->processTaskIsIn; 13.251 PR_int__put_slave_into_slot( slotSlv, slot ); 13.252 } 13.253 13.254 //========================== 13.255 inline 13.256 PRMetaTask * 13.257 -PR_int__give_prolog_of_task( void *task ) 13.258 +PR_int__give_prolog_of_lang_meta_task( void *task ) 13.259 { 13.260 return (PRMetaTask *) &(((PRMetaTask *)task)[-1]); 13.261 } 13.262 @@ -497,19 +520,33 @@ 13.263 retMetaTask->taskType = SlotTask; //just common default 13.264 retMetaTask->ID = NULL; 13.265 retMetaTask->freer = freer; 13.266 + retMetaTask->goAheadAndFree = TRUE; 13.267 13.268 return retMetaTask; //skip over prolog 13.269 } 13.270 13.271 -/*Might never need this fn -- think the slave dissipator does this work 13.272 +/*Calls the lang's freer, which is pointed to, and also removes from collection 13.273 + */ 13.274 +void 13.275 +PR_int__free_lang_meta_task_and_remove_from_coll( void *langMetaTask) 13.276 + { PRMetaTask *protoMetaTask; 13.277 + 13.278 + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); 13.279 + PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber, 13.280 + (PRCollElem **) protoMetaTask->slaveAssignedTo->metaTasks ); 13.281 + 13.282 + (*protoMetaTask->freer)(langMetaTask); 13.283 + PR_int__free( protoMetaTask ); 13.284 + } 13.285 + 13.286 +/*Just calls the lang's freer, and frees the malloc'd meta-task chunk. Should 13.287 + * already have been removed from slave's collection and all queues holding it 13.288 */ 13.289 void 13.290 PR_int__free_lang_meta_task( void *langMetaTask) 13.291 { PRMetaTask *protoMetaTask; 13.292 13.293 - protoMetaTask = PR_int__give_prolog_of_task( langMetaTask ); 13.294 - PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber, 13.295 - protoMetaTask->slaveAssignedTo->metaTasks ); 13.296 + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); 13.297 13.298 (*protoMetaTask->freer)(langMetaTask); 13.299 PR_int__free( protoMetaTask ); 13.300 @@ -578,22 +615,16 @@ 13.301 metaTasks = (PRCollElem **)slave->metaTasks; 13.302 retMetaTask = PR_int__lookup_elem_in_collection( magicNum, metaTasks ); 13.303 if( retMetaTask != NULL ) 13.304 - return &(retMetaTask[1]); //skip over prolog 13.305 + return PR_int__give_lang_meta_task_of_prolog(retMetaTask); //skip over prolog 13.306 else 13.307 - { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave ); 13.308 + { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, magicNum ); 13.309 if(protoLangEnv->langMetaTaskCreator == NULL) 13.310 - PR_int__throw_exception("register a meta task creator"); 13.311 + PR_int__error("register a meta task creator"); 13.312 //This will call 13.313 return (*protoLangEnv->langMetaTaskCreator)( slave ); 13.314 } 13.315 } 13.316 13.317 -inline 13.318 -SlaveVP * 13.319 -PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ) 13.320 - { PRMetaTask *metaTask = &(((PRMetaTask*)langMetaTask)[-1]); 13.321 - return metaTask->slaveAssignedTo; 13.322 - } 13.323 13.324 //================== langData ============================= 13.325 inline 13.326 @@ -628,6 +659,7 @@ 13.327 retLangData->chainedLangData = NULL; 13.328 retLangData->langMagicNumber = magicNum; 13.329 retLangData->freer = freer; 13.330 + retLangData->goAheadAndFree = TRUE; 13.331 retLangData->slaveAssignedTo = slave; 13.332 13.333 //multilang has a "collection" of lang datas inside the slave 13.334 @@ -642,7 +674,7 @@ 13.335 13.336 protoLangData = PR_int__give_prolog_of_lang_data( langData ); 13.337 PR_int__remove_elem_from_collection( protoLangData->langMagicNumber, 13.338 - protoLangData->slaveAssignedTo->langDatas ); 13.339 + (PRCollElem **) protoLangData->slaveAssignedTo->langDatas ); 13.340 13.341 (*protoLangData->freer)(langData); 13.342 PR_int__free( protoLangData ); 13.343 @@ -660,9 +692,9 @@ 13.344 if( retLangData != NULL ) 13.345 return &( retLangData[1] ); //skip over prolog 13.346 else 13.347 - { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave ); 13.348 + { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, magicNum ); 13.349 if(protoLangEnv->langDataCreator == NULL) 13.350 - PR_int__throw_exception("register a lang data creator"); 13.351 + PR_int__error("register a lang data creator"); 13.352 //This will call PR_PI__create_lang_data_in_slave 13.353 return (*protoLangEnv->langDataCreator)( slave ); 13.354 } 13.355 @@ -670,6 +702,22 @@ 13.356 13.357 13.358 //=============================================== 13.359 +PRCollElem ** //return an array of pointers 13.360 +PR_int__make_collection_of_size( int32 numInColl ) 13.361 + { int32 *prolog; 13.362 + PRCollElem **coll; 13.363 + //Note using size of a pointer to a coll element 13.364 + int32 numBytes = sizeof(int32) + numInColl * sizeof(PRCollElem *); 13.365 + prolog = PR_WL__malloc( numBytes ); 13.366 + 13.367 + //operation of collection relies upon initial entries being NULL 13.368 + memset(prolog, ZERO, numBytes>>2); //BUG: if size not multiple of 4 13.369 + 13.370 + prolog[0] = numInColl; 13.371 + coll = (PRCollElem **)&(prolog[1]); 13.372 + return coll; 13.373 + } 13.374 + 13.375 inline 13.376 void 13.377 PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash ) 13.378 @@ -733,32 +781,51 @@ 13.379 test = test->chained; 13.380 if( test == NULL ) return; //not found, nothing to remove 13.381 } 13.382 - if( prev == NULL) 13.383 + if( prev == NULL) //is first elem in chain, so modify ptr in array 13.384 { coll[idx] = coll[idx]->chained; 13.385 return; 13.386 } 13.387 - else 13.388 + else //remove link from chain 13.389 { prev->chained = test->chained; 13.390 return; 13.391 } 13.392 } 13.393 13.394 + 13.395 +/*The function is allowed to modify its OWN chaining.. this takes the next 13.396 + * in chain before calling the function (useful when the function conditionally 13.397 + * frees) 13.398 + */ 13.399 inline 13.400 void 13.401 -PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem *coll ) 13.402 +PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem **coll ) 13.403 { int32 idx, numIdxsInColl; 13.404 - PRCollElem *test; 13.405 + PRCollElem *test, *chainedTest; 13.406 13.407 numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs 13.408 - for( idx = 0; idx < ; idx++ ) 13.409 + //march down array of elements, for each, march down linked chain of elems 13.410 + for( idx = 0; idx < numIdxsInColl; idx++ ) 13.411 { test = coll[idx]; 13.412 while( test != NULL ) 13.413 - { (*Fn)((void *)test); 13.414 - test = test->chained; 13.415 + { chainedTest = test->chained; //Fn may destroy test or change test->chained 13.416 + (*Fn)((void *)test); 13.417 + test = chainedTest; 13.418 } 13.419 } 13.420 } 13.421 13.422 +/*Just sets all entries to NULL -- doesn't modify chaining of any elements 13.423 + * that may be left in the collection.. 13.424 + */ 13.425 +inline 13.426 +void 13.427 +PR_int__set_collection_to_empty( PRCollElem **coll ) 13.428 + { int32 numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs 13.429 + memset( coll, 0, numIdxsInColl * sizeof(PRCollElem *) ); 13.430 + } 13.431 +//========================================== 13.432 + 13.433 + 13.434 //========================================== 13.435 13.436 /*Later, improve this -- for now, just exits the application after printing 13.437 @@ -772,13 +839,20 @@ 13.438 exit(1); 13.439 } 13.440 13.441 +void 13.442 +PR_int__error( char *msgStr ) 13.443 + { 13.444 + printf("%s",msgStr); 13.445 + fflush(stdin); 13.446 + exit(1); 13.447 + } 13.448 13.449 -inline 13.450 + 13.451 char * 13.452 PR_int__strDup( char *str ) 13.453 { char *retStr; 13.454 13.455 - if( str == NULL ) return (char *)NULL; 13.456 + if( str == NULL ) return NULL; 13.457 retStr = (char *)PR_int__malloc( strlen(str) + 1 ); 13.458 strcpy( retStr, str ); 13.459 13.460 @@ -793,13 +867,16 @@ 13.461 PR_int__get_master_lock() 13.462 { int32 *addrOfMasterLock; 13.463 13.464 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 13.465 + return; 13.466 + #endif 13.467 + 13.468 addrOfMasterLock = &(_PRTopEnv->masterLock); 13.469 13.470 int numTriesToGetLock = 0; 13.471 int gotLock = 0; 13.472 13.473 MEAS__Capture_Pre_Master_Lock_Point; 13.474 - 13.475 while( !gotLock ) //keep going until get master lock 13.476 { 13.477 numTriesToGetLock++; //if too many, means too much contention
14.1 --- a/PR__int.h Tue Feb 05 20:23:27 2013 -0800 14.2 +++ b/PR__int.h Sat Mar 02 09:43:45 2013 -0800 14.3 @@ -20,10 +20,6 @@ 14.4 */ 14.5 14.6 inline 14.7 -PRMetaTask * 14.8 -PR_int__create_generic_slave_meta_task( void *initData ); 14.9 - 14.10 -inline 14.11 void 14.12 PR_int__reset_slaveVP_to_TopLvlFn( SlaveVP *slaveVP, TopLevelFnPtr fnPtr, 14.13 void *dataParam); 14.14 @@ -64,7 +60,7 @@ 14.15 14.16 inline 14.17 void 14.18 -PR_int__put_task_into_slot( PRMetaTask *task, PRProcess *process, AnimSlot *slot ); 14.19 +PR_int__put_task_into_slot( void *task, AnimSlot *slot ); 14.20 14.21 inline 14.22 void 14.23 @@ -74,16 +70,10 @@ 14.24 PRHandle__ServiceReq( SlaveVP *requestingSlv ); 14.25 14.26 void 14.27 -PR_WL__suspend_slaveVP_and_send_req( SlaveVP *animatingSlv ); 14.28 - 14.29 -void 14.30 -PR_int__dissipate_slaveVP__SL( SlaveVP *animatingSlv ); 14.31 - 14.32 -void 14.33 PR_int__free_slaveVP( SlaveVP *slave ); 14.34 14.35 void 14.36 -PR_int__recycle_slave( SlaveVP *slave ); 14.37 +PR_int__recycle_slaveVP( SlaveVP *slave ); 14.38 14.39 void 14.40 freeLangDataAsElem( void *elem ); 14.41 @@ -91,6 +81,10 @@ 14.42 void 14.43 freeMetaTaskAsElem( void *elem ); 14.44 14.45 + 14.46 +//============================= 14.47 +//=== Lange Env 14.48 +//= 14.49 inline 14.50 void * 14.51 PR_int__give_lang_env( PRLangEnv *protoLangEnv ); 14.52 @@ -99,13 +93,13 @@ 14.53 PRLangEnv * 14.54 PR_int__give_proto_lang_env( void *langEnv ); 14.55 14.56 -inline 14.57 +//inline 14.58 void * 14.59 PR_int__create_lang_env_in_process( int32 size, PRProcess *process, int32 magicNum ); 14.60 14.61 inline 14.62 void * 14.63 -PR_int__free_lang_env( void *langEnv ); 14.64 +PR_int__remove_lang_env_from_process_and_free( void *langEnv ); 14.65 14.66 inline 14.67 void * 14.68 @@ -114,42 +108,28 @@ 14.69 inline 14.70 void * 14.71 PR_int__give_lang_env_for_slave( SlaveVP *slave, int32 magicNum ); 14.72 -#define PR_PI__give_lang_env_for PR_int__give_lang_env_for_slave 14.73 -#define PR_SS__give_lang_env_for_slave PR_int__give_lang_env_for_slave 14.74 //No WL version -- not safe! if use env in WL, be sure data rd & wr is stable 14.75 14.76 inline 14.77 PRLangEnv * 14.78 -PR_int__give_proto_lang_env_for_slave__ML( SlaveVP *slave, int32 magicNumber ); 14.79 -#define PR_PI__give_proto_lang_env_for PR_int__give_proto_lang_env_for_slave__ML 14.80 -#define PR_SS__give_proto_lang_env_for_slave PR_int__give_proto_lang_env_for_slave__ML 14.81 +PR_int__give_proto_lang_env_for_slave( SlaveVP *slave, int32 magicNumber ); 14.82 //No WL version -- not safe! if use env in WL, be sure data rd & wr is stable 14.83 14.84 inline 14.85 void * 14.86 PR_int__give_lang_env_from_process( PRProcess *process, int32 magicNum ); 14.87 -#define PR_PI__give_lang_env_from_process PR_int__give_lang_env_from_process 14.88 -#define PR_SS__give_lang_env_from_process PR_int__give_lang_env_from_process 14.89 -//#define PR_WL__give_lang_env_from_process PR_int__give_lang_env_from_process 14.90 //No WL version -- not safe! if use env in WL, be sure data rd & wr is stable 14.91 14.92 inline 14.93 PRLangEnv * 14.94 -PR_int__give_proto_lang_env_for_process( PRProcess *process, int32 magicNum ); 14.95 +PR_int__give_proto_lang_env_from_process( PRProcess *process, int32 magicNum ); 14.96 14.97 -/* 14.98 -inline 14.99 -void 14.100 -PR_int__set_work_in_lang_env( void *_langEnv ); 14.101 - 14.102 -inline 14.103 -void 14.104 -PR_int__clear_work_in_lang_env( void *_langEnv ); 14.105 - */ 14.106 - 14.107 +//======================= 14.108 +//=== Meta Task 14.109 +//= 14.110 inline 14.111 PRMetaTask * 14.112 -PR_int__give_prolog_of_task( void *task ); 14.113 +PR_int__give_prolog_of_lang_meta_task( void *task ); 14.114 14.115 inline 14.116 void * 14.117 @@ -157,11 +137,19 @@ 14.118 14.119 inline 14.120 void * 14.121 -PR_int__create_lang_meta_task( int32 size, int32 magicNum ); 14.122 +PR_int__create_lang_meta_task( int32 size, LangMetaTaskFreer freer, int32 magicNum ); 14.123 14.124 inline 14.125 void * 14.126 -PR_int__create_lang_meta_task_in_slave( int32 size, SlaveVP *slave, int32 magicNum ); 14.127 +PR_int__create_lang_meta_task_in_slave( int32 size, LangMetaTaskFreer freer, 14.128 + SlaveVP *slave, int32 magicNum ); 14.129 + 14.130 +inline 14.131 +PRMetaTask * 14.132 +PR_int__create_generic_slave_meta_task( void *initData ); 14.133 + 14.134 +void 14.135 +PR_int__free_lang_meta_task_and_remove_from_coll( void *langMetaTask ); 14.136 14.137 inline 14.138 void 14.139 @@ -174,28 +162,35 @@ 14.140 inline 14.141 void * 14.142 PR_int__give_lang_meta_task_from_slave( SlaveVP *slave, int32 magicNumer ); 14.143 -//#define PR_int__give_lang_meta_task_from_slave__ML( slave, magicNumber )\ 14.144 - slave->metaTask->langMetaTask; 14.145 -#define PR_PI__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave 14.146 -#define PR_SS__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave 14.147 -#define PR_WL__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave 14.148 14.149 inline 14.150 SlaveVP * 14.151 PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ); 14.152 14.153 +//============== 14.154 +//=== Lang Data 14.155 +//= 14.156 inline 14.157 void * 14.158 -PR_PI__create_lang_data_in_slave( int32 size, SlaveVP *slave, int32 magicNum ); 14.159 +PR_PI__create_lang_data_in_slave( int32 size, LangDataFreer freer, 14.160 + SlaveVP *slave, int32 magicNum ); 14.161 14.162 inline 14.163 void * 14.164 PR_int__give_lang_data_from_slave( SlaveVP *slave, int32 magicNumer ); 14.165 -#define PR_PI__give_lang_data PR_int__give_lang_data_from_slave 14.166 -#define PR_SS__give_lang_data PR_int__give_lang_data_from_slave 14.167 #define PR_WL__give_lang_data PR_int__give_lang_data_from_slave 14.168 14.169 inline 14.170 +void * 14.171 +PR_int__give_lang_data_of_prolog( PRLangData *langData); 14.172 + 14.173 +//================================================== 14.174 +//=== Collection 14.175 +//= 14.176 +PRCollElem ** //return an array of pointers 14.177 +PR_int__make_collection_of_size( int32 numInColl ); 14.178 + 14.179 +inline 14.180 void 14.181 PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash ); 14.182 14.183 @@ -209,19 +204,25 @@ 14.184 14.185 inline 14.186 void 14.187 -PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem *coll ); 14.188 +PR_int__set_collection_to_empty( PRCollElem **coll ); 14.189 + 14.190 +inline 14.191 +void 14.192 +PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem **coll ); 14.193 + 14.194 +//=========== 14.195 +//=== 14.196 +//= 14.197 +void 14.198 +PR_int__error( char *msgStr ); 14.199 14.200 void 14.201 PR_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); 14.202 -#define PR_PI__throw_exception PR_int__throw_exception 14.203 14.204 -inline char * 14.205 +char * 14.206 PR_int__strDup( char *str ); 14.207 14.208 inline void 14.209 -PR_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock ); 14.210 - 14.211 -inline void 14.212 PR_int__get_master_lock(); 14.213 14.214 #define PR_int__release_master_lock() _PRTopEnv->masterLock = UNLOCKED
15.1 --- a/PR__structs.h Tue Feb 05 20:23:27 2013 -0800 15.2 +++ b/PR__structs.h Sat Mar 02 09:43:45 2013 -0800 15.3 @@ -17,7 +17,10 @@ 15.4 15.5 15.6 //================================ Typedefs ================================= 15.7 -// 15.8 +//=== 15.9 +//= 15.10 +#define ZERO 0 15.11 + 15.12 typedef unsigned long long TSCount; 15.13 15.14 typedef struct _AnimSlot AnimSlot; 15.15 @@ -30,13 +33,13 @@ 15.16 typedef struct _PRLangData PRLangData; //a prolog 15.17 typedef struct _PRCollElem PRCollElem; //generic form of the prologs 15.18 15.19 -typedef SlaveVP *(*SlaveAssigner) ( void *, AnimSlot* ); //langEnv, slot for HW info 15.20 +typedef bool32 (*SlaveAssigner) ( void *, AnimSlot* ); //langEnv, slot for HW info 15.21 typedef void (*RequestHandler) ( void *, SlaveVP *, void * ); //req, slv, langEnv 15.22 typedef void *(*CreateHandler) ( void *, SlaveVP *, void * ); //req, slv, langEnv 15.23 typedef void (*LangShutdownHdlr) ( void * ); //langEnv 15.24 typedef void *(*LangDataCreator) ( SlaveVP * ); 15.25 typedef void (*LangDataFreer) ( void * ); //lang data to free 15.26 -typedef void *(*LangMetaTaskCreator)( SlaveVP * ); 15.27 +typedef void *(*LangMetaTaskCreator)( SlaveVP * ); //when slave has no meta task for magic num 15.28 typedef void (*LangMetaTaskFreer) ( void * ); //lang meta task to free 15.29 typedef void (*MakeSlaveReadyFn) ( SlaveVP *, void * ); //slave and langEnv 15.30 typedef void (*MakeTaskReadyFn) ( void *, void * ); //langTask and langEnv 15.31 @@ -73,7 +76,7 @@ 15.32 void *resultToReturn; 15.33 15.34 PRLangEnv **langEnvs; //used as a hash table 15.35 - PRLangEnv **langEnvsList; //for fast linear scan of envs 15.36 + PRLangEnv **protoLangEnvsList; //for fast linear scan of envs 15.37 int32 numLangEnvs; //for fast linear scan of envs 15.38 15.39 SlaveVP *seedSlv; 15.40 @@ -86,6 +89,7 @@ 15.41 15.42 15.43 //These are used to coord with an OS thread waiting for process to end 15.44 + bool32 hasWaitingToEnd; 15.45 bool32 executionIsComplete; 15.46 pthread_mutex_t doneLock; 15.47 pthread_cond_t doneCond; 15.48 @@ -124,9 +128,13 @@ 15.49 Service, //To invoke a PR provided equivalent of a language request (ex: probe) 15.50 Hardware, 15.51 IO, 15.52 - OSCall 15.53 + OSCall, 15.54 + LangShutdown, 15.55 + ProcessEnd, 15.56 + PRShutdown 15.57 }; 15.58 15.59 + 15.60 struct _PRReqst 15.61 { 15.62 enum PRReqstType reqType;//used for special forms that have PR behavior 15.63 @@ -149,7 +157,7 @@ 15.64 }; 15.65 //PRReqst 15.66 15.67 -enum PRServReqType //These are equivalent to lang requests, but for 15.68 +enum PRServiceReqType //These are equivalent to lang requests, but for 15.69 { // PR's services available directly to app, like OS 15.70 make_probe = 1, // and probe services -- like a PR-wide built-in lang 15.71 throw_excp, 15.72 @@ -158,13 +166,13 @@ 15.73 }; 15.74 15.75 typedef struct 15.76 - { enum PRServReqType reqType; 15.77 + { enum PRServiceReqType reqType; 15.78 SlaveVP *requestingSlv; 15.79 char *nameStr; //for create probe 15.80 char *msgStr; //for exception 15.81 void *exceptionData; 15.82 } 15.83 -PRServReq; 15.84 +PRServiceReq; 15.85 15.86 15.87 //==================== Core data structures =================== 15.88 @@ -192,9 +200,9 @@ 15.89 FreeTaskSlv, //When a suspended task ends, the slave becomes this 15.90 GenericSlv, //the VP is explicitly seen in the app code, or task suspends 15.91 SeedSlv, 15.92 - Master, 15.93 - Shutdown, 15.94 - Idle 15.95 + Master_VP, 15.96 + ShutdownVP, 15.97 + IdleVP 15.98 }; 15.99 15.100 /*This structure embodies the state of a slaveVP. It is reused for masterVP 15.101 @@ -228,8 +236,8 @@ 15.102 //For language specific data that needs to be in the slave 15.103 //These are accessed directly for single-lang, but multi-lang places 15.104 // a holder here instead, then uses magic num to get lang's version 15.105 - void *langDatas; //Lang saves lang-specific things in slave here 15.106 - void *metaTasks; 15.107 + PRLangData **langDatas; //Lang saves lang-specific things in slave here 15.108 + PRMetaTask **metaTasks; 15.109 15.110 //=========== MEASUREMENT STUFF ========== 15.111 MEAS__Insert_Meas_Fields_into_Slave; 15.112 @@ -335,16 +343,6 @@ 15.113 LangMetaTaskCreator langMetaTaskCreator; 15.114 MakeSlaveReadyFn makeSlaveReadyFn; 15.115 MakeTaskReadyFn makeTaskReadyFn; 15.116 -/* 15.117 - CreateTaskHdlr createTaskHdlr; 15.118 - RequestHandler endTaskHdlr; 15.119 - CreateSlvHdlr createSlaveHdlr; 15.120 - RequestHandler dissipateSlaveHdlr; 15.121 - 15.122 - LangDataFreer langDataFreer; 15.123 - LangMetaTaskFreer langMetaTaskFreer; 15.124 - RequestHandler langDataInitializer; 15.125 - */ 15.126 15.127 //when multi-lang, master polls lang env's to find one with work in it.. 15.128 // in single-lang case, flag ignored, master always asks lang for work 15.129 @@ -354,7 +352,9 @@ 15.130 int32 idxInProcess; //index into array of langEnvs in the process 15.131 15.132 int32 numReadyWork; 15.133 - fixme; //make make_ready update the process's numEnvs with work 15.134 + 15.135 + int32 numLiveWork; 15.136 + PrivQueueStruc *waitingForWorkToEndQ; 15.137 }; 15.138 //PRLangEnv -- this is the prolog of every lang's lang env 15.139 15.140 @@ -371,10 +371,12 @@ 15.141 //============================================================= 15.142 enum PRTaskType taskType; 15.143 int32 *ID; //is standard PR ID 15.144 - SlaveVP *slaveAssignedTo; //no valid until task animated 15.145 + PRProcess *processTaskIsIn; 15.146 + SlaveVP *slaveAssignedTo; //not valid until task animated 15.147 TopLevelFnPtr topLevelFn; //This is the Fn executes as the task 15.148 void *initData; //The data taken by the function 15.149 LangMetaTaskFreer freer; 15.150 + bool32 goAheadAndFree; 15.151 15.152 //NOTE: info needed for "wait" functionality is inside lang's metaTask 15.153 }; 15.154 @@ -386,6 +388,7 @@ 15.155 PRLangData *chainedLangData; 15.156 //============================================================= 15.157 LangDataFreer freer; 15.158 + bool32 goAheadAndFree; 15.159 SlaveVP *slaveAssignedTo; 15.160 }; 15.161 //PRLangData -- this is the prolog of each lang's lang data 15.162 @@ -399,16 +402,6 @@ 15.163 15.164 15.165 15.166 -//The language env of PR's services langlet 15.167 -typedef struct 15.168 - { 15.169 - PrivQueueStruc *slavesReadyToResumeQ; //Shared (slaves not pinned) 15.170 - PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) 15.171 - } 15.172 -PRServLangEnv; 15.173 - 15.174 - 15.175 - 15.176 //========================= Extra Stuff Data Strucs ======================= 15.177 typedef struct 15.178 {
16.1 --- a/Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h Tue Feb 05 20:23:27 2013 -0800 16.2 +++ b/Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h Sat Mar 02 09:43:45 2013 -0800 16.3 @@ -501,7 +501,7 @@ 16.4 #define MEAS__Make_Meas_Hists_for_Language 16.5 #endif 16.6 16.7 -#define makeAMeasHist( idx, name, numBins, startVal, binWidth ) \ 16.8 +#define makeAMeasHist( histInfo, idx, name, numBins, startVal, binWidth ) \ 16.9 makeHighestDynArrayIndexBeAtLeast( _PRTopEnv->measHistsInfo, idx ); \ 16.10 _PRTopEnv->measHists[idx] = \ 16.11 makeFixedBinHist( numBins, startVal, binWidth, name );
17.1 --- a/Services_Offered_by_PR/Measurement_and_Stats/probes.c Tue Feb 05 20:23:27 2013 -0800 17.2 +++ b/Services_Offered_by_PR/Measurement_and_Stats/probes.c Sat Mar 02 09:43:45 2013 -0800 17.3 @@ -49,7 +49,7 @@ 17.4 IntervalProbe * 17.5 create_generic_probe( char *nameStr, SlaveVP *animSlv ) 17.6 { 17.7 - PRServReq reqData; 17.8 + PRServiceReq reqData; 17.9 17.10 reqData.reqType = make_probe; 17.11 reqData.nameStr = nameStr; 17.12 @@ -189,7 +189,7 @@ 17.13 probe = _PRTopEnv->intervalProbes[ probeID ]; 17.14 probe->schedChoiceWasRecorded = TRUE; 17.15 probe->coreNum = animatingSlv->coreAnimatedBy; 17.16 - probe->slaveID = animatingSlv->slaveID; 17.17 + probe->slaveNum = animatingSlv->slaveNum; 17.18 probe->slaveCreateSecs = animatingSlv->createPtInSecs; 17.19 } 17.20 17.21 @@ -265,8 +265,8 @@ 17.22 17.23 17.24 if( probe->schedChoiceWasRecorded ) 17.25 - { printf( "coreNum: %d, slaveID: %d, slaveVPCreated: %0.6f | ", 17.26 - probe->coreNum, probe->slaveID, probe->slaveCreateSecs ); 17.27 + { printf( "coreNum: %d, slaveNum: %d, slaveVPCreated: %0.6f | ", 17.28 + probe->coreNum, probe->slaveNum, probe->slaveCreateSecs ); 17.29 } 17.30 17.31 if( probe->endSecs == 0 ) //just a single point in time
18.1 --- a/Services_Offered_by_PR/Measurement_and_Stats/probes.h Tue Feb 05 20:23:27 2013 -0800 18.2 +++ b/Services_Offered_by_PR/Measurement_and_Stats/probes.h Sat Mar 02 09:43:45 2013 -0800 18.3 @@ -65,7 +65,7 @@ 18.4 18.5 int32 schedChoiceWasRecorded; 18.6 int32 coreNum; 18.7 - int32 slaveID; 18.8 + int32 slaveNum; 18.9 float64 slaveCreateSecs; 18.10 PROBES__Insert_timestamps_and_intervals_into_probe_struct; 18.11 };
19.1 --- a/Services_Offered_by_PR/Memory_Handling/vmalloc.h Tue Feb 05 20:23:27 2013 -0800 19.2 +++ b/Services_Offered_by_PR/Memory_Handling/vmalloc.h Sat Mar 02 09:43:45 2013 -0800 19.3 @@ -54,24 +54,18 @@ 19.4 19.5 void * 19.6 PR_int__malloc( size_t sizeRequested ); 19.7 -#define PR_PI__malloc PR_int__malloc 19.8 -#define PR_SS__malloc PR_int__malloc 19.9 19.10 void * 19.11 PR_WL__malloc( int32 sizeRequested ); /*BUG: -- get master lock */ 19.12 -#define PR_App__malloc PR_WL__malloc 19.13 19.14 void * 19.15 PR_int__malloc_aligned( size_t sizeRequested ); 19.16 -#define PR_PI__malloc_aligned PR_int__malloc_aligned 19.17 19.18 void 19.19 PR_int__free( void *ptrToFree ); 19.20 -#define PR_PI__free PR_int__free 19.21 19.22 void 19.23 PR_WL__free( void *ptrToFree ); 19.24 -#define PR_App__free PR_WL__free 19.25 19.26 19.27
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/Services_Offered_by_PR/Services_Language/Measurement/PRServ_Measurement.h Sat Mar 02 09:43:45 2013 -0800 20.3 @@ -0,0 +1,16 @@ 20.4 +/* 20.5 + * Copyright 2009 OpenSourceResearchInstitute.org 20.6 + * Licensed under GNU General Public License version 2 20.7 + * 20.8 + * Author: seanhalle@yahoo.com 20.9 + * 20.10 + */ 20.11 + 20.12 +#ifndef _PRServ_MEAS_H 20.13 +#define _PRServ_MEAS_H 20.14 + 20.15 + 20.16 + #define MEAS__Make_Meas_Hists_for_PRServ 20.17 + 20.18 +#endif /* */ 20.19 +
21.1 --- a/Services_Offered_by_PR/Services_Language/PRServ.c Tue Feb 05 20:23:27 2013 -0800 21.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ.c Sat Mar 02 09:43:45 2013 -0800 21.3 @@ -4,6 +4,30 @@ 21.4 * Licensed under BSD 21.5 */ 21.6 21.7 +//=========================================================================== 21.8 +// 21.9 +//=========================================================================== 21.10 +/*These are the library functions *called in the application* 21.11 + * 21.12 + *There's a pattern for the outside sequential code to interact with the 21.13 + * PR_HW code. 21.14 + *The PR_HW system is inside a boundary.. every PRServ system is in its 21.15 + * own directory that contains the functions for each of the processor types. 21.16 + * One of the processor types is the "seed" processor that starts the 21.17 + * cascade of creating all the processors that do the work. 21.18 + */ 21.19 + 21.20 + 21.21 +//=========================================================================== 21.22 +// 21.23 +//=========================================================================== 21.24 +/*This file is for the built-in "services" or "utility" langlet, which starts 21.25 + * automatically when a new process is created. The seed VP initially runs 21.26 + * within this langlet's environment. 21.27 + */ 21.28 + 21.29 +//=========================================================================== 21.30 + 21.31 #include <stdio.h> 21.32 #include <stdlib.h> 21.33 #include <malloc.h> 21.34 @@ -11,26 +35,19 @@ 21.35 #include "Queue_impl/PrivateQueue.h" 21.36 #include "Hash_impl/PrivateHash.h" 21.37 21.38 -#include "../../PR.h" 21.39 #include "PRServ.h" 21.40 +//#include "Measurement/PRServ_Counter_Recording.h" 21.41 21.42 //========================================================================== 21.43 +//=== prototypes for local helper functions 21.44 +//= 21.45 void 21.46 PRServ__init_Helper(); 21.47 + 21.48 //========================================================================== 21.49 21.50 21.51 21.52 -//=========================================================================== 21.53 - 21.54 - 21.55 -/*These are the library functions *called in the application* 21.56 - * 21.57 - */ 21.58 - 21.59 - 21.60 -//=========================================================================== 21.61 - 21.62 int32 21.63 PRServ__giveMinWorkUnitCycles( float32 percentOverhead ) 21.64 { 21.65 @@ -53,12 +70,12 @@ 21.66 * saves jump point, and second jumps back several times to get reliable time 21.67 */ 21.68 void 21.69 -PRServ__begin_primitive() 21.70 - { PRServSemData *semData; 21.71 +PRServ__begin_primitive( SlaveVP *animSlv ) 21.72 + { PRServLangData *langData; 21.73 21.74 - semData = (PRServSemData *)PR_WL__give_sem_data( animSlv, PRServ_MAGIC_NUMBER); 21.75 + langData = (PRServLangData *)PR_WL__give_lang_data( animSlv, PRServ_MAGIC_NUMBER); 21.76 21.77 - saveLowTimeStampCountInto( semData->primitiveStartTime ); 21.78 + saveLowTimeStampCountInto( langData->primitiveStartTime ); 21.79 } 21.80 21.81 /*Just quick and dirty for now -- make reliable later 21.82 @@ -67,251 +84,75 @@ 21.83 * also to throw out any "weird" values due to OS interrupt or TSC rollover 21.84 */ 21.85 int32 21.86 -PRServ__end_primitive_and_give_cycles( SlaveVP animSlv ) 21.87 +PRServ__end_primitive_and_give_cycles( SlaveVP *animSlv ) 21.88 { int32 endTime, startTime; 21.89 - PRServSemData *semData; 21.90 + PRServLangData *langData; 21.91 21.92 //TODO: fix by repeating time-measurement 21.93 saveLowTimeStampCountInto( endTime ); 21.94 - semData = (PRServSemData *)PR_WL__give_sem_data( animSlv, PRServ_MAGIC_NUMBER); 21.95 - startTime = semData->primitiveStartTime; 21.96 - return (endTime - startTime - 2*TSC_LOW_CYCLES); 21.97 + langData = (PRServLangData *)PR_WL__give_lang_data( animSlv, PRServ_MAGIC_NUMBER); 21.98 + startTime = langData->primitiveStartTime; 21.99 + return (endTime - startTime); 21.100 } 21.101 21.102 21.103 - 21.104 -//=========================================================================== 21.105 - 21.106 -SlaveVP * 21.107 -PRServ__create_thread( TopLevelFnPtr fnPtr, void *initData, 21.108 - SlaveVP *creatingThd ) 21.109 - { 21.110 - return PRServ__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID, 21.111 - ANY_CORE, creatingThd ); 21.112 +inline 21.113 +int32 * 21.114 +PRServ__give_self_taskID( SlaveVP *animSlv ) 21.115 + { 21.116 + return PR__give_ID_from_slave( animSlv, PRServ_MAGIC_NUMBER ); 21.117 } 21.118 21.119 -SlaveVP * 21.120 -PRServ__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID, 21.121 - SlaveVP *creatingThd ) 21.122 - { 21.123 - return PRServ__create_thread_w_ID_and_affinity( fnPtr, initData, thdID, 21.124 - ANY_CORE, creatingThd ); 21.125 + 21.126 +/* 21.127 + *This function returns information about the version of PR, the language 21.128 + * the program is being run in, its version, and information on the 21.129 + * hardware. 21.130 + */ 21.131 +char * 21.132 +PRServ___give_environment_string() 21.133 + { char *buffer = PR_WL__malloc(10000); 21.134 + int32 j; 21.135 + 21.136 + j = sizeof(int32); //put total num chars here when done 21.137 + //-------------------------- 21.138 + j += sprintf(buffer+j, "#\n# >> Build information <<\n"); 21.139 + j += sprintf(buffer+j, "# GCC VERSION: %d.%d.%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__); 21.140 + j += sprintf(buffer+j, "# Build Date: %s %s\n", __DATE__, __TIME__); 21.141 + 21.142 + j += sprintf(buffer+j, "#\n# >> Hardware information <<\n"); 21.143 + j += sprintf(buffer+j, "# Hardware Architecture: "); 21.144 + #ifdef __x86_64 21.145 + j += sprintf(buffer+j, "x86_64"); 21.146 + #endif //__x86_64 21.147 + #ifdef __i386 21.148 + j += sprintf(buffer+j, "x86"); 21.149 + #endif //__i386 21.150 + j += sprintf(buffer+j, "\n"); 21.151 + j += sprintf(buffer+j, "# Number of Cores: %d\n", NUM_CORES); 21.152 + //-------------------------- 21.153 + 21.154 + //PR Plugins 21.155 + j += sprintf(buffer+j, "#\n# >> PR Plugins <<\n"); 21.156 + j += sprintf(buffer+j, "# Language : "); 21.157 + j += sprintf(buffer+j, _LANG_NAME_); 21.158 + j += sprintf(buffer+j, "\n"); 21.159 + //Meta info gets set by calls from the language during its init, 21.160 + // and info registered by calls from inside the application 21.161 + j += sprintf(buffer+j, "# Assigner: %s\n", _PRTopEnv->metaInfo->assignerInfo); 21.162 + 21.163 + //-------------------------- 21.164 + //Application 21.165 + j += sprintf(buffer+j, "#\n# >> Application <<\n"); 21.166 + j += sprintf(buffer+j, "# Name: %s\n", _PRTopEnv->metaInfo->appInfo); 21.167 + j += sprintf(buffer+j, "# Data Set:\n%s\n",_PRTopEnv->metaInfo->inputInfo); 21.168 + 21.169 + ((int32 *)buffer)[0] = j - sizeof(int32); //insert the number of chars 21.170 + //-------------------------- 21.171 + return (char *) &(((int32 *)buffer)[1]); //return pointer to first char 21.172 } 21.173 21.174 21.175 -SlaveVP * 21.176 -PRServ__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, 21.177 - int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ) 21.178 - { PRServSemReq reqData; 21.179 - 21.180 - //the semantic request data is on the stack and disappears when this 21.181 - // call returns -- it's guaranteed to remain in the VP's stack for as 21.182 - // long as the VP is suspended. 21.183 - reqData.reqType = create_slave; //know type because in a PR create req 21.184 - reqData.coreToAssignOnto = coreToAssignOnto; 21.185 - 21.186 - PR_WL__send_create_slaveVP_req( &reqData, fnPtr, initData, thdID, 21.187 - creatingThd, PRServ_MAGIC_NUMBER ); 21.188 - return creatingThd->dataRetFromReq; 21.189 - } 21.190 - 21.191 -/*This is always the last thing done in the code animated by a thread VP. 21.192 - * Normally, this would be the last line of the thread's top level function. 21.193 - * But, if the thread exits from any point, it has to do so by calling 21.194 - * this. 21.195 - * 21.196 - *It simply sends a dissipate request, which handles all the state cleanup. 21.197 - */ 21.198 -void 21.199 -PRServ__end_thread( SlaveVP *thdToEnd ) 21.200 - { 21.201 - PR_WL__send_dissipate_req( thdToEnd, PRServ_MAGIC_NUMBER ); 21.202 - } 21.203 - 21.204 - 21.205 - 21.206 -//=========================================================================== 21.207 - 21.208 - 21.209 -//======================= task submit and end ============================== 21.210 -/* 21.211 - */ 21.212 -void 21.213 -PRServ__submit_task( PRServTaskType *taskType, void *args, SlaveVP *animSlv) 21.214 - { PRServSemReq reqData; 21.215 - 21.216 - reqData.reqType = submit_task; 21.217 - 21.218 - reqData.taskType = taskType; 21.219 - reqData.args = args; 21.220 - reqData.callingSlv = animSlv; 21.221 - 21.222 - //Create task is a special form, so have to pass as parameters, the 21.223 - // top-level-fn of task and the data for that fn, plus lang's req, 21.224 - // animating slave, and lang's magic number 21.225 - PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID, animSlv, PRServ_MAGIC_NUMBER ); 21.226 - } 21.227 - 21.228 -void 21.229 -PRServ__submit_task_with_ID( PRServTaskType *taskType, void *args, int32 *taskID, 21.230 - SlaveVP *animSlv) 21.231 - { PRServSemReq reqData; 21.232 - 21.233 - reqData.reqType = submit_task; 21.234 - 21.235 - reqData.taskType = taskType; 21.236 - reqData.args = args; 21.237 - reqData.callingSlv = animSlv; 21.238 - 21.239 - PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID, animSlv, PRServ_MAGIC_NUMBER ); 21.240 - } 21.241 - 21.242 - 21.243 -/*This call is the last to happen in every task. It causes the slave to 21.244 - * suspend and get the next task out of the task-queue. Notice there is no 21.245 - * assigner here.. only one slave, no slave ReadyQ, and so on.. 21.246 - *Can either make the assigner take the next task out of the taskQ, or can 21.247 - * leave all as it is, and make task-end take the next task. 21.248 - *Note: this fits the case in the new PR for no-context tasks, so will use 21.249 - * the built-in taskQ of new PR, and should be local and much faster. 21.250 - * 21.251 - *The task-stub is saved in the animSlv, so the request handler will get it 21.252 - * from there, along with the task-type which has arg types, and so on.. 21.253 - * 21.254 - * NOTE: if want, don't need to send the animating SlaveVP around.. 21.255 - * instead, can make a single slave per core, and coreCtrlr looks up the 21.256 - * slave from having the core number. 21.257 - * 21.258 - *But, to stay compatible with all the other PR languages, leave it in.. 21.259 - */ 21.260 -void 21.261 -PRServ__end_task( SlaveVP *animSlv ) 21.262 - { PRServSemReq reqData; 21.263 - 21.264 - reqData.reqType = end_task; 21.265 - reqData.callingSlv = animSlv; 21.266 - 21.267 - PR_WL__send_end_task_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.268 - } 21.269 - 21.270 - 21.271 -/*Waits for all tasks that are direct children to end, then resumes calling 21.272 - * task or thread 21.273 - */ 21.274 -void 21.275 -PRServ__taskwait(SlaveVP *animSlv) 21.276 - { 21.277 - PRServSemReq reqData; 21.278 - 21.279 - reqData.reqType = taskwait; 21.280 - reqData.callingSlv = animSlv; 21.281 - 21.282 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.283 - } 21.284 - 21.285 - 21.286 - 21.287 -//========================== send and receive ============================ 21.288 -// 21.289 - 21.290 -inline int32 * 21.291 -PRServ__give_self_taskID( SlaveVP *animSlv ) 21.292 - { 21.293 - return PR__give_task_ID( animSlv, PRServ_MAGIC_NUMBER ); 21.294 - } 21.295 - 21.296 -//================================ send =================================== 21.297 - 21.298 -void 21.299 -PRServ__send_of_type_to( void *msg, const int32 type, int32 *receiverID, 21.300 - SlaveVP *senderSlv ) 21.301 - { PRServSemReq reqData; 21.302 - 21.303 - reqData.reqType = send_type_to; 21.304 - 21.305 - reqData.msg = msg; 21.306 - reqData.msgType = type; 21.307 - reqData.receiverID = receiverID; 21.308 - reqData.senderSlv = senderSlv; 21.309 - 21.310 - reqData.nextReqInHashEntry = NULL; 21.311 - 21.312 - PR_WL__send_sem_request( &reqData, senderSlv, PRServ_MAGIC_NUMBER ); 21.313 - 21.314 - //When come back from suspend, no longer own data reachable from msg 21.315 - } 21.316 - 21.317 -void 21.318 -PRServ__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ) 21.319 - { PRServSemReq reqData; 21.320 - 21.321 - reqData.reqType = send_from_to; 21.322 - 21.323 - reqData.msg = msg; 21.324 - reqData.senderID = senderID; 21.325 - reqData.receiverID = receiverID; 21.326 - reqData.senderSlv = senderSlv; 21.327 - 21.328 - reqData.nextReqInHashEntry = NULL; 21.329 - 21.330 - PR_WL__send_sem_request( &reqData, senderSlv, PRServ_MAGIC_NUMBER ); 21.331 - } 21.332 - 21.333 - 21.334 -//================================ receive ================================ 21.335 - 21.336 -/*The "type" version of send and receive creates a many-to-one relationship. 21.337 - * The sender is anonymous, and many sends can stack up, waiting to be 21.338 - * received. The same receiver can also have send from-to's 21.339 - * waiting for it, and those will be kept separate from the "type" 21.340 - * messages. 21.341 - */ 21.342 -void * 21.343 -PRServ__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ) 21.344 - { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] ); 21.345 - PRServSemReq reqData; 21.346 - 21.347 - reqData.reqType = receive_type_to; 21.348 - 21.349 - reqData.msgType = type; 21.350 - reqData.receiverID = receiverID; 21.351 - reqData.receiverSlv = receiverSlv; 21.352 - 21.353 - reqData.nextReqInHashEntry = NULL; 21.354 - 21.355 - PR_WL__send_sem_request( &reqData, receiverSlv, PRServ_MAGIC_NUMBER ); 21.356 - 21.357 - return receiverSlv->dataRetFromReq; 21.358 - } 21.359 - 21.360 - 21.361 - 21.362 -/*Call this at the point a receiving task wants in-coming data. 21.363 - * Use this from-to form when know senderID -- it makes a direct channel 21.364 - * between sender and receiver. 21.365 - */ 21.366 -void * 21.367 -PRServ__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ) 21.368 - { 21.369 - PRServSemReq reqData; 21.370 - 21.371 - reqData.reqType = receive_from_to; 21.372 - 21.373 - reqData.senderID = senderID; 21.374 - reqData.receiverID = receiverID; 21.375 - reqData.receiverSlv = receiverSlv; 21.376 - 21.377 - reqData.nextReqInHashEntry = NULL; 21.378 - DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); 21.379 - 21.380 - PR_WL__send_sem_request( &reqData, receiverSlv, PRServ_MAGIC_NUMBER ); 21.381 - 21.382 - return receiverSlv->dataRetFromReq; 21.383 - } 21.384 - 21.385 - 21.386 - 21.387 - 21.388 //========================================================================== 21.389 // 21.390 /*A function singleton is a function whose body executes exactly once, on a 21.391 @@ -329,22 +170,24 @@ 21.392 void asm_write_ret_from_singleton(PRServSingleton *singletonPtrAddr); 21.393 21.394 /*Fn singleton uses ID as index into array of singleton structs held in the 21.395 - * semantic environment. 21.396 + * language environment. 21.397 */ 21.398 void 21.399 PRServ__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ) 21.400 { 21.401 - PRServSemReq reqData; 21.402 + PRServLangReq reqData; 21.403 21.404 // 21.405 - reqData.reqType = singleton_fn_start; 21.406 + reqData.reqType = prserv_singleton_fn_start; 21.407 reqData.singletonID = singletonID; 21.408 21.409 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.410 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleStartFnSingleton, 21.411 + animSlv, PRServ_MAGIC_NUMBER ); 21.412 if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton 21.413 { 21.414 - PRServSemEnv *semEnv = PR_WL__give_sem_env_for( animSlv, PRServ_MAGIC_NUMBER ); 21.415 - asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); 21.416 + PRServLangEnv *langEnv = 21.417 + PR_int__give_lang_env_for_slave( animSlv, PRServ_MAGIC_NUMBER ); 21.418 + asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID])); 21.419 } 21.420 } 21.421 21.422 @@ -355,15 +198,16 @@ 21.423 void 21.424 PRServ__start_data_singleton( PRServSingleton **singletonAddr, SlaveVP *animSlv ) 21.425 { 21.426 - PRServSemReq reqData; 21.427 + PRServLangReq reqData; 21.428 21.429 if( *singletonAddr && (*singletonAddr)->hasFinished ) 21.430 goto JmpToEndSingleton; 21.431 21.432 - reqData.reqType = singleton_data_start; 21.433 + reqData.reqType = prserv_singleton_data_start; 21.434 reqData.singletonPtrAddr = singletonAddr; 21.435 21.436 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.437 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleStartDataSingleton, 21.438 + animSlv, PRServ_MAGIC_NUMBER ); 21.439 if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr 21.440 { //Assembly code changes the return addr on the stack to the one 21.441 // saved into the singleton by the end-singleton-fn 21.442 @@ -384,17 +228,20 @@ 21.443 void 21.444 PRServ__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ) 21.445 { 21.446 - PRServSemReq reqData; 21.447 + PRServLangReq reqData; 21.448 21.449 //don't need this addr until after at least one singleton has reached 21.450 // this function 21.451 - PRServSemEnv *semEnv = PR_WL__give_sem_env_for( animSlv, PRServ_MAGIC_NUMBER ); 21.452 - asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); 21.453 + PRServLangEnv * 21.454 + langEnv = PR_int__give_lang_env_for_slave( animSlv, PRServ_MAGIC_NUMBER ); 21.455 + 21.456 + asm_write_ret_from_singleton( &(langEnv->fnSingletons[ singletonID]) ); 21.457 21.458 - reqData.reqType = singleton_fn_end; 21.459 + reqData.reqType = prserv_singleton_fn_end; 21.460 reqData.singletonID = singletonID; 21.461 21.462 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.463 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleEndFnSingleton, 21.464 + animSlv, PRServ_MAGIC_NUMBER ); 21.465 21.466 EndSingletonInstrAddr: 21.467 return; 21.468 @@ -403,7 +250,7 @@ 21.469 void 21.470 PRServ__end_data_singleton( PRServSingleton **singletonPtrAddr, SlaveVP *animSlv ) 21.471 { 21.472 - PRServSemReq reqData; 21.473 + PRServLangReq reqData; 21.474 21.475 //don't need this addr until after singleton struct has reached 21.476 // this function for first time 21.477 @@ -413,10 +260,11 @@ 21.478 // function in different places for different data-singletons. 21.479 asm_save_ret_to_singleton(*singletonPtrAddr); 21.480 21.481 - reqData.reqType = singleton_data_end; 21.482 + reqData.reqType = prserv_singleton_data_end; 21.483 reqData.singletonPtrAddr = singletonPtrAddr; 21.484 21.485 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.486 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleEndDataSingleton, 21.487 + animSlv, PRServ_MAGIC_NUMBER ); 21.488 } 21.489 21.490 /*This executes the function in the masterVP, so it executes in isolation 21.491 @@ -433,14 +281,15 @@ 21.492 PRServ__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 21.493 void *data, SlaveVP *animSlv ) 21.494 { 21.495 - PRServSemReq reqData; 21.496 + PRServLangReq reqData; 21.497 21.498 // 21.499 - reqData.reqType = atomic; 21.500 + reqData.reqType = prserv_atomic; 21.501 reqData.fnToExecInMaster = ptrToFnToExecInMaster; 21.502 reqData.dataForFn = data; 21.503 21.504 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.505 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleAtomic, 21.506 + animSlv, PRServ_MAGIC_NUMBER ); 21.507 } 21.508 21.509 21.510 @@ -460,14 +309,15 @@ 21.511 void 21.512 PRServ__start_transaction( int32 transactionID, SlaveVP *animSlv ) 21.513 { 21.514 - PRServSemReq reqData; 21.515 + PRServLangReq reqData; 21.516 21.517 // 21.518 reqData.callingSlv = animSlv; 21.519 - reqData.reqType = trans_start; 21.520 + reqData.reqType = prserv_trans_start; 21.521 reqData.transID = transactionID; 21.522 21.523 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.524 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleTransStart, 21.525 + animSlv, PRServ_MAGIC_NUMBER ); 21.526 } 21.527 21.528 /*This suspends to the master, then uses transactionID as index into an 21.529 @@ -482,36 +332,16 @@ 21.530 void 21.531 PRServ__end_transaction( int32 transactionID, SlaveVP *animSlv ) 21.532 { 21.533 - PRServSemReq reqData; 21.534 + PRServLangReq reqData; 21.535 21.536 // 21.537 reqData.callingSlv = animSlv; 21.538 - reqData.reqType = trans_end; 21.539 + reqData.reqType = prserv_trans_end; 21.540 reqData.transID = transactionID; 21.541 21.542 - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); 21.543 + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleTransEnd, 21.544 + animSlv, PRServ_MAGIC_NUMBER ); 21.545 } 21.546 21.547 //======================== Internal ================================== 21.548 -/* 21.549 - */ 21.550 21.551 -SlaveVP * 21.552 -PRServ__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, 21.553 - SlaveVP *creatingSlv, int32 coreToAssignOnto ) 21.554 - { PRServSemReq reqData; 21.555 - 21.556 - //the semantic request data is on the stack and disappears when this 21.557 - // call returns -- it's guaranteed to remain in the VP's stack for as 21.558 - // long as the VP is suspended. 21.559 - reqData.reqType = create_slave_w_aff; //not used, May 2012 21.560 - reqData.coreToAssignOnto = coreToAssignOnto; 21.561 - reqData.fnPtr = fnPtr; 21.562 - reqData.initData = initData; 21.563 - reqData.callingSlv = creatingSlv; 21.564 - 21.565 - PR_WL__send_create_slaveVP_req( &reqData, creatingSlv, PRServ_MAGIC_NUMBER ); 21.566 - 21.567 - return creatingSlv->dataRetFromReq; 21.568 - } 21.569 -
22.1 --- a/Services_Offered_by_PR/Services_Language/PRServ.h Tue Feb 05 20:23:27 2013 -0800 22.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ.h Sat Mar 02 09:43:45 2013 -0800 22.3 @@ -1,93 +1,105 @@ 22.4 /* 22.5 - * Copyright 2009 OpenSourceStewardshipFoundation.org 22.6 + * Copyright 2009 OpenSourceResearchInstitute.org 22.7 * Licensed under GNU General Public License version 2 22.8 * 22.9 * Author: seanhalle@yahoo.com 22.10 * 22.11 */ 22.12 22.13 +#ifndef _PRServ_H 22.14 +#define _PRServ_H 22.15 22.16 #include "Queue_impl/PrivateQueue.h" 22.17 #include "Hash_impl/PrivateHash.h" 22.18 -//#include "../Measurement_and_Stats/" 22.19 - 22.20 -#ifndef _PRServ_H 22.21 -#define _PRServ_H 22.22 +#include "PR_impl/PR.h" 22.23 22.24 22.25 //=========================================================================== 22.26 - //uniquely identifies PRServ -- should be a jenkins char-hash of "PRServ" onto int32 22.27 -#define PRServ_MAGIC_NUMBER 0000000002 22.28 + //uniquely identifies PRServ -- should be a jenkins char-hash of "PRServ" to int32 22.29 +#define PRServ_MAGIC_NUMBER 0000000001 22.30 22.31 -#define NUM_STRUCS_IN_SEM_ENV 1000 22.32 +#define NUM_STRUCS_IN_LANG_ENV 1000 22.33 22.34 + //This is hardware dependent -- it's the number of cycles of scheduling 22.35 + // overhead -- if a work unit is fewer than this, it is better being 22.36 + // combined sequentially with other work 22.37 + //This value depends on both PR overhead and PRServ's plugin. At some point 22.38 + // it will be derived by perf-counter measurements during init of PRServ 22.39 +#define MIN_WORK_UNIT_CYCLES 20000 22.40 22.41 //=========================================================================== 22.42 /*This header defines everything specific to the PRServ semantic plug-in 22.43 */ 22.44 -typedef struct _PRServSemReq PRServSemReq; 22.45 -//typedef struct _PRServTaskStub PRServTaskStub; 22.46 -//typedef void (*PRServTaskFnPtr ) ( void *, SlaveVP *); 22.47 -//typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master 22.48 +typedef struct _PRServLangReq PRServLangReq; 22.49 +typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master 22.50 //=========================================================================== 22.51 22.52 - 22.53 //=========================================================================== 22.54 22.55 -/*This is placed into semData, used for dependencies and wait construct*/ 22.56 -struct _PRServTaskStub 22.57 +/*Semantic layer-specific data sent inside a request from lib called in app 22.58 + * to request handler called in AnimationMaster 22.59 + */ 22.60 + 22.61 +typedef struct 22.62 { 22.63 - //====== The first fields must match PRLangMetaTask fields ====== 22.64 - int32 langMagicNumber; //magic num must be 1st field of langMetaTask 22.65 - PRMetaTask *protoMetaTask; //back-link must always be 2nd field 22.66 - //====== end PRLangMetaTask fields ========= 22.67 - 22.68 + SlaveVP *VPCurrentlyExecuting; 22.69 + PrivQueueStruc *waitingVPQ; 22.70 + } 22.71 +PRServTrans; 22.72 + 22.73 +/*WARNING: assembly hard-codes position of endInstrAddr as first field 22.74 + */ 22.75 +typedef struct 22.76 + { 22.77 + void *endInstrAddr; 22.78 + int32 hasBeenStarted; 22.79 + int32 hasFinished; 22.80 + PrivQueueStruc *waitQ; 22.81 + } 22.82 +PRServSingleton; 22.83 + 22.84 +/*Note: may not need this anymore -- switched to embedding pointer to handler*/ 22.85 +enum PRServLangReqType 22.86 + { 22.87 + prserv_malloc_req = 1, 22.88 + prserv_free_req, 22.89 + prserv_singleton_fn_start, 22.90 + prserv_singleton_fn_end, 22.91 + prserv_singleton_data_start, 22.92 + prserv_singleton_data_end, 22.93 + prserv_atomic, 22.94 + prserv_trans_start, 22.95 + prserv_trans_end 22.96 }; 22.97 22.98 +struct _PRServLangReq 22.99 + { enum PRServLangReqType reqType; 22.100 + SlaveVP *callingSlv; 22.101 22.102 -struct _PRServSemReq 22.103 - { enum PRServReqType reqType; 22.104 - SlaveVP *callingSlv; 22.105 - void *args; 22.106 -// PRServTaskStub *taskStub; //not needed -- get via PR accessor from slv 22.107 - 22.108 - SlaveVP *senderSlv; 22.109 - SlaveVP *receiverSlv; 22.110 - int32 *senderID; 22.111 - int32 *receiverID; 22.112 - int32 msgType; 22.113 - void *msg; 22.114 - PRServSemReq *nextReqInHashEntry; 22.115 -//In PRReq: int32 *taskID; 22.116 - 22.117 - TopLevelFnPtr fnPtr; 22.118 - void *initData; 22.119 - int32 coreToAssignOnto; 22.120 - 22.121 -//These, below, should move to util language.. 22.122 int32 sizeToMalloc; 22.123 void *ptrToFree; 22.124 22.125 int32 singletonID; 22.126 + PRServSingleton **singletonPtrAddr; 22.127 22.128 + PtrToAtomicFn fnToExecInMaster; 22.129 void *dataForFn; 22.130 22.131 int32 transID; 22.132 } 22.133 -/* PRServSemReq */; 22.134 +/* PRServLangReq */; 22.135 22.136 22.137 typedef struct 22.138 - { PRLangEnv *protoLangEnv; 22.139 + { 22.140 PrivQueueStruc *slavesReadyToResumeQ; //Shared (slaves not pinned) 22.141 - PrivQueueStruc *freeTaskSlvRecycleQ; //Shared 22.142 - PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) 22.143 - HashTable *argPtrHashTbl; 22.144 - HashTable *commHashTbl; 22.145 - int32 nextCoreToGetNewSlv; 22.146 + PrivQueueStruc *taskReadyQ; //will never be used in seed langlet 22.147 + 22.148 int32 primitiveStartTime; 22.149 22.150 //fix limit on num with dynArray 22.151 + PRServSingleton fnSingletons[NUM_STRUCS_IN_LANG_ENV]; 22.152 + PRServTrans transactionStrucs[NUM_STRUCS_IN_LANG_ENV]; 22.153 22.154 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 22.155 ListOfArrays* unitList; 22.156 @@ -104,33 +116,24 @@ 22.157 ListOfArrays* counterList[NUM_CORES]; 22.158 #endif 22.159 } 22.160 -PRServSemEnv; 22.161 +PRServLangEnv; 22.162 22.163 22.164 -typedef struct _TransListElem TransListElem; 22.165 -struct _TransListElem 22.166 +typedef struct _PRServTransListElem PRServTransListElem; 22.167 +struct _PRServTransListElem 22.168 { 22.169 int32 transID; 22.170 - TransListElem *nextTrans; 22.171 + PRServTransListElem *nextTrans; 22.172 }; 22.173 //TransListElem 22.174 22.175 -/* PR now handles what this used to be used for 22.176 -enum PRServSlvType 22.177 - { FreeTaskSlv = 1, 22.178 - SlotTaskSlv, 22.179 - ThreadSlv 22.180 - }; 22.181 -*/ 22.182 - 22.183 typedef struct 22.184 { 22.185 int32 highestTransEntered; 22.186 - TransListElem *lastTransEntered; 22.187 + PRServTransListElem *lastTransEntered; 22.188 int32 primitiveStartTime; 22.189 -// PRServTaskStub *taskStub; //get from slave via PR accessor 22.190 } 22.191 -PRServSemData; 22.192 +PRServLangData; 22.193 22.194 //=========================================================================== 22.195 22.196 @@ -149,36 +152,66 @@ 22.197 int32 22.198 PRServ__give_number_of_cores_to_schedule_onto(); 22.199 22.200 +char * 22.201 +PRServ___give_environment_string(); 22.202 + 22.203 //======================= 22.204 22.205 -void 22.206 +PRServLangEnv * 22.207 PRServ__start( SlaveVP *seedSlv ); 22.208 22.209 void 22.210 -PRServ__cleanup_after_shutdown(); 22.211 +PRServ__end(); 22.212 22.213 -//======================= 22.214 void 22.215 -PRServ__resume_slaveVP( SlaveVP *seedSlv, PRServLangEnv *servicesLangEnv ); 22.216 - 22.217 +PRServ__end_seedVP( SlaveVP *seedSlv ); 22.218 //======================= 22.219 22.220 -#define PRServ__malloc( numBytes, callingSlave ) PR_App__malloc( numBytes, callingSlave) 22.221 - 22.222 -#define PRServ__free(ptrToFree, callingSlave ) PR_App__free( ptrToFree, callingSlave ) 22.223 - 22.224 - 22.225 -//======================= 22.226 +inline int32 * 22.227 +PRServ__create_taskID_of_size( int32 numInts, SlaveVP *animSlv ); 22.228 22.229 //========================= 22.230 +void 22.231 +PRServ__taskwait(SlaveVP *animSlv); 22.232 + 22.233 +inline int32 * 22.234 +PRServ__give_self_taskID( SlaveVP *animSlv ); 22.235 + 22.236 +//======================= Concurrency Stuff ====================== 22.237 +void 22.238 +PRServ__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ); 22.239 + 22.240 +void 22.241 +PRServ__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ); 22.242 + 22.243 +void 22.244 +PRServ__start_data_singleton( PRServSingleton **singeltonAddr, SlaveVP *animSlv ); 22.245 + 22.246 +void 22.247 +PRServ__end_data_singleton( PRServSingleton **singletonAddr, SlaveVP *animSlv ); 22.248 + 22.249 +void 22.250 +PRServ__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 22.251 + void *data, SlaveVP *animSlv ); 22.252 + 22.253 +void 22.254 +PRServ__start_transaction( int32 transactionID, SlaveVP *animSlv ); 22.255 + 22.256 +void 22.257 +PRServ__end_transaction( int32 transactionID, SlaveVP *animSlv ); 22.258 22.259 22.260 //========================= Internal use only ============================= 22.261 22.262 -SlaveVP * 22.263 -PRServ__assign_work_to_slot( void *_semEnv, AnimSlot *slot ); 22.264 +bool32 22.265 +PRServ__assign_work_to_slot( void *_langEnv, AnimSlot *slot ); 22.266 + 22.267 +//===================== ===================== 22.268 + 22.269 +#include "PRServ_Request_Handlers.h" 22.270 22.271 //===================== Measurement of Lang Overheads ===================== 22.272 +#include "Measurement/PRServ_Measurement.h" 22.273 22.274 //=========================================================================== 22.275 #endif /* _PRServ_H */
23.1 --- a/Services_Offered_by_PR/Services_Language/PRServ_PluginFns.c Tue Feb 05 20:23:27 2013 -0800 23.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ_PluginFns.c Sat Mar 02 09:43:45 2013 -0800 23.3 @@ -12,17 +12,6 @@ 23.4 #include "PRServ_Request_Handlers.h" 23.5 23.6 //=========================== Local Fn Prototypes =========================== 23.7 -void 23.8 -resume_slaveVP( SlaveVP *slave, PRServSemEnv *semEnv ); 23.9 - 23.10 -inline void 23.11 -handleSemReq( PRReqst *req, SlaveVP *requestingSlv, PRServSemEnv *semEnv ); 23.12 - 23.13 -inline void 23.14 -handleDissipate( SlaveVP *requestingSlv, PRServSemEnv *semEnv ); 23.15 - 23.16 -inline void 23.17 -handleCreate( PRReqst *req, SlaveVP *requestingSlv, PRServSemEnv *semEnv ); 23.18 23.19 //============================== Assigner ================================== 23.20 // 23.21 @@ -51,161 +40,91 @@ 23.22 * to suspend both kinds, but also to keep explicit slave stacks clean from 23.23 * the junk tasks are allowed to leave behind. 23.24 */ 23.25 -SlaveVP * 23.26 -PRServ__assign_work_to_slot( void *_semEnv, AnimSlot *slot ) 23.27 +bool32 23.28 +PRServ__assign_work_to_slot( void *_langEnv, AnimSlot *slot ) 23.29 { SlaveVP *returnSlv; 23.30 - PRServSemEnv *semEnv; 23.31 + PRServLangEnv *langEnv; 23.32 int32 coreNum, slotNum; 23.33 - PRMetaTask *returnMetaTask = NULL, *newTaskStub; 23.34 23.35 coreNum = slot->coreSlotIsOn; 23.36 slotNum = slot->slotIdx; 23.37 23.38 - semEnv = (PRServSemEnv *)_semEnv; 23.39 + langEnv = (PRServLangEnv *)_langEnv; 23.40 23.41 //Check for suspended slaves that are ready to resume 23.42 - returnSlv = readPrivQ( semEnv->slavesReadyToResumeQ ); 23.43 + returnSlv = readPrivQ( langEnv->slavesReadyToResumeQ ); 23.44 if( returnSlv != NULL ) //Yes, have a slave, so return it. 23.45 { returnSlv->coreAnimatedBy = coreNum; 23.46 - returnMetaTask = returnSlv->metaTasks; 23.47 - goto ReturnTheMetaTask; 23.48 + 23.49 + //PR calls this Fn, which in turn uses PR's primitive to assign 23.50 + // a slave to a slot. 23.51 + //Note: this represents a security risk, if langlet has a bug and gives 23.52 + // the wrong slot.. assuming will have a tool in future that analyzes 23.53 + // plugin code before certifying it.. 23.54 + PR_int__put_slave_into_slot( returnSlv, slot ); 23.55 + goto Success; 23.56 } 23.57 23.58 - newTaskStub = readPrivQ( semEnv->taskReadyQ ); 23.59 - if( newTaskStub != NULL ) 23.60 - { returnMetaTask = newTaskStub->protoMetaTask; 23.61 - goto ReturnTheMetaTask; 23.62 - } 23.63 + 23.64 + //If here, didn't assign any work 23.65 + Fail: 23.66 + return FALSE; 23.67 + //fixme; //figure out what to do -- go through holistic code still? 23.68 23.69 -ReturnTheMetaTask: //doing gotos to here should help with holistic.. 23.70 + Success: //doing gotos to here should help with holistic.. 23.71 23.72 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 23.73 //This no longer works -- should be moved into PR in master 23.74 //This assumes the task has already been assigned to a slave, which happens 23.75 // inside Master.. 23.76 if( returnMetaTask == NULL ) 23.77 - { returnSlv = semEnv->process->idleSlv[coreNum][slotNum]; 23.78 + { returnSlv = langEnv->process->idleSlv[coreNum][slotNum]; 23.79 23.80 //things that would normally happen in resume(), but these VPs 23.81 // never go there 23.82 returnSlv->numTimesAssignedToASlot++; 23.83 Unit newU; 23.84 - newU.vp = returnSlv->slaveID; 23.85 + newU.vp = returnSlv->slaveNum; 23.86 newU.task = returnSlv->numTimesAssignedToASlot; 23.87 - addToListOfArrays(Unit,newU,semEnv->unitList); 23.88 + addToListOfArrays(Unit,newU,langEnv->unitList); 23.89 23.90 if (returnSlv->numTimesAssignedToASlot > 1) 23.91 { Dependency newD; 23.92 - newD.from_vp = returnSlv->slaveID; 23.93 + newD.from_vp = returnSlv->slaveNum; 23.94 newD.from_task = returnSlv->numTimesAssignedToASlot - 1; 23.95 - newD.to_vp = returnSlv->slaveID; 23.96 + newD.to_vp = returnSlv->slaveNum; 23.97 newD.to_task = returnSlv->numTimesAssignedToASlot; 23.98 - addToListOfArrays(Dependency, newD, semEnv->ctlDependenciesList); 23.99 + addToListOfArrays(Dependency, newD, langEnv->ctlDependenciesList); 23.100 } 23.101 returnMetaTask = returnSlv->metaTasks; 23.102 } 23.103 else //returnSlv != NULL 23.104 { //assignSlv->numTimesAssigned++; 23.105 Unit prev_in_slot = 23.106 - semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; 23.107 + langEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; 23.108 if(prev_in_slot.vp != 0) 23.109 { Dependency newD; 23.110 newD.from_vp = prev_in_slot.vp; 23.111 newD.from_task = prev_in_slot.task; 23.112 - newD.to_vp = returnSlv->slaveID; 23.113 + newD.to_vp = returnSlv->slaveNum; 23.114 newD.to_task = returnSlv->numTimesAssignedToASlot; 23.115 - addToListOfArrays(Dependency,newD,semEnv->hwArcs); 23.116 + addToListOfArrays(Dependency,newD,langEnv->hwArcs); 23.117 } 23.118 - prev_in_slot.vp = returnSlv->slaveID; 23.119 + prev_in_slot.vp = returnSlv->slaveNum; 23.120 prev_in_slot.task = returnSlv->numTimesAssignedToASlot; 23.121 - semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = 23.122 + langEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = 23.123 prev_in_slot; 23.124 } 23.125 #endif 23.126 - return( returnMetaTask ); 23.127 +/* PR handles work available in lang env and in process.. 23.128 + if( isEmptyPrivQ(langEnv->slavesReadyToResumeQ) && 23.129 + isEmptyPrivQ(langEnv->taskReadyQ) ) 23.130 + PR_int__clear_work_in_lang_env(langEnv); 23.131 + */ 23.132 + 23.133 + return TRUE; 23.134 } 23.135 23.136 23.137 -//=========================== Request Handler ============================ 23.138 -// 23.139 -/* 23.140 - * (Not inline because invoked indirectly via a pointer) 23.141 - */ 23.142 - 23.143 -void 23.144 -handleSemReq( PRReqst *req, SlaveVP *reqSlv, PRServSemEnv *semEnv ) 23.145 - { PRServSemReq *semReq; 23.146 - 23.147 - semReq = PR_PI__take_sem_reqst_from(req); 23.148 - if( semReq == NULL ) return; 23.149 - switch( semReq->reqType ) //sem handlers are all in other file 23.150 - { 23.151 - case send_type_to: handleSendTypeTo( semReq, semEnv); 23.152 - break; 23.153 - case send_from_to: handleSendFromTo( semReq, semEnv); 23.154 - break; 23.155 - case receive_type_to: handleReceiveTypeTo(semReq, semEnv); 23.156 - break; 23.157 - case receive_from_to: handleReceiveFromTo(semReq, semEnv); 23.158 - break; 23.159 - case taskwait: handleTaskwait( semReq, reqSlv, semEnv); 23.160 - break; 23.161 - 23.162 - //==================================================================== 23.163 - case malloc_req: handleMalloc( semReq, reqSlv, semEnv); 23.164 - break; 23.165 - case free_req: handleFree( semReq, reqSlv, semEnv); 23.166 - break; 23.167 - case singleton_fn_start: handleStartFnSingleton(semReq, reqSlv, semEnv); 23.168 - break; 23.169 - case singleton_fn_end: handleEndFnSingleton( semReq, reqSlv, semEnv); 23.170 - break; 23.171 - case singleton_data_start:handleStartDataSingleton(semReq,reqSlv,semEnv); 23.172 - break; 23.173 - case singleton_data_end: handleEndDataSingleton(semReq, reqSlv, semEnv); 23.174 - break; 23.175 - case atomic: handleAtomic( semReq, reqSlv, semEnv); 23.176 - break; 23.177 - case trans_start: handleTransStart( semReq, reqSlv, semEnv); 23.178 - break; 23.179 - case trans_end: handleTransEnd( semReq, reqSlv, semEnv); 23.180 - break; 23.181 - } 23.182 - } 23.183 - 23.184 - 23.185 - 23.186 23.187 //=========================== Helper ============================== 23.188 -void 23.189 -resume_slaveVP( SlaveVP *slave, PRServSemEnv *semEnv ) 23.190 - { 23.191 - //both suspended tasks and suspended explicit slaves resumed with this 23.192 - writePrivQ( slave, semEnv->slavesReadyToResumeQ ); 23.193 - if( semEnv->protoSemEnv->hasWork != TRUE ) 23.194 - semEnv->protoSemEnv->hasWork = TRUE; 23.195 - 23.196 - #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 23.197 -/* 23.198 - int lastRecordIdx = slave->counter_history_array_info->numInArray -1; 23.199 - CounterRecord* lastRecord = slave->counter_history[lastRecordIdx]; 23.200 - saveLowTimeStampCountInto(lastRecord->unblocked_timestamp); 23.201 -*/ 23.202 - #endif 23.203 - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 23.204 - slave->numTimesAssignedToASlot++; //Somewhere here! 23.205 - Unit newU; 23.206 - newU.vp = slave->slaveID; 23.207 - newU.task = slave->numTimesAssignedToASlot; 23.208 - addToListOfArrays(Unit,newU,semEnv->unitList); 23.209 - 23.210 - if (slave->numTimesAssignedToASlot > 1) 23.211 - { Dependency newD; 23.212 - newD.from_vp = slave->slaveID; 23.213 - newD.from_task = slave->numTimesAssignedToASlot - 1; 23.214 - newD.to_vp = slave->slaveID; 23.215 - newD.to_task = slave->numTimesAssignedToASlot; 23.216 - addToListOfArrays(Dependency, newD ,semEnv->ctlDependenciesList); 23.217 - } 23.218 - #endif 23.219 - }
24.1 --- a/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.c Tue Feb 05 20:23:27 2013 -0800 24.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.c Sat Mar 02 09:43:45 2013 -0800 24.3 @@ -17,1048 +17,30 @@ 24.4 24.5 24.6 //=========================== Local Fn Prototypes =========================== 24.7 -void 24.8 -resume_slaveVP( SlaveVP *slave, PRServSemEnv *semEnv ); 24.9 - 24.10 - 24.11 - 24.12 -//========================================================================== 24.13 -// Helpers 24.14 -// 24.15 - 24.16 -/*Only clone the elements of req used in these reqst handlers 24.17 - */ 24.18 -PRServSemReq * 24.19 -cloneReq( PRServSemReq *semReq ) 24.20 - { PRServSemReq *clonedReq; 24.21 - 24.22 - clonedReq = PR_PI__malloc( sizeof(PRServSemReq) ); 24.23 - clonedReq->reqType = semReq->reqType; 24.24 - clonedReq->senderSlv = semReq->senderSlv; 24.25 - clonedReq->receiverSlv= semReq->receiverSlv; 24.26 - clonedReq->msg = semReq->msg; 24.27 - clonedReq->nextReqInHashEntry = NULL; 24.28 - 24.29 - return clonedReq; 24.30 - } 24.31 - 24.32 - 24.33 - 24.34 -HashEntry * 24.35 -giveEntryElseInsertReqst32( int32 *key, PRServSemReq *semReq, 24.36 - HashTable *commHashTbl ) 24.37 - { HashEntry *entry; 24.38 - PRServSemReq *waitingReq; 24.39 - 24.40 - entry = getEntryFromTable32( key, commHashTbl ); 24.41 - if( entry == NULL ) 24.42 - { //no waiting sends or receives, so add this request and exit 24.43 - // note: have to clone the request because it's on stack of sender 24.44 - addValueIntoTable32( key, cloneReq( semReq ), commHashTbl ); 24.45 - return NULL; 24.46 - } 24.47 - waitingReq = (PRServSemReq *)entry->content; 24.48 - if( waitingReq == NULL ) //might happen when last waiting gets paired 24.49 - { //no waiting sends or receives, so add this request and exit 24.50 - entry->content = semReq; 24.51 - return NULL; 24.52 - } 24.53 - return entry; 24.54 - } 24.55 - 24.56 - 24.57 -inline PRServPointerEntry * 24.58 -create_pointer_entry( ) 24.59 - { PRServPointerEntry *newEntry; 24.60 - 24.61 - newEntry = PR_PI__malloc( sizeof(PRServPointerEntry) ); 24.62 - newEntry->hasEnabledNonFinishedWriter = FALSE; 24.63 - newEntry->numEnabledNonDoneReaders = 0; 24.64 - newEntry->waitersQ = makePrivQ(); 24.65 - 24.66 - return newEntry; 24.67 - } 24.68 - 24.69 -/*malloc's space and initializes fields -- and COPIES the arg values 24.70 - * to new space 24.71 - */ 24.72 -inline PRServTaskStub * 24.73 -create_task_stub( PRServTaskType *taskType, void **args ) 24.74 - { void **newArgs; 24.75 - PRServTaskStub* newStub = PR_int__malloc( sizeof(PRMetaTask) + taskType->sizeOfArgs ); 24.76 - newStub->numBlockingProp = taskType->numCtldArgs; 24.77 - newStub->taskType = taskType; 24.78 - newStub->ptrEntries = 24.79 - PR_int__malloc( taskType->numCtldArgs * sizeof(PRServPointerEntry *) ); 24.80 - newArgs = (void **)( (uint8 *)newStub + sizeof(PRMetaTask) ); 24.81 - newStub->args = newArgs; 24.82 - newStub->numLiveChildTasks = 0; 24.83 - newStub->numLiveChildThreads = 0; 24.84 - newStub->isEnded = FALSE; 24.85 - 24.86 - //Copy the arg-pointers.. can be more arguments than just the ones 24.87 - // that StarSs uses to control ordering of task execution. 24.88 - memcpy( newArgs, args, taskType->sizeOfArgs ); 24.89 - 24.90 - return newStub; 24.91 - } 24.92 - 24.93 -inline PRServTaskStubCarrier * 24.94 -create_task_carrier( PRServTaskStub *taskStub, int32 argNum, int32 rdOrWrite ) 24.95 - { PRServTaskStubCarrier *newCarrier; 24.96 - 24.97 - newCarrier = PR_PI__malloc( sizeof(PRServTaskStubCarrier) ); 24.98 - newCarrier->taskStub = taskStub; 24.99 - newCarrier->argNum = argNum; 24.100 - newCarrier->isReader = rdOrWrite == READER; 24.101 - } 24.102 - 24.103 - 24.104 - 24.105 -//=========================== ============================== 24.106 - 24.107 -/*Application invokes this via wrapper library, when it explicitly creates a 24.108 - * thread with the "PRServ__create_thread()" command. 24.109 - * 24.110 - *Slave creation is a special form, so PR does handling before calling this. 24.111 - * It does creation of the new slave, and hands it to this handler. 24.112 - *This handler is registered with PR during PRServ__start(). 24.113 - * 24.114 - *So, here, create a task Stub that contains a marker stating this is a thread. 24.115 - * Then, attach the task stub to the slave's meta Task via a PR command. 24.116 - * 24.117 - *When slave dissipates, PR will call the registered recycler for the task stub. 24.118 - */ 24.119 -inline void 24.120 -handleCreateThd( PRReqst *req, SlaveVP *requestingSlv, SlaveVP *newSlv, PRServSemEnv *semEnv ) 24.121 - { PRServSemReq *semReq; 24.122 - PRServTaskStub *taskStub, *parentTaskStub; 24.123 - 24.124 - semReq = PR_PI__take_sem_reqst_from( req ); 24.125 - 24.126 - parentTaskStub = PR_PI__give_lang_meta_task( requestingSlv ); 24.127 - parentTaskStub->numLiveChildThreads += 1; 24.128 - 24.129 - taskStub = create_thread_task_stub(); //only used for wait info 24.130 - taskStub->parentTaskStub = parentTaskStub; 24.131 - 24.132 - //note, semantic data will be initialized by separate, registered 24.133 - // initializer, at the point it is accessed the first time. 24.134 - 24.135 - //================= Assign the new thread to a core =================== 24.136 - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 24.137 - newSlv->coreAnimatedBy = 0; 24.138 - 24.139 - #else 24.140 - //Assigning slaves to cores is part of SSR code.. 24.141 - int32 coreToAssignOnto = semReq->coreToAssignOnto; 24.142 - if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES ) 24.143 - { //out-of-range, so round-robin assignment 24.144 - newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv; 24.145 - 24.146 - if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 ) 24.147 - semEnv->nextCoreToGetNewSlv = 0; 24.148 - else 24.149 - semEnv->nextCoreToGetNewSlv += 1; 24.150 - } 24.151 - else //core num in-range, so use it 24.152 - { newSlv->coreAnimatedBy = coreToAssignOnto; 24.153 - } 24.154 - #endif 24.155 - //======================================================================== 24.156 - 24.157 - 24.158 - 24.159 - DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", 24.160 - requestingSlv->slaveID, newSlv->slaveID) 24.161 - 24.162 - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 24.163 - Dependency newD; 24.164 - newD.from_vp = requestingSlv->slaveID; 24.165 - newD.from_task = requestingSlv->numTimesAssignedToASlot; 24.166 - newD.to_vp = newSlv->slaveID; 24.167 - newD.to_task = 1; 24.168 - addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); 24.169 - #endif 24.170 - 24.171 - //For PRServ, caller needs ptr to created thread returned to it 24.172 - requestingSlv->dataRetFromReq = newSlv; 24.173 - PR_PI__make_slave_ready(requestingSlv , semEnv ); 24.174 - PR_PI__make_slave_ready( newSlv, semEnv ); 24.175 - } 24.176 - 24.177 -/*Initialize semantic data struct.. this initializer doesn't need any input, 24.178 - * but some languages may need something from inside the request that was sent 24.179 - * to create a slave.. in that case, just make initializer do the malloc then 24.180 - * use the PR_PI__give_sem_data inside the create handler, and fill in the 24.181 - * semData values there. 24.182 - */ 24.183 -void * PRServ__create_lang_data_in_slave( ) 24.184 - { PRServSemData *semData; 24.185 - 24.186 - semData = PR_PI__malloc( sizeof(PRServSemData) ); 24.187 - 24.188 - semData->highestTransEntered = -1; 24.189 - semData->lastTransEntered = NULL; 24.190 - return semData; 24.191 - } 24.192 - 24.193 -/*SlaveVP dissipate -- this is NOT task-end!, only call this to end explicitly 24.194 - * created threads 24.195 - */ 24.196 -inline void 24.197 -handleDissipate( SlaveVP *requestingSlv, PRServSemEnv *semEnv ) 24.198 - { PRServSemData *semData; 24.199 - PRServTaskStub *parentTaskStub, *ownTaskStub; 24.200 - 24.201 - DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d", 24.202 - requestingSlv->slaveID) 24.203 - 24.204 - ownTaskStub = PR_PI__give_lang_meta_task( requestingSlv, PRServ_MAGIC_NUMBER ); 24.205 - parentTaskStub = ownTaskStub->parentTaskStub; 24.206 - parentTaskStub->numLiveChildThreads -= 1; //parent wasn't freed, even if ended 24.207 - 24.208 - //if all children ended, then free this task's stub 24.209 - // else, keep stub around, and last child will free it (below) 24.210 - if( ownTaskStub->numLiveChildTasks == 0 && 24.211 - ownTaskStub->numLiveChildThreads == 0 ) 24.212 - free_task_stub( ownTaskStub ); 24.213 - else 24.214 - ownTaskStub->isEnded = TRUE; //for children to see when they end 24.215 - 24.216 - //Now, check on parents waiting on child threads to end 24.217 - if( parentTaskStub->isWaitingForChildThreadsToEnd && 24.218 - parentTaskStub->numLiveChildThreads == 0 ) 24.219 - { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE; 24.220 - if( parentTaskStub->isWaitingForChildTasksToEnd ) 24.221 - return; //still waiting on tasks (should be impossible) 24.222 - else //parent free to resume 24.223 - PR_PI__make_slave_ready( PR_PI__give_slave_assigned_to(parentTaskStub), semEnv ); 24.224 - } 24.225 - 24.226 - //check if this is last child of ended parent (note, not possible to 24.227 - // have more than one level of ancestor waiting to be freed) 24.228 - if( parentTaskStub->isEnded && 24.229 - parentTaskStub->numLiveChildTasks == 0 && 24.230 - parentTaskStub->numLiveChildThreads == 0 ) 24.231 - { free_task_stub( parentTaskStub ); //just stub, semData already freed 24.232 - } 24.233 - 24.234 - FreeSlaveStateAndReturn: 24.235 - //Used to free the semData and requesting slave's base state, but 24.236 - // now PR does those things, so nothing more to do.. 24.237 -//PR handles this: PR_PI__free( semData ); 24.238 -//PR handles this: PR_PI__dissipate_slaveVP( requestingSlv ); 24.239 - return; 24.240 - } 24.241 - 24.242 -/*Register this with PR, during PRServ start 24.243 - * 24.244 - *At some point, may change PR so that it recycles semData, in which case this 24.245 - * only gets called when a process shuts down.. at that point, PR will call 24.246 - * dissipate on all the slaves it has in the recycle Q. 24.247 - */ 24.248 -void 24.249 -freePRServSemData( void *_semData ) 24.250 - { // 24.251 - PR_PI__free( _semData ); 24.252 - } 24.253 - 24.254 -void resetPRServSemData( void *_semData ) 24.255 - { PRServSemData *semData = (PRServSemData *)_semData; 24.256 - 24.257 - semData->highestTransEntered = -1; 24.258 - semData->lastTransEntered = NULL; 24.259 - } 24.260 - 24.261 -//========================================================================== 24.262 -// 24.263 -// 24.264 -/*Submit Task 24.265 - * 24.266 - *PR creates a PRMetaTask and passes it in. This handler adds language- 24.267 - * specific stuff to it. The language-specific stuff is linked to the 24.268 - * PRMetaTask, but if the task is suspended for any reason, the lang-specific 24.269 - * part is moved to the semData of the slave that is animating the task. 24.270 - *So, while the PRMetaTask is inside the creating language's semantic 24.271 - * env, waiting to be assigned to a slave for animation, the lang-specific 24.272 - * task info is accessed from the PRMetaTask. But once the task suspends, 24.273 - * that lang-specific task info transfers to the slave's semData. All lang 24.274 - * constructs that want to access it must get it from the semData. 24.275 - *However, taskEnd still accesses the lang-specific task info from the 24.276 - * PRMetaTask, whether it suspended or not.. and the task code can access 24.277 - * data to be used within the application behavior via 24.278 - * PR__give_task_info( animatingSlave ). 24.279 - * 24.280 - *Uses a hash table to match the arg-pointers to each other. So, an 24.281 - * argument-pointer is one-to-one with a hash-table entry. 24.282 - * 24.283 - *If overlapping region detection is enabled, then a hash entry is one 24.284 - * link in a ring of all entries that overlap each other. For example, 24.285 - * say region A shared common addresses with region B, but the pointers 24.286 - * to them are different, then the hash entries for the two would be 24.287 - * linked in a ring. When a pointer is processed, all the pointers in 24.288 - * the ring are processed (Doesn't differentiate independent siblings 24.289 - * from parent-child or conjoined twins overlap..) 24.290 - * NOT ENABLED AS OF MAY 25 2012 24.291 - * 24.292 - *A hash entry has a queue of tasks that are waiting to access the 24.293 - * pointed-to region. The queue goes in the order of creation of 24.294 - * the tasks. Each entry in the queue has a pointer to the task-stub 24.295 - * and whether the task reads-only vs writes to the hash-entry's region. 24.296 - * 24.297 - *A hash entry also has a count of the enabled but not yet finished readers 24.298 - * of the region. It also has a flag that says whether a writer has been 24.299 - * enabled and is not yet finished. 24.300 - * 24.301 - *There are two kinds of events that access a hash entry: creation of a 24.302 - * task and end of a task. 24.303 - * 24.304 - * 24.305 - * ========================== creation ========================== 24.306 - * 24.307 - *At creation, make a task-stub. Set the count of blocking propendents 24.308 - * to the number of controlled arguments (a task can have 24.309 - * arguments that are not controlled by the language, like simple integer 24.310 - * inputs from the sequential portion. Note that all controlled arguments 24.311 - * are pointers, and marked as controlled in the application code). 24.312 - * 24.313 - *The controlled arguments are then processed one by one. 24.314 - *Processing an argument means getting the hash of the pointer. Then, 24.315 - * looking up the hash entry. (If none, create one). 24.316 - *With the hash entry: 24.317 - * 24.318 - *If the arg is a reader, and the entry does not have an enabled 24.319 - * non-finished writer, and the queue is empty (could be prev readers, 24.320 - * then a writer that got queued and now new readers that have to also be 24.321 - * queued). 24.322 - *The reader is free. So, decrement the blocking-propendent count in 24.323 - * the task-stub. If the count is zero, then put the task-stub into the 24.324 - * readyQ. 24.325 - *At the same time, increment the hash-entry's count of enabled and 24.326 - * non-finished readers. 24.327 - * 24.328 - *Otherwise, the reader is put into the hash-entry's Q of waiters 24.329 - * 24.330 - *If the arg is a writer, plus the entry does not have a current writer, 24.331 - * plus the number of enabled non-finished readers is zero, plus the Q is 24.332 - * empty, then the writer is free. Mark the entry has having an 24.333 - * enabled and non-finished writer. Decrement the blocking-propendent 24.334 - * count in the writer's task-stub. If the count is zero, then put the 24.335 - * task-stub into the readyQ. 24.336 - * 24.337 - *Otherwise, put the writer into the entry's Q of waiters. 24.338 - * 24.339 - *No matter what, if the hash entry was chained, put it at the start of 24.340 - * the chain. (Means no-longer-used pointers accumulate at end of chain, 24.341 - * decide garbage collection of no-longer-used pointers later) 24.342 - * 24.343 - */ 24.344 -inline 24.345 -void * 24.346 -handleSubmitTask( PRServSemReq *semReq, PRServSemEnv *semEnv ) 24.347 - { uint32 key[3]; 24.348 - HashEntry *rawHashEntry; //has char *, but use with uint32 * 24.349 - PRServPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer 24.350 - void **args; 24.351 - PRServTaskStub *taskStub, *parentTaskStub; 24.352 - PRServTaskType *taskType; 24.353 - PRServTaskStubCarrier *taskCarrier; 24.354 - 24.355 - HashTable * 24.356 - argPtrHashTbl = semEnv->argPtrHashTbl; 24.357 - 24.358 - 24.359 - /* ========================== creation ========================== 24.360 - *Make a task-stub. Set the count of blocking propendents 24.361 - * to the number of controlled arguments (a task can have 24.362 - * arguments that are not controlled by the language, like simple integer 24.363 - * inputs from the sequential portion. Note that all controlled arguments 24.364 - * are pointers, and marked as controlled in the application code). 24.365 - */ 24.366 - args = semReq->args; 24.367 - taskType = semReq->taskType; //this is PRServ task type struct 24.368 - taskStub = create_task_stub( taskType, args );//copies arg ptrs 24.369 - 24.370 - taskStub->numBlockingProp = taskType->numCtldArgs; 24.371 - //PR does this (metaTask contains taskID): taskStub->taskID = semReq->taskID; 24.372 - 24.373 - parentTaskStub = (PRServTaskStub *)PR_PI__give_lang_meta_task(semReq->callingSlv, PRServ_MAGIC_NUMBER); 24.374 - taskStub->parentTaskStub = parentTaskStub; 24.375 - parentTaskStub->numLiveChildTasks += 1; 24.376 - 24.377 - //DEBUG__printf3(dbgRqstHdlr,"Submit req from slaveID: %d, from task: %d, for task: %d", semReq->callingSlv->slaveID, parentSemData->taskStub->taskID[1], taskStub->taskID[1]) 24.378 - DEBUG__printf2(dbgRqstHdlr,"Submit req from slaveID: %d, for task: %d", semReq->callingSlv->slaveID, taskStub->taskID[1]) 24.379 - 24.380 - /*=============== Process args ================= 24.381 - *The controlled arguments are processed one by one. 24.382 - *Processing an argument means getting the hash of the pointer. Then, 24.383 - * looking up the hash entry. (If none, create one). 24.384 - */ 24.385 - int32 argNum; 24.386 - for( argNum = 0; argNum < taskType->numCtldArgs; argNum++ ) 24.387 - { 24.388 - key[0] = 2; //two 32b values in key 24.389 - *( (uint64*)&key[1]) = (uint64)args[argNum]; //write 64b into two 32b 24.390 - 24.391 - /*If the hash entry was chained, put it at the 24.392 - * start of the chain. (Means no-longer-used pointers accumulate 24.393 - * at end of chain, decide garbage collection later) */ 24.394 - rawHashEntry = getEntryFromTable32( key, argPtrHashTbl ); 24.395 - if( rawHashEntry == NULL ) 24.396 - { //adding a value auto-creates the hash-entry 24.397 - ptrEntry = create_pointer_entry(); 24.398 - rawHashEntry = addValueIntoTable32( key, ptrEntry, argPtrHashTbl ); 24.399 - } 24.400 - else 24.401 - { ptrEntry = (PRServPointerEntry *)rawHashEntry->content; 24.402 - if( ptrEntry == NULL ) 24.403 - { ptrEntry = create_pointer_entry(); 24.404 - rawHashEntry = addValueIntoTable32(key, ptrEntry, argPtrHashTbl); 24.405 - } 24.406 - } 24.407 - taskStub->ptrEntries[argNum] = ptrEntry; 24.408 - 24.409 - /*Have the hash entry. 24.410 - *If the arg is a reader and the entry does not have an enabled 24.411 - * non-finished writer, and the queue is empty. */ 24.412 - if( taskType->argTypes[argNum] == READER ) 24.413 - { if( !ptrEntry->hasEnabledNonFinishedWriter && 24.414 - isEmptyPrivQ( ptrEntry->waitersQ ) ) 24.415 - { /*The reader is free. So, decrement the blocking-propendent 24.416 - * count in the task-stub. If the count is zero, then put the 24.417 - * task-stub into the readyQ. At the same time, increment 24.418 - * the hash-entry's count of enabled and non-finished readers.*/ 24.419 - taskStub->numBlockingProp -= 1; 24.420 - if( taskStub->numBlockingProp == 0 ) 24.421 - { writePrivQ( taskStub, semEnv->taskReadyQ ); 24.422 - if( semEnv->protoSemEnv->hasWork != TRUE ) 24.423 - semEnv->protoSemEnv->hasWork = TRUE; 24.424 - } 24.425 - ptrEntry->numEnabledNonDoneReaders += 1; 24.426 - } 24.427 - else 24.428 - { /*Otherwise, the reader is put into the hash-entry's Q of 24.429 - * waiters*/ 24.430 - taskCarrier = create_task_carrier( taskStub, argNum, READER ); 24.431 - writePrivQ( taskCarrier, ptrEntry->waitersQ ); 24.432 - } 24.433 - } 24.434 - else //arg is a writer 24.435 - { /*the arg is a writer, plus the entry does not have a current 24.436 - * writer, plus the number of enabled non-finished readers is 24.437 - * zero, (the Q must be empty, else bug!) then the writer is free*/ 24.438 - if( !ptrEntry->hasEnabledNonFinishedWriter && 24.439 - ptrEntry->numEnabledNonDoneReaders == 0 ) 24.440 - { /*Mark the entry has having a enabled and non-finished writer. 24.441 - * Decrement the blocking-propenden count in the writer's 24.442 - * task-stub. If the count is zero, then put the task-stub 24.443 - * into the readyQ.*/ 24.444 - taskStub->numBlockingProp -= 1; 24.445 - if( taskStub->numBlockingProp == 0 ) 24.446 - { writePrivQ( taskStub, semEnv->taskReadyQ ); 24.447 - if( semEnv->protoSemEnv->hasWork != TRUE ) 24.448 - semEnv->protoSemEnv->hasWork = TRUE; 24.449 - } 24.450 - ptrEntry->hasEnabledNonFinishedWriter = TRUE; 24.451 - } 24.452 - else 24.453 - {/*Otherwise, put the writer into the entry's Q of waiters.*/ 24.454 - taskCarrier = create_task_carrier( taskStub, argNum, WRITER ); 24.455 - writePrivQ( taskCarrier, ptrEntry->waitersQ ); 24.456 - } 24.457 - } 24.458 - } //for argNum 24.459 - 24.460 - //resume the parent, creator 24.461 - PR_PI__make_slave_ready( semReq->callingSlv, semEnv ); 24.462 - 24.463 - return; 24.464 - } 24.465 - 24.466 - 24.467 -/* ========================== end of task =========================== 24.468 - * 24.469 - *At the end of a task, 24.470 - *The task's controlled arguments are processed one by one. 24.471 - *Processing an argument means getting the hash of the pointer. Then, 24.472 - * looking up the hash entry (and putting the entry at the start of the 24.473 - * chain, if there was a chain). 24.474 - *With the hash entry: 24.475 - * 24.476 - *If the arg is a reader, then decrement the enabled and non-finished 24.477 - * reader-count in the hash-entry. If the count becomes zero, then take 24.478 - * the next entry from the Q. It should be a writer, or else there's a 24.479 - * bug in this algorithm. 24.480 - *Set the hash-entry to have an enabled non-finished writer. Decrement 24.481 - * the blocking-propendent-count of the writer's task-stub. If the count 24.482 - * has reached zero, then put the task-stub into the readyQ. 24.483 - * 24.484 - *If the arg is a writer, then clear the enabled non-finished writer flag 24.485 - * of the hash-entry. Take the next entry from the waiters Q. 24.486 - *If it is a writer, then turn the flag back on. Decrement the writer's 24.487 - * blocking-propendent-count in its task-stub. If it becomes zero, then 24.488 - * put the task-stub into the readyQ. 24.489 - * 24.490 - *If waiter is a reader, then do a loop, getting all waiting readers. 24.491 - * For each, increment the hash-entry's count of enabled 24.492 - * non-finished readers. Decrement the blocking propendents count of the 24.493 - * reader's task-stub. If it reaches zero, then put the task-stub into the 24.494 - * readyQ. 24.495 - *Repeat until encounter a writer -- put that writer back into the Q. 24.496 - * 24.497 - *May 2012 -- not keeping track of how many references to a given ptrEntry 24.498 - * exist, so no way to garbage collect.. 24.499 - *TODO: Might be safe to delete an entry when task ends and waiterQ empty 24.500 - * and no readers and no writers.. 24.501 - */ 24.502 -inline void 24.503 -handleEndTask( void *langMetaTask, PRServSemReq *semReq, PRServSemEnv *semEnv ) 24.504 - { PRServPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer 24.505 - void **args; 24.506 - PRServSemData *endingSlvSemData; 24.507 - PRServTaskStub *endingTaskStub, *waitingTaskStub, *parentStub; 24.508 - PRServTaskType *endingTaskType; 24.509 - PRServTaskStubCarrier *waitingTaskCarrier; 24.510 - PRServPointerEntry **ptrEntries; 24.511 - 24.512 - 24.513 -// endingTaskStub = (PRServTaskStub *)PR_PI__give_lang_spec_task_info( semReq->callingSlv ); 24.514 - 24.515 - endingTaskStub = (PRServTaskStub *)langMetaTask; 24.516 - args = endingTaskStub->args; 24.517 - endingTaskType = endingTaskStub->taskType; 24.518 - ptrEntries = endingTaskStub->ptrEntries; //saved in stub when create 24.519 - 24.520 - DEBUG__printf2(dbgRqstHdlr,"EndTask req from slaveID: %d, task: %d",semReq->callingSlv->slaveID, endingTaskStub->taskID[1]) 24.521 - 24.522 - //"wait" functionality: Check if parent was waiting on this task 24.523 - parentStub = endingTaskStub->parentTaskStub; 24.524 - parentStub->numLiveChildTasks -= 1; 24.525 - if( parentStub->isWaitingForChildTasksToEnd && 24.526 - parentStub->numLiveChildTasks == 0) 24.527 - { 24.528 - parentStub->isWaitingForChildTasksToEnd = FALSE; 24.529 - PR_PI__make_slave_ready( PR_PI__give_slave_assigned_to(parentStub), semEnv ); 24.530 - } 24.531 - 24.532 - //Check if parent ended, and this was last descendent, then free it 24.533 - if( parentStub->isEnded && parentStub->numLiveChildTasks == 0 ) 24.534 - { free_task_stub( parentStub ); 24.535 - } 24.536 - 24.537 - 24.538 - //Now, update state of dependents and start ready tasks 24.539 - /*The task's controlled arguments are processed one by one. 24.540 - *Processing an argument means getting arg-pointer's entry. 24.541 - */ 24.542 - int32 argNum; 24.543 - for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ ) 24.544 - { 24.545 - ptrEntry = ptrEntries[argNum]; 24.546 - //check if the ending task was reader of this arg 24.547 - if( endingTaskType->argTypes[argNum] == READER ) 24.548 - { //then decrement the enabled and non-finished reader-count in 24.549 - // the hash-entry. 24.550 - ptrEntry->numEnabledNonDoneReaders -= 1; 24.551 - 24.552 - //If the count becomes zero, then take the next entry from the Q. 24.553 - //It should be a writer, or else there's a bug in this algorithm. 24.554 - if( ptrEntry->numEnabledNonDoneReaders == 0 ) 24.555 - { waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); 24.556 - if( waitingTaskCarrier == NULL ) 24.557 - { //TODO: looks safe to delete the ptr entry at this point 24.558 - continue; //next iter of loop 24.559 - } 24.560 - if( waitingTaskCarrier->isReader ) 24.561 - PR_App__throw_exception("READER waiting", NULL, NULL); 24.562 - 24.563 - waitingTaskStub = waitingTaskCarrier->taskStub; 24.564 - 24.565 - //Set the hash-entry to have an enabled non-finished writer. 24.566 - ptrEntry->hasEnabledNonFinishedWriter = TRUE; 24.567 - 24.568 - // Decrement the blocking-propendent-count of the writer's 24.569 - // task-stub. If the count has reached zero, then put the 24.570 - // task-stub into the readyQ. 24.571 - waitingTaskStub->numBlockingProp -= 1; 24.572 - if( waitingTaskStub->numBlockingProp == 0 ) 24.573 - { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); 24.574 - if( semEnv->protoSemEnv->hasWork != TRUE ) 24.575 - semEnv->protoSemEnv->hasWork = TRUE; 24.576 - } 24.577 - } 24.578 - } 24.579 - else //the ending task is a writer of this arg 24.580 - { //clear the enabled non-finished writer flag of the hash-entry. 24.581 - ptrEntry->hasEnabledNonFinishedWriter = FALSE; 24.582 - 24.583 - //Take the next waiter from the hash-entry's Q. 24.584 - waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); 24.585 - if( waitingTaskCarrier == NULL ) 24.586 - { //TODO: looks safe to delete ptr entry at this point 24.587 - continue; //go to next iter of loop, done here. 24.588 - } 24.589 - waitingTaskStub = waitingTaskCarrier->taskStub; 24.590 - 24.591 - //If task is a writer of this hash-entry's pointer 24.592 - if( !waitingTaskCarrier->isReader ) 24.593 - { // then turn the flag back on. 24.594 - ptrEntry->hasEnabledNonFinishedWriter = TRUE; 24.595 - //Decrement the writer's blocking-propendent-count in task-stub 24.596 - // If it becomes zero, then put the task-stub into the readyQ. 24.597 - waitingTaskStub->numBlockingProp -= 1; 24.598 - if( waitingTaskStub->numBlockingProp == 0 ) 24.599 - { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); 24.600 - if( semEnv->protoSemEnv->hasWork != TRUE ) 24.601 - semEnv->protoSemEnv->hasWork = TRUE; 24.602 - } 24.603 - } 24.604 - else 24.605 - { //Waiting task is a reader, so do a loop, of all waiting readers 24.606 - // until encounter a writer or waitersQ is empty 24.607 - while( TRUE ) //The checks guarantee have a waiting reader 24.608 - { //Increment the hash-entry's count of enabled non-finished 24.609 - // readers. 24.610 - ptrEntry->numEnabledNonDoneReaders += 1; 24.611 - 24.612 - //Decrement the blocking propendents count of the reader's 24.613 - // task-stub. If it reaches zero, then put the task-stub 24.614 - // into the readyQ. 24.615 - waitingTaskStub->numBlockingProp -= 1; 24.616 - if( waitingTaskStub->numBlockingProp == 0 ) 24.617 - { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); 24.618 - if( semEnv->protoSemEnv->hasWork != TRUE ) 24.619 - semEnv->protoSemEnv->hasWork = TRUE; 24.620 - } 24.621 - //Get next waiting task 24.622 - waitingTaskCarrier = peekPrivQ( ptrEntry->waitersQ ); 24.623 - if( waitingTaskCarrier == NULL ) break; //no more waiting readers 24.624 - if( !waitingTaskCarrier->isReader ) break; //no more waiting readers 24.625 - waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); 24.626 - waitingTaskStub = waitingTaskCarrier->taskStub; 24.627 - }//while waiter is a reader 24.628 - }//if-else, first waiting task is a reader 24.629 - }//if-else, check of ending task, whether writer or reader 24.630 - }//for argnum in ending task 24.631 - 24.632 - 24.633 - //done ending the task, if still has live children, then keep stub around 24.634 - // else, free the stub and args copy 24.635 - if( endingTaskStub->numLiveChildTasks == 0 && 24.636 - endingTaskStub->numLiveChildThreads == 0 ) 24.637 - { free_task_stub( endingTaskStub ); 24.638 - } 24.639 - 24.640 - return; 24.641 - } 24.642 - 24.643 - 24.644 -inline void 24.645 -free_task_stub( PRServTaskStub *stubToFree ) 24.646 - { if(stubToFree->ptrEntries != NULL ) //a thread stub has NULL entry 24.647 - { PR_PI__free( stubToFree->ptrEntries ); 24.648 - } 24.649 - PR_PI__free( stubToFree ); 24.650 - } 24.651 - 24.652 -//========================== Task Comm handlers =========================== 24.653 - 24.654 - 24.655 - 24.656 -//============================ Send Handlers ============================== 24.657 -/*Send of Type -- The semantic request has the receiving task ID and Type 24.658 - * 24.659 - *Messages of a given Type have to be kept separate.. so need a separate 24.660 - * entry in the hash table for each pair: receiverID, Type 24.661 - * 24.662 - *Also, if same sender sends multiple before any get received, then need to 24.663 - * stack the sends up -- even if a send waits until it's paired, several 24.664 - * separate tasks can send to the same receiver, and doing hash on the 24.665 - * receive task, so they will stack up. 24.666 - */ 24.667 -inline void 24.668 -handleSendTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv ) 24.669 - { SlaveVP *senderSlv, *receiverSlv; 24.670 - int32 *senderID, *receiverID; 24.671 - int32 *key, keySz, receiverIDNumInt; 24.672 - PRServSemReq *waitingReq; 24.673 - HashEntry *entry; 24.674 - HashTable *commHashTbl = semEnv->commHashTbl; 24.675 - 24.676 - receiverID = semReq->receiverID; //For "send", know both send & recv procrs 24.677 - senderSlv = semReq->senderSlv; 24.678 - 24.679 - DEBUG__printf2(dbgRqstHdlr,"SendType req from sender slaveID: %d, recTask: %d", senderSlv->slaveID, receiverID[1]) 24.680 - 24.681 - 24.682 - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself 24.683 - keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); 24.684 - key = PR_PI__malloc( keySz ); 24.685 - key[0] = receiverIDNumInt + 1; //loc 0 is num int32 in key 24.686 - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 24.687 - key[ 1 + receiverIDNumInt ] = semReq->msgType; 24.688 - 24.689 - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); 24.690 - if( entry == NULL ) //was just inserted, means task has to wait 24.691 - { return; 24.692 - } 24.693 - 24.694 - //if here, found a waiting request with same key 24.695 - waitingReq = (PRServSemReq *)entry->content; 24.696 - 24.697 - //At this point, know have waiting request(s) -- either sends or recv 24.698 - //Note, can only have max of one receive waiting, and cannot have both 24.699 - // sends and receives waiting (they would have paired off) 24.700 - // but can have multiple sends from diff sending VPs, all same msg-type 24.701 - if( waitingReq->reqType == send_type_to ) 24.702 - { //waiting request is another send, so stack this up on list 24.703 - // but first clone the sending request so it persists. 24.704 - PRServSemReq *clonedReq = cloneReq( semReq ); 24.705 - clonedReq-> nextReqInHashEntry = waitingReq->nextReqInHashEntry; 24.706 - waitingReq->nextReqInHashEntry = clonedReq; 24.707 - DEBUG__printf2( dbgRqstHdlr, "linked requests: %p, %p ", clonedReq,\ 24.708 - waitingReq ) 24.709 - return; 24.710 - } 24.711 - else 24.712 - { 24.713 - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 24.714 - Dependency newD; 24.715 - newD.from_vp = senderID->slaveID; 24.716 - newD.from_task = senderID->numTimesAssignedToASlot; 24.717 - newD.to_vp = receiverID->slaveID; 24.718 - newD.to_task = receiverID->numTimesAssignedToASlot +1; 24.719 - //(newD,semEnv->commDependenciesList); 24.720 - addToListOfArrays(Dependency,newD,semEnv->dynDependenciesList); 24.721 - int32 groupId = semReq->msgType; 24.722 - if(semEnv->ntonGroupsInfo->numInArray <= groupId){ 24.723 - makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); 24.724 - } 24.725 - if(semEnv->ntonGroups[groupId] == NULL){ 24.726 - semEnv->ntonGroups[groupId] = new_NtoN(groupId); 24.727 - } 24.728 - Unit u; 24.729 - u.vp = senderID->slaveID; 24.730 - u.task = senderID->numTimesAssignedToASlot; 24.731 - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); 24.732 - u.vp = receiverID->slaveID; 24.733 - u.task = receiverID->numTimesAssignedToASlot +1; 24.734 - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); 24.735 - #endif 24.736 - 24.737 - //set receiver slave, from the waiting request 24.738 - receiverSlv = waitingReq->receiverSlv; 24.739 - 24.740 - //waiting request is a receive_type_to, so it pairs to this send 24.741 - //First, remove the waiting receive request from the entry 24.742 - entry->content = waitingReq->nextReqInHashEntry; 24.743 - PR_PI__free( waitingReq ); //Don't use contents -- so free it 24.744 - 24.745 - if( entry->content == NULL ) 24.746 - { //TODO: mod hash table to double-link, so can delete entry from 24.747 - // table without hashing the key and looking it up again 24.748 - deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees hashEntry 24.749 - } 24.750 - 24.751 - //attach msg that's in this send request to receiving task's Slv 24.752 - // when comes back from suspend will have msg in dataRetFromReq 24.753 - receiverSlv->dataRetFromReq = semReq->msg; 24.754 - 24.755 - //bring both processors back from suspend 24.756 - PR_PI__make_slave_ready( senderSlv, semEnv ); 24.757 - PR_PI__make_slave_ready( receiverSlv, semEnv ); 24.758 - 24.759 - return; 24.760 - } 24.761 - } 24.762 - 24.763 - 24.764 -/*If Send or Receive are called within a task, it causes the task to suspend, 24.765 - * which converts the slave animating it to a free slave and suspends that slave. 24.766 - *Which means that send and receive operate upon slaves, no matter whether they 24.767 - * were called from within a task or a slave. 24.768 - * 24.769 - *Looks like can make single handler for both kinds of send.. 24.770 - */ 24.771 -//TODO: combine both send handlers into single handler 24.772 -inline void 24.773 -handleSendFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv) 24.774 - { SlaveVP *senderSlv, *receiverSlv; 24.775 - int32 *senderID, *receiverID; 24.776 - int32 *key, keySz, receiverIDNumInt, senderIDNumInt; 24.777 - PRServSemReq *waitingReq; 24.778 - HashEntry *entry; 24.779 - HashTable *commHashTbl = semEnv->commHashTbl; 24.780 - 24.781 - DEBUG__printf2(dbgRqstHdlr,"SendFromTo req from task %d to %d", 24.782 - semReq->senderID[1],semReq->receiverID[1]) 24.783 - 24.784 - receiverID = semReq->receiverID; //For "send", know both send & recv procrs 24.785 - senderID = semReq->senderID; 24.786 - senderSlv = semReq->senderSlv; 24.787 - 24.788 - 24.789 - receiverIDNumInt = receiverID[0] + 1; //include the count in the key 24.790 - senderIDNumInt = senderID[0] + 1; 24.791 - keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); 24.792 - key = PR_PI__malloc( keySz ); 24.793 - key[0] = receiverIDNumInt + senderIDNumInt; 24.794 - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 24.795 - memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); 24.796 - 24.797 - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); 24.798 - if( entry == NULL ) //was just inserted, means task has to wait 24.799 - { return; 24.800 - } 24.801 - 24.802 - waitingReq = (PRServSemReq *)entry->content; 24.803 - 24.804 - //At this point, know have waiting request(s) -- either sends or recv 24.805 - if( waitingReq->reqType == send_from_to ) 24.806 - { printf("\n ERROR: shouldn't be two send-from-tos waiting \n"); 24.807 - } 24.808 - else 24.809 - { //waiting request is a receive, so it completes pair with this send 24.810 - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 24.811 - Dependency newD; 24.812 - newD.from_vp = sendPr->slaveID; 24.813 - newD.from_task = sendPr->numTimesAssignedToASlot; 24.814 - newD.to_vp = receivePr->slaveID; 24.815 - newD.to_task = receivePr->numTimesAssignedToASlot +1; 24.816 - //addToListOfArraysDependency(newD,semEnv->commDependenciesList); 24.817 - addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); 24.818 - #endif 24.819 - 24.820 - //set receiver slave, from the waiting request 24.821 - receiverSlv = waitingReq->receiverSlv; 24.822 - 24.823 - //First, remove the waiting receive request from the entry 24.824 - entry->content = waitingReq->nextReqInHashEntry; 24.825 - PR_PI__free( waitingReq ); //Don't use contents -- so free it 24.826 - 24.827 - //can only be one waiting req for "from-to" semantics 24.828 - if( entry->content != NULL ) 24.829 - { 24.830 - printf("\nERROR in handleSendFromTo\n"); 24.831 - } 24.832 - deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry 24.833 - 24.834 - //attach msg that's in this send request to receiving procr 24.835 - // when comes back from suspend, will have msg in dataRetFromReq 24.836 - receiverSlv->dataRetFromReq = semReq->msg; 24.837 - 24.838 - //bring both processors back from suspend 24.839 - PR_PI__make_slave_ready( senderSlv, semEnv ); 24.840 - PR_PI__make_slave_ready( receiverSlv, semEnv ); 24.841 - 24.842 - return; 24.843 - } 24.844 - } 24.845 - 24.846 - 24.847 - 24.848 -//============================== Receives =========================== 24.849 -// 24.850 - 24.851 - 24.852 -inline void 24.853 -handleReceiveTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv) 24.854 - { SlaveVP *senderSlv, *receiverSlv; 24.855 - int32 *receiverID; 24.856 - int32 *key, keySz, receiverIDNumInt; 24.857 - PRServSemReq *waitingReq; 24.858 - HashEntry *entry; 24.859 - HashTable *commHashTbl = semEnv->commHashTbl; 24.860 - 24.861 - DEBUG__printf2(dbgRqstHdlr,"ReceiveType req to ID: %d type: %d",semReq->receiverID[1], semReq->msgType) 24.862 - 24.863 - receiverID = semReq->receiverID; //For "send", know both send & recv procrs 24.864 - receiverSlv = semReq->receiverSlv; 24.865 - 24.866 - 24.867 - //key is the receiverID plus the type -- have to copy them into key 24.868 - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself 24.869 - keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); 24.870 - key = PR_PI__malloc( keySz ); 24.871 - key[0] = receiverIDNumInt + 1; //loc 0 is num int32s in key 24.872 - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 24.873 - key[ 1 + receiverIDNumInt ] = semReq->msgType; 24.874 - 24.875 - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );//clones 24.876 - if( entry == NULL ) //was just inserted, means task has to wait 24.877 - { return; 24.878 - } 24.879 - 24.880 - waitingReq = (PRServSemReq *)entry->content; //previously cloned by insert 24.881 - 24.882 - //At this point, know have waiting request(s) -- should be send(s) 24.883 - if( waitingReq->reqType == send_type_to ) 24.884 - { 24.885 - //set sending slave from the request 24.886 - senderSlv = waitingReq->senderSlv; 24.887 - 24.888 - //waiting request is a send, so pair it with this receive 24.889 - //first, remove the waiting send request from the list in entry 24.890 - entry->content = waitingReq->nextReqInHashEntry; 24.891 - if( entry->content == NULL ) 24.892 - { deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry 24.893 - } 24.894 - 24.895 - //attach msg that's in the send request to receiving procr 24.896 - // when comes back from suspend, will have msg in dataRetFromReq 24.897 - receiverSlv->dataRetFromReq = waitingReq->msg; 24.898 - 24.899 - //bring both processors back from suspend 24.900 - PR_PI__free( waitingReq ); 24.901 - 24.902 - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 24.903 - Dependency newD; 24.904 - newD.from_vp = sendPr->slaveID; 24.905 - newD.from_task = sendPr->numTimesAssignedToASlot; 24.906 - newD.to_vp = receivePr->slaveID; 24.907 - newD.to_task = receivePr->numTimesAssignedToASlot +1; 24.908 - //addToListOfArraysDependency(newD,semEnv->commDependenciesList); 24.909 - addToListOfArrays(Dependency,newD,semEnv->dynDependenciesList); 24.910 - int32 groupId = semReq->msgType; 24.911 - if(semEnv->ntonGroupsInfo->numInArray <= groupId){ 24.912 - makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); 24.913 - } 24.914 - if(semEnv->ntonGroups[groupId] == NULL){ 24.915 - semEnv->ntonGroups[groupId] = new_NtoN(groupId); 24.916 - } 24.917 - Unit u; 24.918 - u.vp = sendPr->slaveID; 24.919 - u.task = sendPr->numTimesAssignedToASlot; 24.920 - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); 24.921 - u.vp = receivePr->slaveID; 24.922 - u.task = receivePr->numTimesAssignedToASlot +1; 24.923 - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); 24.924 - #endif 24.925 - 24.926 - PR_PI__make_slave_ready( senderSlv, semEnv ); 24.927 - PR_PI__make_slave_ready( receiverSlv, semEnv ); 24.928 - 24.929 - return; 24.930 - } 24.931 - printf("\nLang Impl Error: Should never be two waiting receives!\n"); 24.932 - } 24.933 - 24.934 - 24.935 -/* 24.936 - */ 24.937 -inline void 24.938 -handleReceiveFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv) 24.939 - { SlaveVP *senderSlv, *receiverSlv; 24.940 - int32 *senderID, *receiverID; 24.941 - int32 *key, keySz, receiverIDNumInt, senderIDNumInt; 24.942 - PRServSemReq *waitingReq; 24.943 - HashEntry *entry; 24.944 - HashTable *commHashTbl = semEnv->commHashTbl; 24.945 - 24.946 - DEBUG__printf2(dbgRqstHdlr,"RecFromTo req from ID: %d to ID: %d",semReq->senderID[1],semReq->receiverID[1]) 24.947 - 24.948 - receiverID = semReq->receiverID; //For "send", know both send & recv procrs 24.949 - senderID = semReq->senderID; 24.950 - receiverSlv = semReq->receiverSlv; 24.951 - 24.952 - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself 24.953 - senderIDNumInt = senderID[0] + 1; 24.954 - keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); 24.955 - key = PR_PI__malloc( keySz ); 24.956 - key[0] = receiverIDNumInt + senderIDNumInt; //loc 0 is num int32s in key 24.957 - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 24.958 - memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32)); 24.959 - 24.960 - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); 24.961 - if( entry == NULL ) //was just inserted, means task has to wait 24.962 - { return; 24.963 - } 24.964 - 24.965 - waitingReq = (PRServSemReq *)entry->content; 24.966 - 24.967 - //At this point, know have a request to rendez-vous -- should be send 24.968 - if( waitingReq->reqType == send_from_to ) 24.969 - { //waiting request is a send, so pair it with this receive 24.970 - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 24.971 - Dependency newD; 24.972 - newD.from_vp = sendPr->slaveID; 24.973 - newD.from_task = sendPr->numTimesAssignedToASlot; 24.974 - newD.to_vp = receivePr->slaveID; 24.975 - newD.to_task = receivePr->numTimesAssignedToASlot +1; 24.976 - //addToListOfArraysDependency(newD,semEnv->commDependenciesList); 24.977 - addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); 24.978 - #endif 24.979 - 24.980 - //have receiver slave, now set sender slave 24.981 - senderSlv = waitingReq->senderSlv; 24.982 - 24.983 - //For from-to, should only ever be a single reqst waiting tobe paird 24.984 - entry->content = waitingReq->nextReqInHashEntry; 24.985 - if( entry->content != NULL ) printf("\nERROR in handleRecvFromTo\n"); 24.986 - deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees entry too 24.987 - 24.988 - //attach msg that's in the send request to receiving procr 24.989 - // when comes back from suspend, will have msg in dataRetFromReq 24.990 - receiverSlv->dataRetFromReq = waitingReq->msg; 24.991 - 24.992 - //bring both processors back from suspend 24.993 - PR_PI__free( waitingReq ); 24.994 - 24.995 - PR_PI__make_slave_ready( senderSlv, semEnv ); 24.996 - PR_PI__make_slave_ready( receiverSlv, semEnv ); 24.997 - 24.998 - return; 24.999 - } 24.1000 - printf("\nLang Impl Error: Should never be two waiting receives!\n"); 24.1001 - } 24.1002 - 24.1003 - 24.1004 -/*Waits for all tasks that are direct children to end, then resumes calling 24.1005 - * task or thread 24.1006 - */ 24.1007 -inline void 24.1008 -handleTaskwait( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv) 24.1009 - { PRServTaskStub* taskStub; 24.1010 - 24.1011 - DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d", 24.1012 - requestingSlv->slaveID) 24.1013 - 24.1014 - taskStub = (PRServTaskStub *)PR_PI__give_lang_meta_task( requestingSlv, PRServ_MAGIC_NUMBER); 24.1015 - 24.1016 - if( taskStub->numLiveChildTasks == 0 ) 24.1017 - { //nobody to wait for, resume 24.1018 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1019 - } 24.1020 - else //have to wait, mark waiting 24.1021 - { 24.1022 - taskStub->isWaitingForChildTasksToEnd = TRUE; 24.1023 - } 24.1024 - } 24.1025 24.1026 24.1027 //========================================================================== 24.1028 /* 24.1029 */ 24.1030 void 24.1031 -handleMalloc( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ) 24.1032 +PRServ__handleMalloc( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ) 24.1033 { void *ptr; 24.1034 24.1035 - DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveID) 24.1036 + DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveNum) 24.1037 24.1038 - ptr = PR_PI__malloc( semReq->sizeToMalloc ); 24.1039 + ptr = PR_PI__malloc( langReq->sizeToMalloc ); 24.1040 requestingSlv->dataRetFromReq = ptr; 24.1041 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1042 + PR_PI__make_slave_ready( requestingSlv, langEnv ); 24.1043 } 24.1044 24.1045 /* 24.1046 */ 24.1047 void 24.1048 -handleFree( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ) 24.1049 +PRServ__handleFree( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ) 24.1050 { 24.1051 - DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveID) 24.1052 - PR_PI__free( semReq->ptrToFree ); 24.1053 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1054 + DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveNum) 24.1055 + PR_PI__free( langReq->ptrToFree ); 24.1056 + PR_PI__make_slave_ready( requestingSlv, langEnv ); 24.1057 } 24.1058 24.1059 24.1060 @@ -1067,14 +49,15 @@ 24.1061 /*Uses ID as index into array of flags. If flag already set, resumes from 24.1062 * end-label. Else, sets flag and resumes normally. 24.1063 */ 24.1064 -void inline 24.1065 -handleStartSingleton_helper( PRServSingleton *singleton, SlaveVP *reqstingSlv, 24.1066 - PRServSemEnv *semEnv ) 24.1067 +void 24.1068 +//inline 24.1069 +PRServ__handleStartSingleton_helper( PRServSingleton *singleton, SlaveVP *reqstingSlv, 24.1070 + PRServLangEnv *langEnv ) 24.1071 { 24.1072 if( singleton->hasFinished ) 24.1073 { //the code that sets the flag to true first sets the end instr addr 24.1074 reqstingSlv->dataRetFromReq = singleton->endInstrAddr; 24.1075 - PR_PI__make_slave_ready( reqstingSlv, semEnv ); 24.1076 + PR_PI__make_slave_ready( reqstingSlv, langEnv ); 24.1077 return; 24.1078 } 24.1079 else if( singleton->hasBeenStarted ) 24.1080 @@ -1086,42 +69,45 @@ 24.1081 { //hasn't been started, so this is the first attempt at the singleton 24.1082 singleton->hasBeenStarted = TRUE; 24.1083 reqstingSlv->dataRetFromReq = 0x0; 24.1084 - PR_PI__make_slave_ready( reqstingSlv, semEnv ); 24.1085 + PR_PI__make_slave_ready( reqstingSlv, langEnv ); 24.1086 return; 24.1087 } 24.1088 } 24.1089 -void inline 24.1090 -handleStartFnSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, 24.1091 - PRServSemEnv *semEnv ) 24.1092 +void 24.1093 +//inline 24.1094 +PRServ__handleStartFnSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, 24.1095 + PRServLangEnv *langEnv ) 24.1096 { PRServSingleton *singleton; 24.1097 - DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingSlv->slaveID) 24.1098 + DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingSlv->slaveNum) 24.1099 24.1100 - singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); 24.1101 - handleStartSingleton_helper( singleton, requestingSlv, semEnv ); 24.1102 + singleton = &(langEnv->fnSingletons[ langReq->singletonID ]); 24.1103 + PRServ__handleStartSingleton_helper( singleton, requestingSlv, langEnv ); 24.1104 } 24.1105 -void inline 24.1106 -handleStartDataSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, 24.1107 - PRServSemEnv *semEnv ) 24.1108 +void 24.1109 +//inline 24.1110 +PRServ__handleStartDataSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, 24.1111 + PRServLangEnv *langEnv ) 24.1112 { PRServSingleton *singleton; 24.1113 24.1114 - DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveID) 24.1115 - if( *(semReq->singletonPtrAddr) == NULL ) 24.1116 + DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveNum) 24.1117 + if( *(langReq->singletonPtrAddr) == NULL ) 24.1118 { singleton = PR_PI__malloc( sizeof(PRServSingleton) ); 24.1119 singleton->waitQ = makePRQ(); 24.1120 singleton->endInstrAddr = 0x0; 24.1121 singleton->hasBeenStarted = FALSE; 24.1122 singleton->hasFinished = FALSE; 24.1123 - *(semReq->singletonPtrAddr) = singleton; 24.1124 + *(langReq->singletonPtrAddr) = singleton; 24.1125 } 24.1126 else 24.1127 - singleton = *(semReq->singletonPtrAddr); 24.1128 - handleStartSingleton_helper( singleton, requestingSlv, semEnv ); 24.1129 + singleton = *(langReq->singletonPtrAddr); 24.1130 + PRServ__handleStartSingleton_helper( singleton, requestingSlv, langEnv ); 24.1131 } 24.1132 24.1133 24.1134 -void inline 24.1135 -handleEndSingleton_helper( PRServSingleton *singleton, SlaveVP *requestingSlv, 24.1136 - PRServSemEnv *semEnv ) 24.1137 +void 24.1138 +//inline 24.1139 +PRServ__handleEndSingleton_helper( PRServSingleton *singleton, SlaveVP *requestingSlv, 24.1140 + PRServLangEnv *langEnv ) 24.1141 { PrivQueueStruc *waitQ; 24.1142 int32 numWaiting, i; 24.1143 SlaveVP *resumingSlv; 24.1144 @@ -1139,33 +125,33 @@ 24.1145 { //they will resume inside start singleton, then jmp to end singleton 24.1146 resumingSlv = readPrivQ( waitQ ); 24.1147 resumingSlv->dataRetFromReq = singleton->endInstrAddr; 24.1148 - PR_PI__make_slave_ready( resumingSlv, semEnv ); 24.1149 + PR_PI__make_slave_ready( resumingSlv, langEnv ); 24.1150 } 24.1151 24.1152 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1153 + PR_PI__make_slave_ready( requestingSlv, langEnv ); 24.1154 24.1155 } 24.1156 -void inline 24.1157 -handleEndFnSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, 24.1158 - PRServSemEnv *semEnv ) 24.1159 +void 24.1160 +PRServ__handleEndFnSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, 24.1161 + PRServLangEnv *langEnv ) 24.1162 { 24.1163 PRServSingleton *singleton; 24.1164 24.1165 - DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingSlv->slaveID) 24.1166 + DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingSlv->slaveNum) 24.1167 24.1168 - singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); 24.1169 - handleEndSingleton_helper( singleton, requestingSlv, semEnv ); 24.1170 + singleton = &(langEnv->fnSingletons[ langReq->singletonID ]); 24.1171 + PRServ__handleEndSingleton_helper( singleton, requestingSlv, langEnv ); 24.1172 } 24.1173 -void inline 24.1174 -handleEndDataSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, 24.1175 - PRServSemEnv *semEnv ) 24.1176 +void 24.1177 +PRServ__handleEndDataSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, 24.1178 + PRServLangEnv *langEnv ) 24.1179 { 24.1180 PRServSingleton *singleton; 24.1181 24.1182 - DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingSlv->slaveID) 24.1183 + DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingSlv->slaveNum) 24.1184 24.1185 - singleton = *(semReq->singletonPtrAddr); 24.1186 - handleEndSingleton_helper( singleton, requestingSlv, semEnv ); 24.1187 + singleton = *(langReq->singletonPtrAddr); 24.1188 + PRServ__handleEndSingleton_helper( singleton, requestingSlv, langEnv ); 24.1189 } 24.1190 24.1191 24.1192 @@ -1173,11 +159,11 @@ 24.1193 * pointer out of the request and call it, then resume the VP. 24.1194 */ 24.1195 void 24.1196 -handleAtomic( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ) 24.1197 +PRServ__handleAtomic( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ) 24.1198 { 24.1199 - DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingSlv->slaveID) 24.1200 - semReq->fnToExecInMaster( semReq->dataForFn ); 24.1201 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1202 + DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingSlv->slaveNum) 24.1203 + langReq->fnToExecInMaster( langReq->dataForFn ); 24.1204 + PR_PI__make_slave_ready( requestingSlv, langEnv ); 24.1205 } 24.1206 24.1207 /*First, it looks at the VP's semantic data, to see the highest transactionID 24.1208 @@ -1195,35 +181,35 @@ 24.1209 *If NULL, then write requesting into the field and resume. 24.1210 */ 24.1211 void 24.1212 -handleTransStart( PRServSemReq *semReq, SlaveVP *requestingSlv, 24.1213 - PRServSemEnv *semEnv ) 24.1214 - { PRServSemData *semData; 24.1215 - TransListElem *nextTransElem; 24.1216 +PRServ__handleTransStart( PRServLangReq *langReq, SlaveVP *requestingSlv, 24.1217 + PRServLangEnv *langEnv ) 24.1218 + { PRServLangData *langData; 24.1219 + PRServTransListElem *nextTransElem; 24.1220 24.1221 - DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingSlv->slaveID) 24.1222 + DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingSlv->slaveNum) 24.1223 24.1224 //check ordering of entering transactions is correct 24.1225 - semData = requestingSlv->semanticData; 24.1226 - if( semData->highestTransEntered > semReq->transID ) 24.1227 + langData = PR_PI__give_lang_data_from_slave(requestingSlv, PRServ_MAGIC_NUMBER); 24.1228 + if( langData->highestTransEntered > langReq->transID ) 24.1229 { //throw PR exception, which shuts down PR. 24.1230 PR_PI__throw_exception( "transID smaller than prev", requestingSlv, NULL); 24.1231 } 24.1232 //add this trans ID to the list of transactions entered -- check when 24.1233 // end a transaction 24.1234 - semData->highestTransEntered = semReq->transID; 24.1235 - nextTransElem = PR_PI__malloc( sizeof(TransListElem) ); 24.1236 - nextTransElem->transID = semReq->transID; 24.1237 - nextTransElem->nextTrans = semData->lastTransEntered; 24.1238 - semData->lastTransEntered = nextTransElem; 24.1239 + langData->highestTransEntered = langReq->transID; 24.1240 + nextTransElem = PR_PI__malloc( sizeof(PRServTransListElem) ); 24.1241 + nextTransElem->transID = langReq->transID; 24.1242 + nextTransElem->nextTrans = langData->lastTransEntered; 24.1243 + langData->lastTransEntered = nextTransElem; 24.1244 24.1245 //get the structure for this transaction ID 24.1246 PRServTrans * 24.1247 - transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 24.1248 + transStruc = &(langEnv->transactionStrucs[ langReq->transID ]); 24.1249 24.1250 if( transStruc->VPCurrentlyExecuting == NULL ) 24.1251 { 24.1252 transStruc->VPCurrentlyExecuting = requestingSlv; 24.1253 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1254 + PR_PI__make_slave_ready( requestingSlv, langEnv ); 24.1255 } 24.1256 else 24.1257 { //note, might make future things cleaner if save request with VP and 24.1258 @@ -1248,15 +234,15 @@ 24.1259 * resume both. 24.1260 */ 24.1261 void 24.1262 -handleTransEnd(PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv) 24.1263 - { PRServSemData *semData; 24.1264 +PRServ__handleTransEnd(PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv) 24.1265 + { PRServLangData *langData; 24.1266 SlaveVP *waitingSlv; 24.1267 PRServTrans *transStruc; 24.1268 - TransListElem *lastTrans; 24.1269 + PRServTransListElem *lastTrans; 24.1270 24.1271 - DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingSlv->slaveID) 24.1272 + DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingSlv->slaveNum) 24.1273 24.1274 - transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 24.1275 + transStruc = &(langEnv->transactionStrucs[ langReq->transID ]); 24.1276 24.1277 //make sure transaction ended in same VP as started it. 24.1278 if( transStruc->VPCurrentlyExecuting != requestingSlv ) 24.1279 @@ -1265,21 +251,163 @@ 24.1280 } 24.1281 24.1282 //make sure nesting is correct -- last ID entered should == this ID 24.1283 - semData = requestingSlv->semanticData; 24.1284 - lastTrans = semData->lastTransEntered; 24.1285 - if( lastTrans->transID != semReq->transID ) 24.1286 + langData = PR_PI__give_lang_data_from_slave(requestingSlv, PRServ_MAGIC_NUMBER); 24.1287 + lastTrans = langData->lastTransEntered; 24.1288 + if( lastTrans->transID != langReq->transID ) 24.1289 { 24.1290 PR_PI__throw_exception( "trans incorrectly nested", requestingSlv, NULL ); 24.1291 } 24.1292 24.1293 - semData->lastTransEntered = semData->lastTransEntered->nextTrans; 24.1294 + langData->lastTransEntered = langData->lastTransEntered->nextTrans; 24.1295 24.1296 24.1297 waitingSlv = readPrivQ( transStruc->waitingVPQ ); 24.1298 transStruc->VPCurrentlyExecuting = waitingSlv; 24.1299 24.1300 if( waitingSlv != NULL ) 24.1301 - PR_PI__make_slave_ready( waitingSlv, semEnv ); 24.1302 + PR_PI__make_slave_ready( waitingSlv, langEnv ); 24.1303 24.1304 - PR_PI__make_slave_ready( requestingSlv, semEnv ); 24.1305 + PR_PI__make_slave_ready( requestingSlv, langEnv ); 24.1306 } 24.1307 + 24.1308 + 24.1309 +//========================================================================== 24.1310 +// Helpers 24.1311 +// 24.1312 +void 24.1313 +PRServ__make_task_ready( void *taskStub, void *_langEnv ) 24.1314 + { 24.1315 + writePrivQ( taskStub, ((PRServLangEnv*)_langEnv)->taskReadyQ ); 24.1316 + } 24.1317 + 24.1318 + 24.1319 +/*Proto Runtime has a special call-chain for resuming a slaveVP. The langlet 24.1320 + * supplies a function to perform the resume, but then registers it with 24.1321 + * PR, and instead calls PR's version.. PR then decides whether to handle 24.1322 + * the resume itself, or pass resume along to this registered handler. 24.1323 + */ 24.1324 +void 24.1325 +PRServ__resume_slave( SlaveVP *slave, void *_langEnv ) 24.1326 + { PRServLangEnv *langEnv = (PRServLangEnv *)_langEnv; 24.1327 + 24.1328 + //both suspended tasks and suspended explicit slaves resumed with this 24.1329 + writePrivQ( slave, langEnv->slavesReadyToResumeQ ); 24.1330 +//PR handles this.. PR_int__set_work_in_lang_env(langEnv); 24.1331 + 24.1332 + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 24.1333 +/* 24.1334 + int lastRecordIdx = slave->counter_history_array_info->numInArray -1; 24.1335 + CounterRecord* lastRecord = slave->counter_history[lastRecordIdx]; 24.1336 + saveLowTimeStampCountInto(lastRecord->unblocked_timestamp); 24.1337 +*/ 24.1338 + #endif 24.1339 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 24.1340 + slave->numTimesAssignedToASlot++; //Somewhere here! 24.1341 + Unit newU; 24.1342 + newU.vp = slave->slaveNum; 24.1343 + newU.task = slave->numTimesAssignedToASlot; 24.1344 + addToListOfArrays(Unit,newU,langEnv->unitList); 24.1345 + 24.1346 + if (slave->numTimesAssignedToASlot > 1) 24.1347 + { Dependency newD; 24.1348 + newD.from_vp = slave->slaveNum; 24.1349 + newD.from_task = slave->numTimesAssignedToASlot - 1; 24.1350 + newD.to_vp = slave->slaveNum; 24.1351 + newD.to_task = slave->numTimesAssignedToASlot; 24.1352 + addToListOfArrays(Dependency, newD ,langEnv->ctlDependenciesList); 24.1353 + } 24.1354 + #endif 24.1355 + } 24.1356 + 24.1357 +void 24.1358 +PRServ__handleDissipateSeed(void *langReq, SlaveVP *seedSlv, VSsLangEnv *langEnv ) 24.1359 + { 24.1360 + 24.1361 + DEBUG__printf1(dbgRqstHdlr,"Dissipate in PRServ %d", 24.1362 + requestingSlv->slaveNum); 24.1363 + //This should only ever be called for the seed slave -- for which there's 24.1364 + // nothing to do.. 24.1365 + if( seedSlv->typeOfVP != SeedSlv ) 24.1366 + { 24.1367 + PR_int__throw_exception( "PR__end_seed called on non-seed slave\n", NULL, NULL); 24.1368 + } 24.1369 + } 24.1370 + 24.1371 +void 24.1372 +PRServ__handle_end_process_from_inside( void *langReq, SlaveVP *reqSlave, PRServLangEnv *langEnv ) 24.1373 + { PR_SS__end_process_normally( reqSlave->processSlaveIsIn ); 24.1374 + } 24.1375 + 24.1376 + 24.1377 +/*Initialize semantic data struct.. this initializer doesn't need any input, 24.1378 + * but some languages may need something from inside the request that was sent 24.1379 + * to create a slave.. in that case, just make initializer do the malloc then 24.1380 + * use the PR_PI__give_lang_data inside the create handler, and fill in the 24.1381 + * langData values there. 24.1382 + */ 24.1383 +void * 24.1384 +PRServ__create_lang_data_in_slave( SlaveVP *slave ) 24.1385 + { PRServLangData *langData; 24.1386 + 24.1387 + 24.1388 + langData = PR_PI__create_lang_data_in_slave( sizeof(PRServLangData), 24.1389 + &PRServ__free_lang_data, slave, PRServ_MAGIC_NUMBER ); 24.1390 + 24.1391 + langData->highestTransEntered = -1; 24.1392 + langData->lastTransEntered = NULL; 24.1393 + return langData; 24.1394 + } 24.1395 + 24.1396 + 24.1397 +/*Register this by passing a pointer to this to PR's lang data creator Fn 24.1398 + * 24.1399 + *It deletes all the transactions that the slave had entered.. 24.1400 + *Probably a bug -- need to do something more to free blocked slaves waiting. 24.1401 + * 24.1402 + *At some point, may change PR so that it recycles langData, in which case this 24.1403 + * only gets called when a process shuts down.. at that point, PR will call 24.1404 + * dissipate on all the slaves it has in the recycle Q. 24.1405 + */ 24.1406 +void 24.1407 +PRServ__free_lang_data( void *_langData ) 24.1408 + { PRServLangData *langData; 24.1409 + PRServTransListElem *transElem, *nextTransElem; 24.1410 + 24.1411 + langData = (PRServLangData *)_langData; 24.1412 + transElem = langData->lastTransEntered; 24.1413 + 24.1414 + //Each trans the slave has entered was saved in a linked list elem inside 24.1415 + // lang data -- delete those linked list elements 24.1416 + //Bug: if this is not part of shutdown, then update state of transactions 24.1417 + // to free blocked VPs 24.1418 + while( transElem != NULL) 24.1419 + { nextTransElem = transElem->nextTrans; 24.1420 + PR_int__free( transElem ); 24.1421 + transElem = nextTransElem; 24.1422 + } 24.1423 + PR_PI__free( _langData ); 24.1424 + } 24.1425 + 24.1426 + 24.1427 +void 24.1428 +PRServ__lang_meta_task_freer( void *_langMetaTask ) 24.1429 + { //no PRServ meta tasks created, so nothing to do 24.1430 + } 24.1431 + 24.1432 + 24.1433 +/*Will be used by a langData recycler, when (and if) such a thing added 24.1434 + * to PR 24.1435 + */ 24.1436 +void 24.1437 +resetPRServLangData( void *_langData ) 24.1438 + { PRServLangData *langData = (PRServLangData *)_langData; 24.1439 + 24.1440 + langData->highestTransEntered = -1; 24.1441 + langData->lastTransEntered = NULL; 24.1442 + } 24.1443 + 24.1444 +//========================================================================== 24.1445 +// 24.1446 +// 24.1447 + 24.1448 +
25.1 --- a/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.h Tue Feb 05 20:23:27 2013 -0800 25.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.h Sat Mar 02 09:43:45 2013 -0800 25.3 @@ -1,5 +1,5 @@ 25.4 /* 25.5 - * Copyright 2009 OpenSourceStewardshipFoundation.org 25.6 + * Copyright 2009 OpenSourceResearchInstitute.org 25.7 * Licensed under GNU General Public License version 2 25.8 * 25.9 * Author: seanhalle@yahoo.com 25.10 @@ -14,46 +14,55 @@ 25.11 /*This header defines everything specific to the PRServ semantic plug-in 25.12 */ 25.13 25.14 +void 25.15 +PRServ__handleMalloc( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv); 25.16 +void 25.17 +PRServ__handleFree( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ); 25.18 + 25.19 +//============================================ 25.20 +void 25.21 +PRServ__handleStartFnSingleton( PRServLangReq *langReq, SlaveVP *reqstingSlv, 25.22 + PRServLangEnv *langEnv ); 25.23 +void 25.24 +PRServ__handleEndFnSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, 25.25 + PRServLangEnv *langEnv ); 25.26 inline void 25.27 -handleSubmitTask( PRServSemReq *semReq, PRServSemEnv *semEnv); 25.28 +PRServ__handleStartDataSingleton( PRServLangReq *langReq, SlaveVP *reqstingSlv, 25.29 + PRServLangEnv *langEnv ); 25.30 inline void 25.31 -handleEndTask( PRServSemReq *semReq, PRServSemEnv *semEnv); 25.32 -inline void 25.33 -handleSendTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv); 25.34 -inline void 25.35 -handleSendFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv); 25.36 -inline void 25.37 -handleReceiveTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv); 25.38 -inline void 25.39 -handleReceiveFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv); 25.40 -inline void 25.41 -handleTaskwait(PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv); 25.42 +PRServ__handleEndDataSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, 25.43 + PRServLangEnv *langEnv ); 25.44 +void 25.45 +PRServ__handleTransStart( PRServLangReq *langReq, SlaveVP *requestingSlv, 25.46 + PRServLangEnv *langEnv ); 25.47 +void 25.48 +PRServ__handleTransEnd(PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv*langEnv); 25.49 25.50 -inline void 25.51 -handleMalloc( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv); 25.52 -inline void 25.53 -handleFree( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ); 25.54 -inline void 25.55 -handleTransEnd(PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv*semEnv); 25.56 -inline void 25.57 -handleTransStart( PRServSemReq *semReq, SlaveVP *requestingSlv, 25.58 - PRServSemEnv *semEnv ); 25.59 -inline void 25.60 -handleAtomic( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv); 25.61 -inline void 25.62 -handleStartFnSingleton( PRServSemReq *semReq, SlaveVP *reqstingSlv, 25.63 - PRServSemEnv *semEnv ); 25.64 -inline void 25.65 -handleEndFnSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, 25.66 - PRServSemEnv *semEnv ); 25.67 -inline void 25.68 -handleStartDataSingleton( PRServSemReq *semReq, SlaveVP *reqstingSlv, 25.69 - PRServSemEnv *semEnv ); 25.70 -inline void 25.71 -handleEndDataSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, 25.72 - PRServSemEnv *semEnv ); 25.73 -inline void 25.74 -free_task_stub( PRMetaTask *stubToFree ); 25.75 +void 25.76 +PRServ__handleAtomic( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv); 25.77 +//================================== 25.78 +void 25.79 +PRServ__make_task_ready( void *taskStub, void *_langEnv ); 25.80 +void 25.81 +PRServ__resume_slave( SlaveVP *slave, void *langEnv ); 25.82 + 25.83 +void 25.84 +PRServ__handleDissipateSeed(void *langReq, SlaveVP *seedSlv, PRServLangEnv *langEnv ); 25.85 + 25.86 +void 25.87 +PRServ__handle_end_process_from_inside( void *langReq, SlaveVP *reqSlave, PRServLangEnv *langEnv ); 25.88 + 25.89 +void 25.90 +PRServ__handle_shutdown( void *_langEnv ); 25.91 + 25.92 +void * 25.93 +PRServ__create_lang_data_in_slave( SlaveVP *slave ); 25.94 + 25.95 +void 25.96 +PRServ__free_lang_data( void *_langData ); 25.97 + 25.98 +void 25.99 +PRServ__lang_meta_task_freer( void *_langMetaTask ); 25.100 25.101 25.102 #endif /* _PRServ_REQ_H */
26.1 --- a/Services_Offered_by_PR/Services_Language/PRServ_SS.c Tue Feb 05 20:23:27 2013 -0800 26.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ_SS.c Sat Mar 02 09:43:45 2013 -0800 26.3 @@ -12,8 +12,7 @@ 26.4 #include "Hash_impl/PrivateHash.h" 26.5 26.6 #include "PRServ.h" 26.7 -#include "Measurement/PRServ_Counter_Recording.h" 26.8 - 26.9 +#include "PR_impl/Services_Offered_by_PR/Measurement_and_Stats/PR_MEAS__Counter_Recording.h" 26.10 //========================================================================== 26.11 26.12 26.13 @@ -22,90 +21,69 @@ 26.14 26.15 /* 26.16 */ 26.17 -void 26.18 +PRServLangEnv * 26.19 PRServ__start( SlaveVP *seedSlv ) 26.20 - { PRServSemEnv *semEnv; 26.21 - int32 i, coreNum, slotNum; 26.22 - PRServSemData *semData; 26.23 - PRServTaskStub *threadTaskStub, *parentTaskStub; 26.24 + { PRServLangEnv *langEnv; 26.25 + int32 i; 26.26 26.27 - semEnv = PR_WL__malloc( sizeof(PRServSemEnv) ); 26.28 + langEnv = 26.29 + PR_SS__create_lang_env( sizeof(PRServLangEnv), seedSlv, PRServ_MAGIC_NUMBER); 26.30 26.31 - PR_SS__register_langlets_semEnv( semEnv, seedSlv, PRServ_MAGIC_NUMBER ); 26.32 + 26.33 + //create the ready queues 26.34 + langEnv->slavesReadyToResumeQ = makePRQ(); 26.35 + langEnv->taskReadyQ = makePRQ(); 26.36 26.37 - //seed slave is a thread slave, so make a thread's task stub for it 26.38 - // and then make another to stand for the seed's parent task. Make 26.39 - // the parent be already ended, and have one child (the seed). This 26.40 - // will make the dissipate handler do the right thing when the seed 26.41 - // is dissipated. 26.42 - threadTaskStub = create_thread_task_stub( initData ); 26.43 - parentTaskStub = create_thread_task_stub( NULL ); 26.44 - parentTaskStub->isEnded = TRUE; 26.45 - parentTaskStub->numLiveChildThreads = 1; //so dissipate works for seed 26.46 - threadTaskStub->parentTaskStub = parentTaskStub; 26.47 - 26.48 - PR_SS__set_langMetaTask_for_seedSlv( threadTaskStub, seedSlv ); 26.49 - 26.50 - //Hook up the semantic layer's plug-ins to the Master virt procr 26.51 - PR_SS__register_create_task_handler( &createTaskHandler, seedVP, PRServ_MAGIC_NUMBER ); 26.52 - PR_SS__register_end_task_handler( &endTaskHandler, seedVP, PRServ_MAGIC_NUMBER ); 26.53 - PR_SS__register_create_slave_handler( &createThreadHandler, seedVP, PRServ_MAGIC_NUMBER ); 26.54 - PR_SS__register_dissipate_slave_handler( &endThreadHandler, seedVP, PRServ_MAGIC_NUMBER ); 26.55 - PR_SS__register_request_handler( &PRServ__Request_Handler, seedVP, PRServ_MAGIC_NUMBER ); 26.56 - PR_SS__register_assigner( &PRServ__assign_work_to_slot, seedVP, PRServ_MAGIC_NUMBER ); 26.57 - RequestHandler createInitialSemDataFn; 26.58 - RequestHandler resetSemDataFn; 26.59 - 26.60 + //register the langlet's handlers with PR 26.61 + PR_SS__register_assigner( &PRServ__assign_work_to_slot, seedSlv, PRServ_MAGIC_NUMBER ); 26.62 + PR_SS__register_lang_shutdown_handler( &PRServ__handle_shutdown, seedSlv, PRServ_MAGIC_NUMBER ); 26.63 + PR_SS__register_lang_data_creator( &PRServ__create_lang_data_in_slave, seedSlv, PRServ_MAGIC_NUMBER ); 26.64 +// PR_SS__register_lang_meta_task_creator( &PRServ__create_empty_lang_meta_task_in_slave, seedSlv, PRServ_MAGIC_NUMBER ); 26.65 + PR_SS__register_make_slave_ready_fn( &PRServ__resume_slave, seedSlv, PRServ_MAGIC_NUMBER ); 26.66 + PR_SS__register_make_task_ready_fn( &PRServ__make_task_ready, seedSlv, PRServ_MAGIC_NUMBER ); 26.67 + 26.68 #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 26.69 - _PRTopEnv->counterHandler = &PRServ__counter_handler; 26.70 - PRServ__init_counter_data_structs(); 26.71 + _PRTopEnv->counterHandler = &PR_MEAS__counter_handler; 26.72 + PR_MEAS__init_counter_data_structs_for_lang( seedSlv, PRServ_MAGIC_NUMBER ); 26.73 #endif 26.74 26.75 - 26.76 - //create the ready queues, hash tables used for matching and so forth 26.77 - semEnv->slavesReadyToResumeQ = makePRQ(); 26.78 - semEnv->taskReadyQ = makePRQ(); 26.79 26.80 - semEnv->argPtrHashTbl = makeHashTable32( 16, &PR_int__free ); 26.81 - semEnv->commHashTbl = makeHashTable32( 16, &PR_int__free ); 26.82 - 26.83 - semEnv->nextCoreToGetNewSlv = 0; 26.84 - 26.85 - 26.86 //TODO: bug -- turn these arrays into dyn arrays to eliminate limit 26.87 - //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); 26.88 - //semanticEnv->transactionStrucs = makeDynArrayInfo( ); 26.89 - for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) 26.90 + //langEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); 26.91 + //langEnv->transactionStrucs = makeDynArrayInfo( ); 26.92 + for( i = 0; i < NUM_STRUCS_IN_LANG_ENV; i++ ) 26.93 { 26.94 - semEnv->fnSingletons[i].endInstrAddr = NULL; 26.95 - semEnv->fnSingletons[i].hasBeenStarted = FALSE; 26.96 - semEnv->fnSingletons[i].hasFinished = FALSE; 26.97 - semEnv->fnSingletons[i].waitQ = makePRQ(); 26.98 - semEnv->transactionStrucs[i].waitingVPQ = makePRQ(); 26.99 + langEnv->fnSingletons[i].endInstrAddr = NULL; 26.100 + langEnv->fnSingletons[i].hasBeenStarted = FALSE; 26.101 + langEnv->fnSingletons[i].hasFinished = FALSE; 26.102 + langEnv->fnSingletons[i].waitQ = makePRQ(); 26.103 + langEnv->transactionStrucs[i].waitingVPQ = makePRQ(); 26.104 } 26.105 26.106 26.107 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 26.108 - semEnv->unitList = makeListOfArrays(sizeof(Unit),128); 26.109 - semEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); 26.110 - semEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); 26.111 - semEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); 26.112 - semEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semEnv->ntonGroups),8); 26.113 + langEnv->unitList = makeListOfArrays(sizeof(Unit),128); 26.114 + langEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); 26.115 + langEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); 26.116 + langEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); 26.117 + langEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(langEnv->ntonGroups),8); 26.118 26.119 - semEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); 26.120 - memset(semEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); 26.121 + langEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); 26.122 + memset(langEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); 26.123 #endif 26.124 + 26.125 + return langEnv; 26.126 } 26.127 26.128 26.129 -/*Frees any memory allocated by PRServ__init() then calls PR_int__shutdown 26.130 +/*This shuts down the langlet 26.131 + * Frees any memory allocated by PRServ__init() and deletes any slaves or tasks 26.132 + * still in ready Qs. 26.133 */ 26.134 void 26.135 -PRServ__cleanup_after_shutdown() 26.136 - { PRServSemEnv *semanticEnv; 26.137 +PRServ__handle_shutdown( void *_langEnv ) 26.138 + { PRServLangEnv *langEnv = (PRServLangEnv *)_langEnv; 26.139 26.140 - semanticEnv = _PRTopEnv->semanticEnv; 26.141 - 26.142 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 26.143 //UCC 26.144 FILE* output; 26.145 @@ -131,10 +109,10 @@ 26.146 //set_dot_file(output); 26.147 //FIXME: first line still depends on counters being enabled, replace w/ unit struct! 26.148 //forAllInDynArrayDo(_PRTopEnv->counter_history_array_info, &print_dot_node_info ); 26.149 - forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file); 26.150 - forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); 26.151 - forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); 26.152 - forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file); 26.153 + forAllInListOfArraysDo(langEnv->unitList, &print_unit_to_file); 26.154 + forAllInListOfArraysDo( langEnv->commDependenciesList, &print_comm_dependency_to_file ); 26.155 + forAllInListOfArraysDo( langEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); 26.156 + forAllInDynArrayDo(langEnv->ntonGroupsInfo,&print_nton_to_file); 26.157 //fprintf(output,"}\n"); 26.158 fflush(output); 26.159 26.160 @@ -164,11 +142,11 @@ 26.161 //set_dot_file(output); 26.162 //FIXME: first line still depends on counters being enabled, replace w/ unit struct! 26.163 //forAllInDynArrayDo(_PRTopEnv->counter_history_array_info, &print_dot_node_info ); 26.164 - forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file ); 26.165 - forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); 26.166 - forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); 26.167 - forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file ); 26.168 - forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file ); 26.169 + forAllInListOfArraysDo( langEnv->unitList, &print_unit_to_file ); 26.170 + forAllInListOfArraysDo( langEnv->commDependenciesList, &print_comm_dependency_to_file ); 26.171 + forAllInListOfArraysDo( langEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); 26.172 + forAllInListOfArraysDo( langEnv->dynDependenciesList, &print_dyn_dependency_to_file ); 26.173 + forAllInListOfArraysDo( langEnv->hwArcs, &print_hw_dependency_to_file ); 26.174 //fprintf(output,"}\n"); 26.175 fflush(output); 26.176 26.177 @@ -179,10 +157,10 @@ 26.178 } 26.179 26.180 26.181 - freeListOfArrays(semanticEnv->unitList); 26.182 - freeListOfArrays(semanticEnv->commDependenciesList); 26.183 - freeListOfArrays(semanticEnv->ctlDependenciesList); 26.184 - freeListOfArrays(semanticEnv->dynDependenciesList); 26.185 + freeListOfArrays(langEnv->unitList); 26.186 + freeListOfArrays(langEnv->commDependenciesList); 26.187 + freeListOfArrays(langEnv->ctlDependenciesList); 26.188 + freeListOfArrays(langEnv->dynDependenciesList); 26.189 26.190 #endif 26.191 #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 26.192 @@ -201,12 +179,13 @@ 26.193 printf("Saving Counter measurements to File: %s ...\n", filename); 26.194 output = fopen(filename,"w+"); 26.195 if(output!=NULL){ 26.196 + int i; 26.197 set_counter_file(output); 26.198 - int i; 26.199 - for(i=0;i<NUM_CORES;i++){ 26.200 - forAllInListOfArraysDo( semanticEnv->counterList[i], &print_counter_events_to_file ); 26.201 - fflush(output); 26.202 - } 26.203 + for(i=0;i<NUM_CORES;i++) 26.204 + { 26.205 + forAllInListOfArraysDo( langEnv->counterList[i], &PR_MEAS__print_counter_event_to_file ); 26.206 + fflush(output); 26.207 + } 26.208 26.209 } else 26.210 printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); 26.211 @@ -215,21 +194,39 @@ 26.212 } 26.213 26.214 #endif 26.215 -/* It's all allocated inside PR's big chunk -- that's about to be freed, so 26.216 - * nothing to do here 26.217 26.218 - 26.219 - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 26.220 + //Things to free: 26.221 + // tasks and slaves in ready Qs 26.222 + // ready Qs 26.223 + // tasks and slaves in the comm hash table 26.224 + // comm hash table 26.225 + // tasks in the argPtrHashTbl 26.226 + // the argPtrHashTbl 26.227 + PrivQueueStruc *queue; 26.228 + SlaveVP *slave; 26.229 + 26.230 + //dissipate any slaves still in the readyQ, because this is last lang 26.231 + queue = langEnv->slavesReadyToResumeQ; 26.232 + slave = readPrivQ( queue ); 26.233 + while( slave != NULL ) 26.234 + { 26.235 + PR_int__recycle_slaveVP( slave ); //recycler is for all of PR 26.236 + slave = readPrivQ( queue ); 26.237 + } 26.238 + freePrivQ( queue ); 26.239 + 26.240 + //no any tasks in the readyQ 26.241 + queue = langEnv->taskReadyQ; 26.242 + freePrivQ( queue ); 26.243 + 26.244 + int32 i; 26.245 + for( i = 0; i < NUM_STRUCS_IN_LANG_ENV; i++ ) 26.246 { 26.247 - PR_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); 26.248 - PR_int__free( semanticEnv->readyVPQs[coreIdx] ); 26.249 + freePrivQ( langEnv->fnSingletons[i].waitQ ); 26.250 + freePrivQ( langEnv->transactionStrucs[i].waitingVPQ ); 26.251 } 26.252 - PR_int__free( semanticEnv->readyVPQs ); 26.253 26.254 - freeHashTable( semanticEnv->commHashTbl ); 26.255 - PR_int__free( _PRTopEnv->semanticEnv ); 26.256 - */ 26.257 - PR_SS__cleanup_at_end_of_shutdown(); 26.258 + PR_int__remove_lang_env_from_process_and_free( langEnv ); 26.259 } 26.260 26.261
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/Services_Offered_by_PR/Services_Language/PRServ_singleton_asm.s Sat Mar 02 09:43:45 2013 -0800 27.3 @@ -0,0 +1,21 @@ 27.4 + 27.5 +//Assembly code takes the return addr off the stack and saves 27.6 +// into the singleton. The first field in the singleton is the 27.7 +// "endInstrAddr" field, and the return addr is at 0x4(%ebp) 27.8 +.globl asm_save_ret_to_singleton 27.9 +asm_save_ret_to_singleton: 27.10 + movq 0x8(%rbp), %rax #get ret address, ebp is the same as in the calling function 27.11 + movq %rax, (%rdi) #write ret addr to endInstrAddr field 27.12 + ret 27.13 + 27.14 + 27.15 +//Assembly code changes the return addr on the stack to the one 27.16 +// saved into the singleton by the end-singleton-fn 27.17 +//The stack's return addr is at 0x4(%%ebp) 27.18 +.globl asm_write_ret_from_singleton 27.19 +asm_write_ret_from_singleton: 27.20 + movq (%rdi), %rax #get endInstrAddr field 27.21 + movq %rax, 0x8(%rbp) #write return addr to the stack of the caller 27.22 + ret 27.23 + 27.24 +