# HG changeset patch # User Sean Halle # Date 1362246225 28800 # Node ID 40e7625e57bda24f7c3ad72f73f5d96ecaaa8dd3 # Parent bc5030385120bb7a7ddb517edea4ed3ce4166824 Compiles and runs, up to end of process, working on end process and shutdown diff -r bc5030385120 -r 40e7625e57bd AnimationMaster.c --- a/AnimationMaster.c Tue Feb 05 20:23:27 2013 -0800 +++ b/AnimationMaster.c Sat Mar 02 09:43:45 2013 -0800 @@ -12,23 +12,30 @@ #include "PR.h" #include "VSs_impl/VSs.h" -/* -void PRHandle_CreateTask_SL(SlaveVP *slave); +//========================= Local Declarations ======================== +inline PRProcess * +pickAProcess( AnimSlot *slot ); +inline bool32 +assignWork( PRProcess *process, AnimSlot *slot ); -void PRHandle_CreateSlave_SL(SlaveVP *slave); -void PRHandle_Dissipate_SL(SlaveVP *slave); -void PR_int__handle_PRServiceReq_SL(SlaveVP *slave); -*/ -inline void PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); -inline void PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); -inline void PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); -void PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); +inline void +PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); +inline void +PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); +inline void +PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); +inline void +PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); +inline void +PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ); -//inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot ); -inline PRProcess * pickAProcess( AnimSlot *slot ); -inline bool32 assignWork( PRProcess *process, AnimSlot *slot ); +inline void +handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); +inline void +handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); +//=========================================================================== /*Note: there used to be a coreController that was another animation * layer below both the masterVP and the slaveVPs.. in that case, the @@ -59,7 +66,7 @@ PRLangEnv *langEnv; PRReqst *req; PRProcess *process; - bool32 foundWork; + bool32 didAssignWork; //Check if newly-done slave in slot, which will need request handled //NOTE: left over from when had a coreController & MasterVP managed @@ -67,53 +74,58 @@ if( slot->workIsDone ) { slot->workIsDone = FALSE; slot->needsWorkAssigned = TRUE; + + //An Idle VP has no request to handle, so skip to assign.. + if( slot->slaveAssignedToSlot->typeOfVP != IdleVP ) + { + HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot + MEAS__startReqHdlr; - HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot - MEAS__startReqHdlr; + //process the request made by the slave (held inside slave struc) + slave = slot->slaveAssignedToSlot; + req = slave->request; - //process the request made by the slave (held inside slave struc) - slave = slot->slaveAssignedToSlot; - req = slave->request; + //If the requesting slave is a slot slave, and request is not + // task-end, then turn it into a free task slave & continue + if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) + PR_int__replace_with_new_slot_slv( slave ); - //If the requesting slave is a slot slave, and request is not - // task-end, then turn it into a free task slave. - if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) - PR_int__replace_with_new_slot_slv( slave ); - - //Handle task create and end first -- they're special cases.. - switch( req->reqType ) - { case TaskEnd: - { //do PR handler, which calls lang's hdlr and does recycle of - // free task slave if needed -- PR handler checks for free task Slv - PRHandle__EndTask( req, slave ); break; + //Handle task create and end first -- they're special cases.. + switch( req->reqType ) + { case TaskEnd: + { //do PR handler, which calls lang's hdlr and does recycle of + // free task slave if needed -- PR handler checks for free task Slv + PRHandle__EndTask( req, slave ); break; + } + case TaskCreate: + { //Do PR's create-task handler, which calls the lang's hdlr + // PR handler checks for free task Slv + PRHandle__CreateTask( req, slave ); break; + } + case SlvCreate: PRHandle__CreateSlave( req, slave ); break; + case SlvDissipate: PRHandle__EndSlave( req, slave ); break; + case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env + case Hardware: //for future expansion + case IO: //for future expansion + case OSCall: //for future expansion + PR_int__throw_exception("Not implemented", slave, NULL); break; + case LangShutdown: PRHandle__LangShutdown( req, slave ); break; + case Language: //normal lang request + { magicNumber = req->langMagicNumber; + langEnv = PR_PI__give_lang_env_for_slave( slave, magicNumber ); + (*req->handler)( req->langReq, slave, langEnv ); + } } - case TaskCreate: - { //Do PR's create-task handler, which calls the lang's hdlr - // PR handler checks for free task Slv - PRHandle__CreateTask( req, slave ); break; - } - case SlvCreate: PRHandle__CreateSlave( req, slave ); break; - case SlvDissipate: PRHandle__EndSlave( req, slave ); break; - case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env - case Hardware: //for future expansion - case IO: //for future expansion - case OSCall: //for future expansion - PR_int__throw_exception("Not implemented", slave, NULL); break; - case Language: //normal lang request - { magicNumber = req->langMagicNumber; - langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); - (*req->handler)( req->langReq, slave, langEnv ); - } - } - + MEAS__endReqHdlr; HOLISTIC__Record_AppResponder_end; + }//if not idleVP } //if have request to be handled //NOTE: IF statement is leftover from when master managed many slots - foundWork = FALSE; - if( slot->needsWorkAssigned ) //can probably remove IF, not that only one slot + didAssignWork = FALSE; + if( slot->needsWorkAssigned ) //can probably remove IF, now that only one slot { HOLISTIC__Record_Assigner_start; @@ -122,15 +134,19 @@ //Scan lang environs, looking for langEnv with ready work. // call the Assigner for that lang Env, to get a slave for the slot - foundWork = - assignWork( process, slot ); - + if( process != NULL ) + { didAssignWork = + assignWork( process, slot ); + } HOLISTIC__Record_Assigner_end; -// fixme; //make this a while loop that tries a different process if this one fails + if( !didAssignWork ) //if no work assigned, be sure idle slave is in slot + { slot->slaveAssignedToSlot = _PRTopEnv->idleSlv[slot->coreSlotIsOn][0]; + } +// fixme; //make into a loop that tries more processes if fails to assign }//if slot needs slave assigned - return foundWork; + return didAssignWork; } /*When several processes exist, use some pattern for picking one to give @@ -201,19 +217,19 @@ } //If here, then no override assigner, so search language envs for work - int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv; - langEnvsList = process->langEnvsList; + int32 envIdx, numEnvs; PRLangEnv **protoLangEnvsList, *protoLangEnv; + protoLangEnvsList = process->protoLangEnvsList; numEnvs = process->numLangEnvs; for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array - { langEnv = langEnvsList[envIdx]; - if( langEnv->numReadyWork > 0 ) + { protoLangEnv = protoLangEnvsList[envIdx]; + if( protoLangEnv->numReadyWork > 0 ) { bool32 didAssignWork = - (*langEnv->workAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot + (*protoLangEnv->workAssigner)( PR_int__give_lang_env(protoLangEnv), slot ); //assigner calls PR to put slave/task into slot if(didAssignWork) - { langEnv->numReadyWork -= 1; - if( langEnv->numReadyWork == 0 ) + { protoLangEnv->numReadyWork -= 1; + if( protoLangEnv->numReadyWork == 0 ) { process->numEnvsWithWork -= 1; } goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work @@ -260,6 +276,124 @@ } +//================================= +//=== +//= +/*Create task is a special form, that has PR behavior in addition to plugin + * behavior. Master calls this first, and it then calls the plugin's + * create task handler. + * + *Note: the requesting slave must be either generic slave or free task slave + */ +inline +void +PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) + { PRMetaTask *protoMetaTask; + PRProcess *process; + PRLangEnv *protoLangEnv; + void *task; + + process = slave->processSlaveIsIn; + + protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, + req->langMagicNumber ); + + //Do the langlet's create-task handler, which keeps the task + // inside the langlet's lang env, but returns the langMetaTask + // so that PR can then put stuff into the prolog + //typedef void * (*CreateHandler)( void *, SlaveVP *, void * ); //req, slv, langEnv + // + task = + (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( task ); + protoMetaTask->ID = req->ID; //may be NULL + protoMetaTask->topLevelFn = req->topLevelFn; + protoMetaTask->initData = req->initData; + protoMetaTask->processTaskIsIn = process; + + process->numLiveTasks += 1; + protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead + + return; + } + +/*When a task ends, have two scenarios: 1) task ran to completion, or 2) task + * has been suspended at some point in its code. + *For 1, just decr count of live tasks (and check for end condition) -- the + * master loop will decide what goes into the slot freed up by this task end, + * so, here, don't worry about assigning a new task to the slot slave. + *For 2, the task's slot slave has been converted to a free task slave, which + * now has nothing more to do, so send it to the recycle Q (which includes + * freeing all the langData and meta task structs alloc'd for it). Then + * decrement the live task count and check end condition. + * + *PR has to update count of live tasks, and check end of process condition. + * The "main" can invoke constructs that wait for a process to end, so when + * end detected, have to resume what's waiting.. + *Thing is, that wait involves the main OS thread. That means + * PR internals have to do OS thread signaling. Want to do that in the + * core controller, which has the original stack of an OS thread. So the + * end process handling happens in the core controller. + * + *So here, when detect process end, signal to the core controller, which will + * then do the condition variable notify to the OS thread that's waiting. + * + *Note: slave may be either a slot slave or a free task slave. + */ +inline +void +PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) + { void *langEnv; + PRLangEnv *protoLangEnv; + PRProcess *process; + void *langMetaTask; + + process = requestingSlv->processSlaveIsIn; + langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req + protoLangEnv = PR_int__give_proto_lang_env( langEnv ); + + langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); + + //Do the langlet's request handler + //Want to keep PR structs hidden from plugin, so extract langReq.. + //This is supposed to free any langlet-malloc'd mem, including meta task + (*req->handler)( req->langReq, requestingSlv, langEnv ); + + protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead + if( protoLangEnv->numLiveWork == 0 && + numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) + { SlaveVP * + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); + //can't resume into langlet that just ended its last work! + // and don't have env that the waiter was created in, so resume + // into PRServ env.. + void * + resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); + while( waitingSlave != NULL ) + { //resume a slave that was waiting for work in this env to finish + PR_PI__make_slave_ready( waitingSlave, resumeEnv ); + //get next waiting slave, repeat.. + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); + } + } + + + //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv + if( requestingSlv->typeOfVP == FreeTaskSlv ) + PR_int__recycle_slaveVP( requestingSlv ); //Doesn't decr num live slaves + + process->numLiveTasks -= 1; + //NOTE: end-task is unrelated to work available (just in case wondering) + + //check End Of Process Condition + if( process->numLiveTasks == 0 && + process->numLiveGenericSlvs == 0 ) + { //Tell the core controller to do wakeup of any waiting OS thread + PR_SS__end_process_normally( process ); + } + } + + /*This is first thing called when creating a slave.. it hands off to the * langlet's creator, then adds updates of its own.. @@ -293,7 +427,7 @@ PRLangEnv *protoLangEnv; process = slave->processSlaveIsIn; - protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber ); + protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, req->langMagicNumber ); //create handler, or a future request handler will call PR_PI__make_slave_ready // which will in turn handle updating which langlets and which processes have @@ -306,6 +440,7 @@ newSlv->processSlaveIsIn = process; newSlv->ID = req->ID; process->numLiveGenericSlvs += 1; //not same as work ready! + protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead } /*The dissipate handler has to, update the number of slaves of the type, within @@ -327,105 +462,60 @@ process = slave->processSlaveIsIn; //do the language's dissipate handler - protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber ); + protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, slave->request->langMagicNumber ); if(req->handler != NULL) (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); + protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead + if( protoLangEnv->numLiveWork == 0 && + numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) + { SlaveVP * + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); + //can't resume into langlet that just ended its last work! + // and don't have env that the waiter was created in, so resume + // into PRServ env.. + void * + resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); + while( waitingSlave != NULL ) + { //resume a slave that was waiting for work in this env to finish + PR_PI__make_slave_ready( waitingSlave, resumeEnv ); + //get next waiting slave, repeat.. + waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); + } + } + process->numLiveGenericSlvs -= 1; - PR_int__recycle_slave( slave ); + PR_int__recycle_slaveVP( slave ); //NOTE: dissipate is unrelated to work available (just in case wondering) //check End Of Process Condition if( process->numLiveTasks == 0 && process->numLiveGenericSlvs == 0 ) - PR_SS__shutdown_process( process ); + PR_SS__end_process_normally( process ); } -/*Create task is a special form, that has PR behavior in addition to plugin - * behavior. Master calls this first, and it then calls the plugin's - * create task handler. - * - *Note: the requesting slave must be either generic slave or free task slave +//======================= +//=== +//= +/*Langlet shutdown triggers this, which calls the registered shutdown + * handler for the langlet, and removes the lang's env from the process */ inline void -PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) - { PRMetaTask *metaTask; - PRProcess *process; - PRLangEnv *protoLangEnv; - void *task; - - process = slave->processSlaveIsIn; +PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ) + { void *langEnv; + PRLangEnv *protoLangEnv; + PRProcess *process; - protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, - req->langMagicNumber ); + process = requestingSlv->processSlaveIsIn; + protoLangEnv = PR_int__give_proto_lang_env_from_process( process, req->langMagicNumber ); + langEnv = PR_int__give_lang_env( protoLangEnv ); - //Do the langlet's create-task handler, which keeps the task - // inside the langlet's lang env, but returns the langMetaTask - // so PR can put stuff into the prolog - task = - (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); - metaTask = PR_int__give_prolog_of_task( task ); - metaTask->ID = req->ID; //may be NULL - metaTask->topLevelFn = req->topLevelFn; - metaTask->initData = req->initData; - - process->numLiveTasks += 1; - - return; - } - -/*When a task ends, have two scenarios: 1) task ran to completion, or 2) task - * has been suspended at some point in its code. - *For 1, just decr count of live tasks (and check for end condition) -- the - * master loop will decide what goes into the slot freed up by this task end, - * so, here, don't worry about assigning a new task to the slot slave. - *For 2, the task's slot slave has been converted to a free task slave, which - * now has nothing more to do, so send it to the recycle Q (which includes - * freeing all the langData and meta task structs alloc'd for it). Then - * decrement the live task count and check end condition. - * - *PR has to update count of live tasks, and check end of process condition. - * The "main" can invoke constructs that wait for a process to end, so when - * end detected, have to resume what's waiting.. - *Thing is, that wait involves the main OS thread. That means - * PR internals have to do OS thread signaling. Want to do that in the - * core controller, which has the original stack of an OS thread. So the - * end process handling happens in the core controller. - * - *So here, when detect process end, signal to the core controller, which will - * then do the condition variable notify to the OS thread that's waiting. - * - *Note: slave may be either a slot slave or a free task slave. - */ -inline -void -PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) - { void *langEnv; - PRProcess *process; - void *langMetaTask; + //call the langlet's registered handler + (*protoLangEnv->shutdownHdlr)( langEnv ); - langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req - langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); - - //Do the langlet's request handler - //Want to keep PR structs hidden from plugin, so extract langReq.. - (*req->handler)( req->langReq, requestingSlv, langEnv ); - - //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv - if( requestingSlv->typeOfVP == FreeTaskSlv ) - PR_int__recycle_slave( requestingSlv ); //Doesn't decr num live slaves - - process->numLiveTasks -= 1; - //NOTE: end-task is unrelated to work available (just in case wondering) - - //check End Of Process Condition - if( process->numLiveTasks == 0 && - process->numLiveGenericSlvs == 0 ) - { //Tell the core controller to do wakeup of any waiting OS thread - PR_SS__shutdown_process( process ); - } + PR_int__remove_lang_env_from_process_and_free( langEnv ); //removes from process and frees } @@ -438,24 +528,58 @@ */ void inline PRHandle__ServiceReq( SlaveVP *requestingSlv ) - { PRReqst *req; - PRServReq *langReq; - void *langEnv; - int32 magicNumber; + { PRReqst *req; + PRServiceReq *langReq; + PRLangEnv *protoLangEnv; + int32 magicNumber; req = requestingSlv->request; magicNumber = req->langMagicNumber; - langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); + protoLangEnv = PR_int__give_proto_lang_env_for_slave( requestingSlv, magicNumber ); langReq = PR_PI__take_lang_reqst_from(req); if( langReq == NULL ) return; switch( langReq->reqType ) //lang handlers are all in other file { - case make_probe: handleMakeProbe( langReq, langEnv ); + case make_probe: handleMakeProbe( langReq, protoLangEnv ); break; - case throw_excp: handleThrowException( langReq, langEnv ); + case throw_excp: handleThrowException( langReq, protoLangEnv ); break; } } + + +/*These handlers are special -- they don't belong to a language, because they + * deal with things internal to PR, so put them here.. + */ +inline +void +handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) + { IntervalProbe *newProbe; + + newProbe = PR_int__malloc( sizeof(IntervalProbe) ); + newProbe->nameStr = PR_int__strDup( langReq->nameStr ); + newProbe->hist = NULL; + newProbe->schedChoiceWasRecorded = FALSE; + + //This runs in masterVP, so no race-condition worries + //BUG: move to process + newProbe->probeID = + addToDynArray( newProbe, _PRTopEnv->dynIntervalProbesInfo ); + + langReq->requestingSlv->dataRetFromReq = newProbe; + + (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); + } + +inline +void +handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) + { + PR_int__throw_exception( langReq->msgStr, langReq->requestingSlv, langReq->exceptionData ); + + (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); + } + diff -r bc5030385120 -r 40e7625e57bd CoreController.c --- a/CoreController.c Tue Feb 05 20:23:27 2013 -0800 +++ b/CoreController.c Sat Mar 02 09:43:45 2013 -0800 @@ -74,7 +74,7 @@ bool32 foundWork; AnimSlot *animSlot; volatile int32 *addrOfMasterLock; //thing pointed to is volatile, not ptr - SlaveVP *thisCoresMasterVP; +// SlaveVP *thisCoresMasterVP; //Variables used for pthread related things ThdParams *thisCoresThdParams; cpu_set_t coreMask; //used during pinning pthread to CPU core @@ -95,9 +95,11 @@ //TODO: DEBUG: check get correct pointer here animSlot = _PRTopEnv->allAnimSlots[ thisCoresIdx ][0]; + animSlot->slaveAssignedToSlot = _PRTopEnv->idleSlv[thisCoresIdx][ZERO]; + numRepetitionsWithNoWork = 0; addrOfMasterLock = &(_PRTopEnv->masterLock); - thisCoresMasterVP = _PRTopEnv->masterVPs[ thisCoresIdx ]; +// thisCoresMasterVP = _PRTopEnv->masterVPs[ thisCoresIdx ]; //==================== pthread related stuff ====================== //pin the pthread to the core -- takes away Linux control @@ -135,7 +137,7 @@ //Alternatively, the VP suspend primitive could just not bother // returning from switchToSlv, and instead jmp directly to here. - if(animSlot->slaveAssignedToSlot->typeOfVP == Idle) + if(animSlot->slaveAssignedToSlot->typeOfVP == IdleVP) { //The Holistic stuff turns on idle slaves.. but can also be in mode // where have no idle slaves.. so, this IF statement can only be true // executed when HOLISTIC is turned on.. @@ -212,7 +214,7 @@ terminateCoreCtlr(SlaveVP *currSlv) { //first, free shutdown Slv that jumped here, then end the pthread - PR_int__dissipate_slaveVP__SL( currSlv ); + PR_int__recycle_slaveVP( currSlv ); pthread_exit( NULL ); } @@ -275,60 +277,141 @@ */ void * coreCtlr_Seq( void *paramsIn ) - { + { int32 thisCoresIdx; int32 numRepetitionsWithNoWork; - SlaveVP *currVP; - AnimSlot *currSlot, **animSlots; - int32 currSlotIdx; - int32 *addrOfMasterLock; - SlaveVP *thisCoresMasterVP; + bool32 foundWork; + AnimSlot *animSlot; + volatile int32 *addrOfMasterLock; //thing pointed to is volatile, not ptr + //Variables used for pthread related things + ThdParams *thisCoresThdParams; + cpu_set_t coreMask; //used during pinning pthread to CPU core + int32 errorCode; + //Variables used during measurements (inside macro!) + TSCountLowHigh endSusp; + //Variables used in random-backoff, for master-lock and waiting for work + uint32_t seed1 = rand()%1000; // init random number generator for backoffs + uint32_t seed2 = rand()%1000; + //=============== Initializations =================== - thisCoresIdx = 0; //sequential version - animSlots = _PRTopEnv->allAnimSlots[thisCoresIdx]; - currSlotIdx = 0; //start at slot 0, go up until one empty, then do master +// thisCoresThdParams = (ThdParams *)paramsIn; +// thisCoresIdx = thisCoresThdParams->coreNum; + thisCoresIdx = 0; + + //Assembly that saves addr of label of return instr -- addr used in assmbly + recordCoreCtlrReturnLabelAddr((void**)&(_PRTopEnv->coreCtlrReturnPt)); + + //TODO: DEBUG: check get correct pointer here + animSlot = _PRTopEnv->allAnimSlots[ thisCoresIdx ][0]; + animSlot->slaveAssignedToSlot = _PRTopEnv->idleSlv[thisCoresIdx][ZERO]; + numRepetitionsWithNoWork = 0; addrOfMasterLock = &(_PRTopEnv->masterLock); - thisCoresMasterVP = _PRTopEnv->masterVPs[thisCoresIdx]; - //Assembly that saves addr of label of return instr -- label in assmbly - recordCoreCtlrReturnLabelAddr((void**)&(_PRTopEnv->coreCtlrReturnPt)); + //==================== pthread related stuff ====================== + //pin the pthread to the core -- takes away Linux control + //Linux requires pinning to be done inside the thread-function + //Designate a core by a 1 in bit-position corresponding to the core +/* + CPU_ZERO(&coreMask); //initialize mask bits to zero + CPU_SET(thisCoresThdParams->coreNum,&coreMask); //set bit repr the coreNum + pthread_t selfThd = pthread_self(); + errorCode = + pthread_setaffinity_np( selfThd, sizeof(coreMask), &coreMask); + if(errorCode){ printf("\n pinning thd to core failed \n"); exit(0); } + //make sure the controllers all start at same time, by making them wait + pthread_mutex_lock( &suspendLock ); + while( !(_PRTopEnv->firstProcessReady) ) + { pthread_cond_wait( &suspendCond, &suspendLock ); + } + pthread_mutex_unlock( &suspendLock ); + HOLISTIC__CoreCtrl_Setup; + + DEBUG__printf1(TRUE, "started coreCtrlr", thisCoresIdx ); + */ //====================== The Core Controller ====================== - while(1) - { - if( currSlotIdx >= NUM_ANIM_SLOTS ) goto switchToMaster; - currSlot = animSlots[ currSlotIdx ]; + while(1) + { //Assembly code switches the core between animating a VP and + // animating this core controller. The switch is done by + // changing the stack-pointer and frame-pointer and then doing + // an assembly jmp. When reading this code, the effect is + // that the "switchToSlv()" at the end of the loop is sort of a + // "warp in time" -- the core disappears inside this, jmps to + // animating a VP, and when that VP suspends, the suspend + // jmps back. This has the effect of "returning" from the + // switchToSlv() call. Then control loops back to here. + //Alternatively, the VP suspend primitive could just not bother + // returning from switchToSlv, and instead jmp directly to here. + //core controller top of loop + if(animSlot->slaveAssignedToSlot->typeOfVP == IdleVP) + { //The Holistic stuff turns on idle slaves.. but can also be in mode + // where have no idle slaves.. so, this IF statement can only be true + // executed when HOLISTIC is turned on.. + numRepetitionsWithNoWork ++; + HOLISTIC__Record_last_work; + } + - if( ! currSlot->needsSlaveAssigned ) //slot does have slave assigned - { numRepetitionsWithNoWork = 0; //reset B2B master count - currSlotIdx ++; - currVP = currSlot->slaveAssignedToSlot; - } - else //slot is empty, so switch to master - { - switchToMaster: - currSlotIdx = 0; //doing switch to master, so start over at slot 0 + + HOLISTIC__Record_AppResponderInvocation_start; + MEAS__Capture_Pre_Master_Lock_Point; + + int numTriesToGetLock = 0; int gotLock = 0; + while( gotLock == FALSE ) //keep going until get master lock + { + //want to + // reduce lock contention from cores with no work, so first + // check if this is a core with no work, and busy wait if so. + //Then, if it's been way too long without work, yield pthread + if( numRepetitionsWithNoWork > NUM_REPS_W_NO_WORK_BEFORE_BACKOFF) + doBackoff_for_TooLongWithNoWork( numRepetitionsWithNoWork, &seed1, &seed2 ); + if( numRepetitionsWithNoWork > NUM_REPS_W_NO_WORK_BEFORE_YIELD ) + { numRepetitionsWithNoWork = 0; pthread_yield(); } + + + //Try to get the lock + gotLock = __sync_bool_compare_and_swap( addrOfMasterLock, + UNLOCKED, LOCKED ); + if( gotLock ) + { //At this point, have successfully gotten master lock. + //So, break out of get-lock loop. + break; + } + //Get here only when failed to get lock -- check in should do backoff + + numTriesToGetLock++; //if too many, means too much contention + if( numTriesToGetLock > NUM_TRIES_BEFORE_DO_BACKOFF ) + doBackoff_for_TooLongToGetLock( numTriesToGetLock, &seed1, &seed2 ); + if( numTriesToGetLock > MASTERLOCK_RETRIES_BEFORE_YIELD ) + { numTriesToGetLock = 0; pthread_yield(); } + } //while( currVP == NULL ) + MEAS__Capture_Post_Master_Lock_Point; + + //have master lock, perform master function, which manages request + // handling and assigning work to this core's slot + foundWork = - currVP = thisCoresMasterVP; - - MEAS__Capture_Pre_Master_Lock_Point; //back to back because - MEAS__Capture_Post_Master_Lock_Point; // sequential version - - if( numRepetitionsWithNoWork > NUM_REPS_W_NO_WORK_BEFORE_YIELD ) - { printf("Lots of reps w/o work\n"); - exit(0); //if no work, no way to ever get it in sequential! - } + masterFunction( animSlot ); + + PR_int__release_master_lock(); + + if( foundWork ) + numRepetitionsWithNoWork = 0; + else numRepetitionsWithNoWork += 1; - } - switchToSlv(currVP); //Slave suspend makes core "return" from this call + //now that master is done, have work in the slot, so switch to it + HOLISTIC__Record_Work_start; + + switchToSlv(animSlot->slaveAssignedToSlot); //Slave suspend makes core "return" from this call flushRegisters(); //prevent GCC optimization from doing bad things MEAS__Capture_End_Susp_in_CoreCtlr_ForSys; - - } //while(1) + HOLISTIC__Record_Work_end; + }//while(1) } + #endif diff -r bc5030385120 -r 40e7625e57bd Defines/MEAS__macros_to_be_moved_to_langs.h --- a/Defines/MEAS__macros_to_be_moved_to_langs.h Tue Feb 05 20:23:27 2013 -0800 +++ b/Defines/MEAS__macros_to_be_moved_to_langs.h Sat Mar 02 09:43:45 2013 -0800 @@ -22,30 +22,37 @@ #ifdef VCILK +/*These defines are used in the macros below*/ #define spawnHistIdx 1 //note: starts at 1 #define syncHistIdx 2 -#define MEAS__Make_Meas_Hists_for_Language() \ - _PRTopEnv->measHistsInfo = \ +#define MEAS__Make_Meas_Hists_for_VCilk( slave, magicNum ) \ + do \ + { VCilkLangEnv * \ + langEnv = PR_PI__get_lang_env_from_slave( slave, magicNum ); \ + langEnv->measHistsInfo = \ makePrivDynArrayOfSize( (void***)&(_PRTopEnv->measHists), 200); \ - makeAMeasHist( spawnHistIdx, "Spawn", 50, 0, 200 ) \ - makeAMeasHist( syncHistIdx, "Sync", 50, 0, 200 ) + histInfo = langEnv->measHistsInfo; + makeAMeasHist( histInfo, spawnHistIdx, "Spawn", 50, 0, 200 ) \ + makeAMeasHist( histInfo, syncHistIdx, "Sync", 50, 0, 200 ) \ + }while(FALSE); /* macro magic to protect local vars from name collision */ - -#define Meas_startSpawn \ +#define Meas_startSpawn fixme; /* changed names -- added __Cilk to end*/ + +#define Meas_startSpawn__Cilk \ int32 startStamp, endStamp; \ saveLowTimeStampCountInto( startStamp ); \ -#define Meas_endSpawn \ +#define Meas_endSpawn__Cilk \ saveLowTimeStampCountInto( endStamp ); \ addIntervalToHist( startStamp, endStamp, \ _PRTopEnv->measHists[ spawnHistIdx ] ); -#define Meas_startSync \ +#define Meas_startSync__Cilk \ int32 startStamp, endStamp; \ saveLowTimeStampCountInto( startStamp ); \ -#define Meas_endSync \ +#define Meas_endSync__Cilk \ saveLowTimeStampCountInto( endStamp ); \ addIntervalToHist( startStamp, endStamp, \ _PRTopEnv->measHists[ syncHistIdx ] ); diff -r bc5030385120 -r 40e7625e57bd HW_Dependent_Primitives/PR__primitives.h --- a/HW_Dependent_Primitives/PR__primitives.h Tue Feb 05 20:23:27 2013 -0800 +++ b/HW_Dependent_Primitives/PR__primitives.h Sat Mar 02 09:43:45 2013 -0800 @@ -31,8 +31,10 @@ void jmpToTwoParamFn(); -void * +void asmTerminateCoreCtlr(SlaveVP *currSlv); +void +asmTerminateCoreCtlrSeq(SlaveVP *animatingSlv); #define flushRegisters() \ asm volatile ("":::"%rbx", "%r12", "%r13","%r14","%r15") diff -r bc5030385120 -r 40e7625e57bd HW_Dependent_Primitives/PR__primitives_asm.s --- a/HW_Dependent_Primitives/PR__primitives_asm.s Tue Feb 05 20:23:27 2013 -0800 +++ b/HW_Dependent_Primitives/PR__primitives_asm.s Sat Mar 02 09:43:45 2013 -0800 @@ -156,7 +156,7 @@ /* * This one for the sequential version is special. It discards the current stack - * and returns directly from the coreCtlr after PR_WL__dissipate_slaveVP was called + * and returns directly from the coreCtlr */ .globl asmTerminateCoreCtlrSeq asmTerminateCoreCtlrSeq: @@ -164,7 +164,7 @@ movq 0x20(%rdi), %rsp #restore stack pointer movq 0x18(%rdi), %rbp #restore frame pointer #argument is in %rdi - call PR_int__dissipate_slaveVP__SL + call PR_int__free_slaveVP movq %rbp , %rsp #goto the coreCtlrs stack pop %rbp #restore the old framepointer ret #return from core controller diff -r bc5030385120 -r 40e7625e57bd PR.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PR.c Sat Mar 02 09:43:45 2013 -0800 @@ -0,0 +1,314 @@ +/* + * Copyright 2010 OpenSourceResearchInstitute + * + * Licensed under BSD + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "PR.h" + + +#define thdAttrs NULL + + +/* MEANING OF WL PI SS int + * These indicate which places the function is safe to use. They stand for: + * WL: Wrapper Library + * PI: Plugin + * SS: Startup and Shutdown + * int: internal to the PR implementation + */ + + +//=========================================================================== + +//=========================================================================== + +/*Setup has two phases: + * 1) Semantic layer first calls init_PR, which creates masterEnv, and puts + * the master Slv into the work-queue, ready for first "call" + * 2) Semantic layer then does its own init, which creates the seed virt + * slave inside the semantic layer, ready to assign it when + * asked by the first run of the animationMaster. + * + *This part is bit weird because PR really wants to be "always there", and + * have applications attach and detach.. for now, this PR is part of + * the app, so the PR system starts up as part of running the app. + * + *The semantic layer is isolated from the PR internals by making the + * semantic layer do setup to a state that it's ready with its + * initial Slvs, ready to assign them to slots when the animationMaster + * asks. Without this pattern, the semantic layer's setup would + * have to modify slots directly to assign the initial virt-procrs, and put + * them into the readyToAnimateQ itself, breaking the isolation completely. + * + * + *The semantic layer creates the initial Slv(s), and adds its + * own environment to masterEnv, and fills in the pointers to + * the requestHandler and slaveAssigner plug-in functions + */ + +//Check the comments above -- likely out of sync + +/*This allocates PR data structures, populates the top environments. After + * this call, processes can be started. + */ +void +PR__start() + { + PR_SS__create_topEnv(); + + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + printf( "\n\n Running in SEQUENTIAL mode \n\n" ); + //Only difference between version with an OS thread pinned to each core and + // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. + + //Don't do anything here -- using main thread for all PR activity, so + // do PR activity when main thread calls "wait for process to end" + #else + DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(TopEnv,masterLock) ); + PR_SS__create_the_coreCtlr_OS_threads(); + + #endif + } + + +/*For now, this is ONLY called from the main thread -- seems this can be relaxed + * at some point, but want to reduce complexity to get the first version working + * so making this restriction for now.. + * + *It creates a seed slave, from the top-level fn and initial data passed into + * this fn. + *The only langlet in the created process is the default PRServ. The rest + * must be started up via calls made by the seed VP's top-level fn (passed in + * to this call). + *That places the information about which langlets are used within the process + * into the seed Fn of that process, where all the langlet start() calls are + * made. + * + *A process is represented by a structure that holds all the process-specific + * information: + *-] The hash-array containing the language environs of any langlets started + * inside the process. + *-] Counter of num live slaves and num live tasks in the process + * + */ +PRProcess * +PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ) + { SlaveVP *seedSlv; + PRProcess *process; + PRLangEnv **langEnvs, **langEnvsList; + + //This runs outside of the master lock, so use PR_WL form of malloc + process = PR_WL__malloc( sizeof(PRProcess) ); + _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; + _PRTopEnv->numProcesses += 1; + + langEnvs = + (PRLangEnv **)PR_int__make_collection_of_size( NUM_IN_COLLECTION ); + langEnvsList = PR_WL__malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); + process->langEnvs = langEnvs; + process->protoLangEnvsList = langEnvsList; + process->numLangEnvs = 0; + + //A Process starts with one slave, the seed slave + seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); + seedSlv->typeOfVP = SeedSlv; + seedSlv->processSlaveIsIn = process; + process->numLiveGenericSlvs = 1; //count the seed + process->numLiveTasks = 0; + + PRServLangEnv * + servicesLangEnv = + PRServ__start(seedSlv); + + //resume seedVP into PR's built-in services language's lang env + process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this + PR_PI__make_slave_ready( seedSlv, servicesLangEnv ); + + + //The first process created has to unblock the core controllers. + // This is the "magic" that starts the activity of PR going. + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + //Do nothing here.. in sequential mode, are using the main thread, so + // don't use it to do anything yet.. do the PR activity when main thread + // calls "wait for process to end" + #else + if( _PRTopEnv->numProcesses == 1 ) + { + //tell the core controller threads that a process is ready to be animated + //get lock, to lock out any threads still starting up -- they'll see + // that firstProcessReady is true before entering while loop, and so never + // wait on the condition + pthread_mutex_lock( &suspendLock ); + _PRTopEnv->firstProcessReady = 1; + pthread_mutex_unlock( &suspendLock ); + pthread_cond_broadcast( &suspendCond ); + } + #endif + pthread_mutex_init( &(process->doneLock), NULL ); + pthread_cond_init( &(process->doneCond), NULL ); + process->executionIsComplete = FALSE; + + return process; + } + +PR__end_seedVP( SlaveVP *seedSlv ) + { + PR_WL__send_end_slave_req( NULL, (RequestHandler)&PRServ__handleDissipateSeed, seedSlv, + PRServ_MAGIC_NUMBER ); + } + +PR__end_process_from_inside( SlaveVP *seedSlv ) + { + PR_WL__send_lang_request( NULL, (RequestHandler)&PRServ__handle_end_process_from_inside, + seedSlv, PRServ_MAGIC_NUMBER ); + } + + + +/*When all work in the process has completed, then return from this call. + * The seedVP of the process may still exist, but it has no work, nor do any + * other VPs.. + *The process must be shutdown via a separate call. That shutdown frees the + * process struct and bookkeeping structs. + *First checks whether the process is done, if yes, calls the clean-up fn then + * returns the result extracted from the PRProcess struct. + *If process not done yet, then performs a wait (in a loop to be sure the + * wakeup is not spurious, which can happen). PR registers the wait, and upon + * the process ending (last SlaveVP owned by it dissipates), then PR signals + * this to wakeup. This then calls the cleanup fn and returns the result. + */ +void * +PR__give_results_from_process_when_ready( PRProcess *process ) + { void *result; + //First get the "ACK" lock, then do normal wait for signal, then release + // ACK lock, to let end-process know it can free the process struct + pthread_mutex_lock( &(process->doneAckLock) ); + + pthread_mutex_lock( &(process->doneLock) ); + while( process->executionIsComplete != TRUE ) + { + pthread_cond_wait( &(process->doneCond), + &(process->doneLock) ); + } + pthread_mutex_unlock( &(process->doneLock) ); + result = process->resultToReturn; + + //now send "ACK" signal to process_end Fn, that it may proceed + pthread_mutex_unlock( &(process->doneAckLock) ); + + return result; + //TODO: BUG? -- can process be created and end, before this acquires the + // first lock? Can see some rare code that creates a bunch, before getting + // to waiting.. leave for now.. pain to fix.. + } + + +void +PR__wait_for_process_to_end( PRProcess *process ) + { + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + // call the one and only core ctlr (sequential version), in the main thread. + coreCtlr_Seq( NULL ); + flushRegisters(); //Not sure why here, but leaving to be safe + + #else + //First get the "ACK" lock, then do normal wait for signal, then release + // ACK lock, to let end-process know it can free the process struct + pthread_mutex_lock( &(process->doneAckLock) ); + pthread_mutex_lock( &(process->doneLock) ); + while( process->executionIsComplete != TRUE ) + { + pthread_cond_wait( &(process->doneCond), + &(process->doneLock) ); + } + pthread_mutex_unlock( &(process->doneLock) ); + //now send "ACK" signal to process_end Fn, that it may proceed + pthread_mutex_unlock( &(process->doneAckLock) ); + + //TODO: BUG? -- can process be created and end, before this acquires the + // first lock? Can see some rare code that creates a bunch, before getting + // to waiting.. leave for now.. pain to fix.. + #endif + } + + +void +PR__wait_for_all_activity_to_end() + { + pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); + while( !(_PRTopEnv->allActivityIsDone) ) + { + pthread_cond_wait( &(_PRTopEnv->activityDoneCond), + &(_PRTopEnv->activityDoneLock) ); + } + pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); + } + + +/*This info is retrieved by PRServ's "give environ string" function + *These Fn s are meant to be called from main, or possibly the seed slave. + */ +void +PR__set_app_info( char *info ) + { int32 len; + char *copy; + len = strlen(info) +1; + copy = PR_int__malloc(len); + strcpy(copy, info); + _PRTopEnv->metaInfo->appInfo = copy; + } +void +PR__set_input_info( char *info ) + { int32 len; + char *copy; + len = strlen(info) +1; + copy = PR_int__malloc(len); + strcpy(copy, info); + _PRTopEnv->metaInfo->inputInfo = copy; + } + + + + +//========================== SHUT DOWN =========================== + +/*This is called from the main thread, and causes PR's OS threads to stop + * then cleans up any memory allocated by PR from the OS. + * + *The main thread has a separate call it can use to wait for all work to + * finish, so when this is called, it just shuts down, whether there's + * unfinished work or not. + * + *However, cores that are performing work won't see this shutdown until + * they finish their current work-unit. + */ +void +PR__shutdown() + { int32 coreIdx; + + PR_SS__shutdown_OS_threads(); + + //wait for the OS threads to exit + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) + { + pthread_join( coreCtlrThdHandles[coreIdx], NULL ); + } + + //Before getting rid of everything, print out any measurements made + PR_SS__print_out_measurements(); + + //free all memory allocated from the OS + PR_SS__cleanup_at_end_of_shutdown(); + } + + + diff -r bc5030385120 -r 40e7625e57bd PR.h --- a/PR.h Tue Feb 05 20:23:27 2013 -0800 +++ b/PR.h Sat Mar 02 09:43:45 2013 -0800 @@ -86,7 +86,7 @@ #include "PR__WL.h" //================================= -#define implement_me printf("Unimpl Fn: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) +#define implement_me() printf("Unimpl Fn: \n%s \n%s : %d\n", __FILE__, __FUNCTION__, __LINE__) //#define fix_me printf("Fix me at: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) diff -r bc5030385120 -r 40e7625e57bd PR__PI.c --- a/PR__PI.c Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__PI.c Sat Mar 02 09:43:45 2013 -0800 @@ -49,6 +49,16 @@ } } +/*Any langlet can transfer slaves over to be resumed in PRServ.. the resume Fn + * is registered in the PRServ lang env during process creation. + */ +void +PR_PI__resume_slave_in_PRServ( SlaveVP *slave ) + { void *langEnv; + langEnv = PR_PI__give_lang_env_for_slave( slave, PRServ_MAGIC_NUMBER ); + PR_PI__make_slave_ready( slave, langEnv ); + } + void PR_PI__make_task_ready( void *_task, void *_langEnv ) { PRLangEnv *protoLangEnv; @@ -57,7 +67,7 @@ { //put task into override readyQ - //update override hasWork flag ? + //update numWorkReady } else { //call langlet's registered make ready @@ -72,7 +82,84 @@ } } + +/*This is used by langlets.. the intent is that they provide a wrapper + * lib call for a "wait" command, and then call this PR service inside their + * request handler. + *Note: PRServ doesn't offer a "wait for work to end".. it also doesn't have any + * create work calls.. and there is no way to end PRServ, except by ending the + * process. Therefore, this can safely use the PRServ env to + * resume any waiting slaves (incl free task slaves, which are one-to-one + * with a task). + */ +void +PR_PI__handle_wait_for_langlets_work_to_end( SlaveVP *slave, void *langEnv ) + { PRLangEnv *protoLangEnv; + protoLangEnv = PR_int__give_proto_lang_env( langEnv ); + + if( protoLangEnv->numLiveWork == 0 ) + { //resume into different env than one with no work, as it may be shut down + void * + resumeEnv = PR_PI__give_lang_env_from_process( slave->processSlaveIsIn, PRServ_MAGIC_NUMBER ); + PR_PI__make_slave_ready( slave, resumeEnv ); + return; + } + else + { + writePrivQ( slave, protoLangEnv->waitingForWorkToEndQ ); + } + } + +SlaveVP * +PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ) + { PRMetaTask *metaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); + return metaTask->slaveAssignedTo; + } + +void +PR_PI__set_no_del_flag_in_lang_meta_task( void *langMetaTask ) + { PRMetaTask *protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); + protoMetaTask->goAheadAndFree = FALSE; + } + +void +PR_PI__clear_no_del_flag_in_lang_meta_task( void *langMetaTask ) + { PRMetaTask *protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); + protoMetaTask->goAheadAndFree = TRUE; + } + +/*Two use-cases for freeing a meta-task.. one is the langlet has control + * over the meta tasks's life-line it may differ from the task-work-unit's + * lifeline.. the other is PR controls, for example when a langlet or + * process gets pre-maturely shutdown due to outside influences, or exception, + * and so on.. + *In the first case, the langlet has two choices.. it can free all the langlet + * malloc'd data owned by the meta-task, then as PR to free the remaining + * proto meta-task.. or, it can just call PR's full-service "free meta-task" + * which in turn calls the langlet's "free just langlet-malloc'd data" Fn, which + * was given to the meta-task creator.. + * + *In the second case, PR calls the langlet's "free just langlet malloc'd data" + * Fn, which was given to the meta-task creator. The langlet has no other + * involvement. + * + *This is used by the langlet when it separately frees its own + * portion of the meta-task. + * + *PR uses "PR_int__free_lang_meta_task", which calls the langlet's freer, which + * was given to the meta task creator + */ +void +PR_PI__free_proto_meta_task_by_langlet( PRMetaTask *protoMetaTask ) + { + PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber, + (PRCollElem **) protoMetaTask->slaveAssignedTo->metaTasks ); + + PR_int__free( protoMetaTask ); + } + + PRReqst * PR_PI__take_next_request_out_of( SlaveVP *slaveWithReq ) { PRReqst *req; diff -r bc5030385120 -r 40e7625e57bd PR__PI.h --- a/PR__PI.h Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__PI.h Sat Mar 02 09:43:45 2013 -0800 @@ -36,28 +36,159 @@ * wrapper-library calls! */ -#define PR_PI__create_slaveVP PR_int__create_slaveVP_helper +#define \ +PR_PI__create_slaveVP PR_int__create_slaveVP_helper -inline +//============== +//=== Lang Data +//= +#define \ +PR_PI__give_lang_data_from_slave PR_int__give_lang_data_from_slave +#define \ +PR_SS__give_lang_data_from_slave PR_int__give_lang_data_from_slave + + +//============ +//=== Lang Env +//= +#define \ +PR_PI__give_proto_lang_env_for_slave PR_int__give_proto_lang_env_for_slave +#define \ +PR_PI__give_lang_env_for_slave PR_int__give_lang_env_for_slave +#define \ +PR_PI__give_lang_env_from_process PR_int__give_lang_env_from_process + + +//========= +//=== Meta Task +//= +#define \ +PR_PI__give_lang_meta_task_from_slave PR_int__give_lang_meta_task_from_slave +#define \ +PR_PI__give_prolog_of_lang_meta_task PR_int__give_prolog_of_lang_meta_task + SlaveVP * PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ); +#define \ +PR_PI__free_lang_meta_task_and_remove_from_slave PR_int__free_lang_meta_task_and_remove_from_coll + +#define \ +PR_PI__free_lang_meta_task PR_int__free_lang_meta_task + +void +PR_PI__set_no_del_flag_in_lang_meta_task( void *langMetaTask ); +void +PR_PI__clear_no_del_flag_in_lang_meta_task( void *langMetaTask ); + +//========== +//=== +//= +#define \ +PR_PI__give_ID_from_lang_meta_task PR__give_ID_from_lang_meta_task +#define \ +PR_PI__give_ID_from_slave PR__give_ID_from_slave + +//============= +//=== +//= +#define \ +PR_PI__put_slave_into_slot PR_int__put_slave_into_slot +#define \ +PR_PI__put_task_into_slot PR_int__put_task_into_slot PRReqst * PR_PI__take_next_request_out_of( SlaveVP *slaveWithReq ); -//#define PR_PI__take_next_request_out_of( slave ) slave->requests -//inline void * -//PR_PI__take_lang_reqst_from( PRReqst *req ); -#define PR_PI__take_lang_reqst_from( req ) req->langReqData +#define \ +PR_PI__take_lang_reqst_from( req ) req->langReq + +void +PR_PI__resume_slave_in_PRServ( SlaveVP *slave ); + +#define \ +PR_PI__malloc PR_int__malloc +#define \ +PR_PI__malloc_aligned PR_int__malloc_aligned +#define \ +PR_PI__free PR_int__free + + +#define \ +PR_PI__throw_exception PR_int__throw_exception //=============== Startup and Shutdown ================ +//=== +//= +void +PR_SS__create_topEnv(); + +AnimSlot ** +PR_SS__create_anim_slots( int32 coreSlotsAreOn ); + +void +PR_SS__create_the_coreCtlr_OS_threads(); + +//=================== +void * +PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum ); + +void +PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ); +void +PR_SS__register_lang_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP, + int32 magicNum ); +void +PR_SS__register_lang_data_creator( LangDataCreator langDataCreator, + SlaveVP *seedVP, int32 magicNum ); +void +PR_SS__register_lang_meta_task_creator( LangDataCreator langMetaTaskCreator, + SlaveVP *seedVP, int32 magicNum ); +void +PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP, + int32 magicNum ); +void +PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP, + int32 magicNum ); +//=================== + +void +PR_SS__end_process_normally( PRProcess *process ); + void PR_SS__shutdown_OS_threads(); + +SlaveVP* +PR_SS__create_shutdown_slave(); + +void +PR_SS__cleanup_at_end_of_shutdown(); void PR_SS__print_out_measurements(); +void +PR_SS__wait_for_PR_to_shutdown(); + + +//============================= +//=== +//= + +#define \ +PR_SS__give_proto_lang_env_for_slave PR_int__give_proto_lang_env_for_slave + +#define \ +PR_SS__give_lang_meta_task_from_slave PR_int__give_lang_meta_task_from_slave +#define \ +PR_SS__give_lang_env_for_slave PR_int__give_lang_env_for_slave +#define \ +PR_SS__give_lang_env_from_process PR_int__give_lang_env_from_process + +#define \ +PR_SS__malloc PR_WL__malloc /*SS happens outside the Master*/ +#define \ +PR_SS__free PR_WL__free //================================================ #endif /* _PR__PI_H */ diff -r bc5030385120 -r 40e7625e57bd PR__SS.c --- a/PR__SS.c Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__SS.c Sat Mar 02 09:43:45 2013 -0800 @@ -28,14 +28,6 @@ //=========================================================================== -AnimSlot ** -create_anim_slots( int32 coreSlotsAreOn ); - -void -create_topEnv(); - -void -create_the_coreCtlr_OS_threads(); MallocProlog * create_free_list(); @@ -45,571 +37,8 @@ //=========================================================================== - -/*Setup has two phases: - * 1) Semantic layer first calls init_PR, which creates masterEnv, and puts - * the master Slv into the work-queue, ready for first "call" - * 2) Semantic layer then does its own init, which creates the seed virt - * slave inside the semantic layer, ready to assign it when - * asked by the first run of the animationMaster. - * - *This part is bit weird because PR really wants to be "always there", and - * have applications attach and detach.. for now, this PR is part of - * the app, so the PR system starts up as part of running the app. - * - *The semantic layer is isolated from the PR internals by making the - * semantic layer do setup to a state that it's ready with its - * initial Slvs, ready to assign them to slots when the animationMaster - * asks. Without this pattern, the semantic layer's setup would - * have to modify slots directly to assign the initial virt-procrs, and put - * them into the readyToAnimateQ itself, breaking the isolation completely. - * - * - *The semantic layer creates the initial Slv(s), and adds its - * own environment to masterEnv, and fills in the pointers to - * the requestHandler and slaveAssigner plug-in functions - */ - -//Check the comments above -- likely out of sync - -/*This allocates PR data structures, populates the top environments. After - * this call, processes can be started. - */ void -PR__start() - { - create_topEnv(); - - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - printf( "\n\n Running in SEQUENTIAL mode \n\n" ); - #else - DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(TopEnv,masterLock) ); - create_the_coreCtlr_OS_threads(); - - #endif - } - - -/*This creates a new process and sets the mode to single lang for it - *It creates a seed slave, from the top-level fn and initial data passed into - * this fn. - *The only langlet in the created process is the default PRServ. The rest - * must b e started up via calls made by the seed VP's top-level fn (passed in - * to this call). - * - *A process is represented by a structure that holds all the process-specific - * information: - *-] The hash-array containing the language environs of any langlets started - * inside the process. - *-] Counter of num live slaves and num live tasks in the process - * - */ -/* -PRProcess * -PR__create_process__SL( TopLevelFnPtr seed_Fn, void *seedData ) - { SlaveVP *seedSlv; - PRProcess *process; - PRLangEnv **langEnvs, **langEnvsList; - - _PRTopEnv->mode = SingleLang; - - - process = malloc( sizeof(PRProcess) ); - _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; - _PRTopEnv->numProcesses += 1; - - langEnvs = malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRCollElem *) ); - ((int32 *)langEnvs)[0] = NUM_IN_COLLECTION; - langEnvsList = malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); - process->langEnvs = langEnvs; - process->langEnvsList = langEnvsList; - process->numLangEnvs = 0; - - //A Process starts with one slave, the seed slave - seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); - seedSlv->typeOfVP = SeedSlv; - seedSlv->processSlaveIsIn = process; - process->numLiveGenericSlvs = 1; //count the seed - process->numLiveTasks = 0; - - PRServLangEnv * - servicesLangEnv = - PR_int__create_lang_env_in_process( sizeof(PRServLangEnv), process, PRServ_MAGIC_NUMBER ); - - servicesLangEnv->slavesReadyToResumeQ = makePrivQ(); - servicesLangEnv->taskReadyQ = makePrivQ(); - - //resume seedVP into PR's built-in services language's language env - process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this - PRServ__resume_slaveVP( seedSlv, servicesLangEnv ); - - - //The first process created has to unblock the core controllers. - if( _PRTopEnv->numProcesses == 1 ) - { - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - //Only difference between version with an OS thread pinned to each core and - // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. - - // call the one and only core ctlr (sequential version), in the main thread. - coreCtlr_Seq( NULL ); - flushRegisters(); //Not sure why here, but leaving to be safe - #else - //tell the core controller threads that a process is ready to be animated - //get lock, to lock out any threads still starting up -- they'll see - // that firstProcessReady is true before entering while loop, and so never - // wait on the condition - pthread_mutex_lock( &suspendLock ); - _PRTopEnv->firstProcessReady = 1; - pthread_mutex_unlock( &suspendLock ); - pthread_cond_broadcast( &suspendCond ); - #endif - } - pthread_mutex_init( process->doneLock, NULL ); - pthread_cond_init( process->doneCond, NULL ); - process->executionIsComplete = FALSE; - - return process; - } - */ - -/*This is only called in multi-lang mode. - *It creates a seed slave, from the top-level fn and initial data passed into - * this fn. - *The only langlet in the created process is the default PRServ. The rest - * must be started up via calls made by the seed VP's top-level fn (passed in - * to this call). - * - *A process is represented by a structure that holds all the process-specific - * information: - *-] The hash-array containing the language environs of any langlets started - * inside the process. - *-] Counter of num live slaves and num live tasks in the process - * - */ -PRProcess * -PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ) - { SlaveVP *seedSlv; - PRProcess *process; - PRLangEnv **langEnvs, **langEnvsList; - - _PRTopEnv->mode = MultiLang; //leftover, not used, but reminder - - //This runs outside of the master lock, so use PR_WL form of malloc - process = PR_WL__malloc( sizeof(PRProcess) ); - _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; - _PRTopEnv->numProcesses += 1; - - langEnvs = PR_WL__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRCollElem *) ); - ((int32 *)langEnvs)[0] = NUM_IN_COLLECTION; - langEnvsList = PR_WL__malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); - process->langEnvs = langEnvs; - process->langEnvsList = langEnvsList; - process->numLangEnvs = 0; - - //A Process starts with one slave, the seed slave - seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); - seedSlv->typeOfVP = SeedSlv; - seedSlv->processSlaveIsIn = process; - process->numLiveGenericSlvs = 1; //count the seed - process->numLiveTasks = 0; - - PRServLangEnv * - servicesLangEnv = - PR_int__create_lang_env_in_process( sizeof(PRServLangEnv), process, - PRServ_MAGIC_NUMBER ); - - servicesLangEnv->slavesReadyToResumeQ = makePrivQ(); - servicesLangEnv->taskReadyQ = makePrivQ(); - - //resume seedVP into PR's built-in services language's language env - process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this - PRServ__resume_slaveVP( seedSlv, servicesLangEnv ); - - - //The first process created has to unblock the core controllers. - if( _PRTopEnv->numProcesses == 1 ) - { - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - //Only difference between version with an OS thread pinned to each core and - // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. - - // call the one and only core ctlr (sequential version), in the main thread. - coreCtlr_Seq( NULL ); - flushRegisters(); //Not sure why here, but leaving to be safe - #else - //tell the core controller threads that a process is ready to be animated - //get lock, to lock out any threads still starting up -- they'll see - // that firstProcessReady is true before entering while loop, and so never - // wait on the condition - pthread_mutex_lock( &suspendLock ); - _PRTopEnv->firstProcessReady = 1; - pthread_mutex_unlock( &suspendLock ); - pthread_cond_broadcast( &suspendCond ); - #endif - } - pthread_mutex_init( &(process->doneLock), NULL ); - pthread_cond_init( &(process->doneCond), NULL ); - process->executionIsComplete = FALSE; - - return process; - } - - -/*are already in Master when detect, inside end-task or dissipate, so call "PR_SS__shutdown_process" - */ -void -PR_SS__shutdown_process( PRProcess *process ) - { int32 i, processIdx; - PRProcess **processes; - - //remove process from PR's list of processes.. - processes = _PRTopEnv->processes; - //find the process within the list - for( i = 0; i < _PRTopEnv->numProcesses; i++ ) - { if( processes[i] == process ) - { processIdx = i; - break; - } - } - //move all the higher processes down, overwriting the target - for( i = processIdx +1; i < _PRTopEnv->numProcesses; i++ ) - { processes[i-1] = processes[i]; - } - _PRTopEnv->numProcesses -= 1; - - //remove process from the process-to-slot chooser - _PRTopEnv->currProcessIdx = 0; //start choosing starting at process 0 - - //call shutdown on each langlet started in process (which frees any - // langlet-allocd data in langEnv); - //Then free the lang env - PRLangEnv *protoLangEnv; - for( i = 0; i < process->numLangEnvs; i++ ) - { protoLangEnv = PR_int__give_proto_lang_env(process->langEnvsList[i]); - //The lang shutdowns should free any slaves or tasks in the langEnv - (*protoLangEnv->shutdownHdlr)(&(protoLangEnv[1])); - PR_int__free( protoLangEnv ); - } - PR_int__free( process->langEnvsList ); //list array - PR_int__free( &(((int32 *)process->langEnvs)[-1]) ); //the collection array - - //any slaves from this process still in slots will finish executing, but - // have no lang env for the request handlers to use! - //So, have to mark each slave, so the request handling isn't done - AnimSlot *slot, **animSlots; - int32 core; - for( core = 0; core < NUM_CORES; core++ ) - { animSlots = _PRTopEnv->allAnimSlots[core]; - for( i = 0; i < NUM_ANIM_SLOTS; i++ ) - { slot = animSlots[i]; - if( slot->slaveAssignedToSlot->processSlaveIsIn == process ) - { //turn off req handling by disallowing slave from chging slot flag - slot->slaveAssignedToSlot->animSlotAssignedTo = NULL; - slot->workIsDone = FALSE; //just in case, make sure req hdling off - slot->needsWorkAssigned = TRUE; //make new slave be assigned - } - } - } - - //cause resume of "PR__wait_for_process_to_end()" call - pthread_mutex_lock( &(process->doneLock) ); - process->executionIsComplete = TRUE; - pthread_mutex_unlock( &(process->doneLock) ); - pthread_cond_broadcast( &(process->doneCond) ); - //now wait for woken waiter to Ack, then free the process struct - pthread_mutex_lock( &(process->doneAckLock) ); //BUG:? may be a race - pthread_mutex_unlock( &(process->doneAckLock) ); - PR_int__free(process); - - //if no more processes, cause resume of "PR__wait_for_all_activity_to_end" - if( _PRTopEnv->numProcesses == 0) - { - pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); - _PRTopEnv->allActivityIsDone = TRUE; - pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); - pthread_cond_broadcast( &(_PRTopEnv->activityDoneCond) ); - } - } - -/*This waits for the OS threads in the PR system to end. Causing them to end - * has to be done separately (haven't worked out details as of this comment) - */ -void -PR_SS__wait_for_PR_to_shutdown() - { - //wait for all to complete - int coreIdx; - for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) - { - pthread_join( coreCtlrThdHandles[coreIdx], NULL ); - } - } - -void -PR__wait_for_all_activity_to_end() - { - pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); - while( !(_PRTopEnv->allActivityIsDone) ) - { - pthread_cond_wait( &(_PRTopEnv->activityDoneCond), - &(_PRTopEnv->activityDoneLock) ); - } - pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); - } - - -void -PR__wait_for_process_to_end( PRProcess *process ) - { //First get the "ACK" lock, then do normal wait for signal, then release - // ACK lock, to let end-process know it can free the process struct - pthread_mutex_lock( &(process->doneAckLock) ); - pthread_mutex_lock( &(process->doneLock) ); - while( process->executionIsComplete != TRUE ) - { - pthread_cond_wait( &(process->doneCond), - &(process->doneLock) ); - } - pthread_mutex_unlock( &(process->doneLock) ); - //now send "ACK" signal to process_end Fn, that it may proceed - pthread_mutex_unlock( &(process->doneAckLock) ); - - //TODO: BUG? -- can process be created and end, before this acquires the - // first lock? Can see some rare code that creates a bunch, before getting - // to waiting.. leave for now.. pain to fix.. - } - -/*When all work in the process has completed, then return from this call. - * The seedVP of the process may still exist, but it has no work, nor do any - * other VPs.. - *The process must be shutdown via a separate call. That shutdown frees the - * process struct and bookkeeping structs. - *First checks whether the process is done, if yes, calls the clean-up fn then - * returns the result extracted from the PRProcess struct. - *If process not done yet, then performs a wait (in a loop to be sure the - * wakeup is not spurious, which can happen). PR registers the wait, and upon - * the process ending (last SlaveVP owned by it dissipates), then PR signals - * this to wakeup. This then calls the cleanup fn and returns the result. - */ -void * -PR__give_results_from_process_when_ready( PRProcess *process ) - { void *result; - //First get the "ACK" lock, then do normal wait for signal, then release - // ACK lock, to let end-process know it can free the process struct - pthread_mutex_lock( &(process->doneAckLock) ); - - pthread_mutex_lock( &(process->doneLock) ); - while( process->executionIsComplete != TRUE ) - { - pthread_cond_wait( &(process->doneCond), - &(process->doneLock) ); - } - pthread_mutex_unlock( &(process->doneLock) ); - result = process->resultToReturn; - - //now send "ACK" signal to process_end Fn, that it may proceed - pthread_mutex_unlock( &(process->doneAckLock) ); - - return result; - //TODO: BUG? -- can process be created and end, before this acquires the - // first lock? Can see some rare code that creates a bunch, before getting - // to waiting.. leave for now.. pain to fix.. - } - - -inline -void * -PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum ) - { - return PR_int__create_lang_env_in_process( size, slave->processSlaveIsIn, magicNum ); - } - - -/*These store the pointer to handler into the language env -- language env - * found by using magic num to look it up in the process that the seedVP - * is inside of. - */ -void -PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->workAssigner = assigner; - } -void -PR_SS__register_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP, - int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->shutdownHdlr = shutdownHdlr; - } -void -PR_SS__register_lang_data_creator( LangDataCreator langDataCreator, - SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->langDataCreator = langDataCreator; - } -void -PR_SS__register_lang_meta_task_creator( LangDataCreator langMetaTaskCreator, - SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->langMetaTaskCreator = langMetaTaskCreator; - } -void -PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP, - int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->makeSlaveReadyFn = fn; - } -void -PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP, - int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->makeTaskReadyFn = fn; - } - -/* -void -PR_SS__register_create_task_handler( RequestHandler createTaskHandler, SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->createTaskHdlr = createTaskHandler; - } -void -PR_SS__register_end_task_handler( RequestHandler endTaskHandler, SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->endTaskHdlr = endTaskHandler; - } -void -PR_SS__register_create_slave_handler( RequestHandler createSlvHandler, SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->createSlaveHdlr = createSlvHandler; - } -void -PR_SS__register_dissipate_slave_handler( RequestHandler dissipateHandler, SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->dissipateSlaveHdlr = dissipateHandler; - } -void -PR_SS__register_request_handler( RequestHandler reqHandler, SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->requestHdlr = reqHandler; - } - */ -/* -void -PR_SS__register_lang_data_initializer( LangDataInitializer langDataInitializer, - SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->langDataInitializer = langDataInitializer; - } -void -PR_SS__register_lang_data_freer( LangDataFreer langDataFreer, - SlaveVP *seedVP, int32 magicNum ) - { PRLangEnv *langEnv; - - langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); - langEnv->langDataFreer = langDataFreer; - } -*/ - - - - -/* - *This function returns information about the version of PR, the language - * the program is being run in, its version, and information on the - * hardware. - */ -char * -PRServ___give_environment_string() - { char *buffer = PR_WL__malloc(10000); - int32 j; - - j = sizeof(int32); //put total num chars here when done - //-------------------------- - j += sprintf(buffer+j, "#\n# >> Build information <<\n"); - j += sprintf(buffer+j, "# GCC VERSION: %d.%d.%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__); - j += sprintf(buffer+j, "# Build Date: %s %s\n", __DATE__, __TIME__); - - j += sprintf(buffer+j, "#\n# >> Hardware information <<\n"); - j += sprintf(buffer+j, "# Hardware Architecture: "); - #ifdef __x86_64 - j += sprintf(buffer+j, "x86_64"); - #endif //__x86_64 - #ifdef __i386 - j += sprintf(buffer+j, "x86"); - #endif //__i386 - j += sprintf(buffer+j, "\n"); - j += sprintf(buffer+j, "# Number of Cores: %d\n", NUM_CORES); - //-------------------------- - - //PR Plugins - j += sprintf(buffer+j, "#\n# >> PR Plugins <<\n"); - j += sprintf(buffer+j, "# Language : "); - j += sprintf(buffer+j, _LANG_NAME_); - j += sprintf(buffer+j, "\n"); - //Meta info gets set by calls from the language during its init, - // and info registered by calls from inside the application - j += sprintf(buffer+j, "# Assigner: %s\n", _PRTopEnv->metaInfo->assignerInfo); - - //-------------------------- - //Application - j += sprintf(buffer+j, "#\n# >> Application <<\n"); - j += sprintf(buffer+j, "# Name: %s\n", _PRTopEnv->metaInfo->appInfo); - j += sprintf(buffer+j, "# Data Set:\n%s\n",_PRTopEnv->metaInfo->inputInfo); - - ((int32 *)buffer)[0] = j - sizeof(int32); //insert the number of chars - //-------------------------- - return (char *) &(((int32 *)buffer)[1]); //return pointer to first char - } - -void -PR__set_app_info( char *info ) - { int32 len; - char *copy; - len = strlen(info) +1; - copy = PR_int__malloc(len); - strcpy(copy, info); - _PRTopEnv->metaInfo->appInfo = copy; - } -void -PR__set_input_info( char *info ) - { int32 len; - char *copy; - len = strlen(info) +1; - copy = PR_int__malloc(len); - strcpy(copy, info); - _PRTopEnv->metaInfo->inputInfo = copy; - } - - - - - - -void -create_topEnv() +PR_SS__create_topEnv() { TopEnv *masterEnv; PRQueueStruc **readyToAnimateQs; int32 coreIdx; @@ -640,16 +69,18 @@ allAnimSlots = PR_int__malloc( NUM_CORES * sizeof(AnimSlot *) ); _PRTopEnv->allAnimSlots = allAnimSlots; - //Make the master VPs + //Make the animation slots and similar per-core structs.. for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) { - readyToAnimateQs[ coreIdx ] = makePRQ(); + //readyToAnimateQs[ coreIdx ] = makePRQ(); - //Q: should give masterVP core-specific info as its init data? +/* //Q: should give masterVP core-specific info as its init data? + Don't have masterVPs anymore -- the pinned pthread takes that role masterVPs[ coreIdx ] = PR_int__create_slaveVP_helper( (TopLevelFnPtr)&animationMaster, (void*)_PRTopEnv ); masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx; masterVPs[ coreIdx ]->typeOfVP = Master; - allAnimSlots[ coreIdx ] = create_anim_slots( coreIdx ); //makes for one core + */ + allAnimSlots[ coreIdx ] = PR_SS__create_anim_slots( coreIdx ); //makes for one core } //For each animation slot, there is an idle slave, and an initial @@ -659,10 +90,11 @@ for( coreNum = 0; coreNum < NUM_CORES; coreNum++ ) { //langEnv->coreIsDone[coreNum] = FALSE; //use during shutdown - + //Still have multiple slots -- left over from prev incarnation for( slotNum = 0; slotNum < NUM_ANIM_SLOTS; ++slotNum ) { idleSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL ); idleSlv->coreAnimatedBy = coreNum; + idleSlv->typeOfVP = IdleVP; idleSlv->animSlotAssignedTo = _PRTopEnv->allAnimSlots[coreNum][slotNum]; _PRTopEnv->idleSlv[coreNum][slotNum] = idleSlv; @@ -688,6 +120,7 @@ _PRTopEnv->numSlavesCreated = 0; //used by create slave to set slave ID + //TODO: remove this, and the vars from TopEnv //=================== single lang only vars ================== // // @@ -704,6 +137,7 @@ // readyToAnimateQs = PR_int__malloc( NUM_CORES * sizeof(PRQueueStruc *) ); + //BUG: have a fixed max num processes, but never check whether exceeded _PRTopEnv->processes = PR_int__malloc( NUM_IN_COLLECTION * sizeof(PRProcess *) ); _PRTopEnv->numProcesses = 0; _PRTopEnv->currProcessIdx = 0; @@ -731,7 +165,7 @@ } AnimSlot ** -create_anim_slots( int32 coreSlotsAreOn ) +PR_SS__create_anim_slots( int32 coreSlotsAreOn ) { AnimSlot **animSlots; int i; @@ -751,7 +185,7 @@ } void -freeAnimSlots( AnimSlot **animSlots ) +PR_SS__freeAnimSlots( AnimSlot **animSlots ) { int i; for( i = 0; i < NUM_ANIM_SLOTS; i++ ) { @@ -769,7 +203,7 @@ * all the core controller threads when the first process is created. */ void -create_the_coreCtlr_OS_threads() +PR_SS__create_the_coreCtlr_OS_threads() { //======================================================================== // Create the Threads @@ -800,34 +234,149 @@ } -//========================== SHUT DOWN =========================== +//====================== +//=== +//= +//inline +void * +PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum ) + { + return PR_int__create_lang_env_in_process( size, slave->processSlaveIsIn, magicNum ); + } -/*This is called from the main thread, and causes PR's OS threads to stop - * then cleans up any memory allocated by PR from the OS. - * - *The main thread has a separate call it can use to wait for all work to - * finish, so when this is called, it just shuts down, whether there's - * unfinished work or not. - * - *However, cores that are performing work won't see this shutdown until - * they finish their current work-unit. + +/*These store the pointer to handler into the language env -- language env + * found by using magic num to look it up in the process that the seedVP + * is inside of. */ -PR__shutdown() - { int32 coreIdx; +void +PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->workAssigner = assigner; + } +void +PR_SS__register_lang_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP, + int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->shutdownHdlr = shutdownHdlr; + } +void +PR_SS__register_lang_data_creator( LangDataCreator langDataCreator, + SlaveVP *seedVP, int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->langDataCreator = langDataCreator; + } +void +PR_SS__register_lang_meta_task_creator( LangMetaTaskCreator langMetaTaskCreator, + SlaveVP *seedVP, int32 magicNum ) + { PRLangEnv *protoLangEnv; + + protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + protoLangEnv->langMetaTaskCreator = langMetaTaskCreator; + } +void +PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP, + int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->makeSlaveReadyFn = fn; + } +void +PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP, + int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->makeTaskReadyFn = fn; + } + +//======== + + +/*are in Master when call this.. due to detecting end-of-work, from inside + * end-task or dissipate.. or, call this when app calls "end process" + */ +void +PR_SS__end_process_normally( PRProcess *process ) + { int32 i, processIdx; + PRProcess **processes; - PR_SS__shutdown_OS_threads(); + //remove process from PR's list of processes.. + processes = _PRTopEnv->processes; + //find the process within the list + for( i = 0; i < _PRTopEnv->numProcesses; i++ ) + { if( processes[i] == process ) + { processIdx = i; + break; + } + } + //move all the higher processes down, overwriting the target + for( i = processIdx +1; i < _PRTopEnv->numProcesses; i++ ) + { processes[i-1] = processes[i]; + } + _PRTopEnv->numProcesses -= 1; - //wait for the OS threads to exit - for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) + //remove process from the process-to-slot chooser + _PRTopEnv->currProcessIdx = 0; //start choosing starting at process 0 + + //call shutdown on each langlet started in process (which frees any + // langlet-allocd data in langEnv); + //Then free the lang env + PRLangEnv *protoLangEnv; + for( i = 0; i < process->numLangEnvs; i++ ) + { protoLangEnv = PR_int__give_proto_lang_env(process->protoLangEnvsList[i]); + //The lang shutdowns should free any slaves or tasks in the langEnv + (*protoLangEnv->shutdownHdlr)(&(protoLangEnv[1])); + PR_int__free( protoLangEnv ); + } + PR_int__free( process->protoLangEnvsList ); //list array + PR_int__free( &(((int32 *)process->langEnvs)[-1]) ); //the collection array + + //any slaves from this process still in slots will finish executing, but + // have no lang env for the request handlers to use! + //So, have to mark each slave, so the request handling isn't done + AnimSlot *slot, **animSlots; + int32 core; + for( core = 0; core < NUM_CORES; core++ ) + { animSlots = _PRTopEnv->allAnimSlots[core]; + for( i = 0; i < NUM_ANIM_SLOTS; i++ ) + { slot = animSlots[i]; + if( slot->slaveAssignedToSlot->processSlaveIsIn == process ) + { //turn off req handling by disallowing slave from chging slot flag + slot->slaveAssignedToSlot->animSlotAssignedTo = NULL; + slot->workIsDone = FALSE; //just in case, make sure req hdling off + slot->needsWorkAssigned = TRUE; //make new slave be assigned + } + } + } + + //cause resume of "PR__wait_for_process_to_end()" call + if( process->hasWaitingToEnd ) { - pthread_join( coreCtlrThdHandles[coreIdx], NULL ); + pthread_mutex_lock( &(process->doneLock) ); + process->executionIsComplete = TRUE; + pthread_mutex_unlock( &(process->doneLock) ); + pthread_cond_broadcast( &(process->doneCond) ); + //now wait for woken waiter to Ack, then free the process struct + pthread_mutex_lock( &(process->doneAckLock) ); //BUG:? may be a race + pthread_mutex_unlock( &(process->doneAckLock) ); + PR_int__free(process); + } + //if no more processes, cause resume of "PR__wait_for_all_activity_to_end" + if( _PRTopEnv->numProcesses == 0) + { + pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); + _PRTopEnv->allActivityIsDone = TRUE; + pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); + pthread_cond_broadcast( &(_PRTopEnv->activityDoneCond) ); } - - //Before getting rid of everything, print out any measurements made - PR_SS__print_out_measurements(); - - //free all memory allocated from the OS - PR_SS__cleanup_at_end_of_shutdown(); } @@ -868,12 +417,26 @@ SlaveVP* shutdownVP; shutdownVP = PR_int__create_slaveVP_helper( &endOSThreadFn, NULL ); - shutdownVP->typeOfVP = Shutdown; + shutdownVP->typeOfVP = ShutdownVP; return shutdownVP; } +/*This is run in the main thread, as part of the PR__shutdown() call + * It frees any memory allocated from the OS + */ +void +PR_SS__cleanup_at_end_of_shutdown() + { + //All the environment data has been allocated with PR__malloc, so just + // free the memory obtained by PR__malloc, then free the top env. + //These are the only two that use system free + PR_ext__free_free_list( _PRTopEnv->freeLists ); + free( (void *)_PRTopEnv ); + } + + void PR_SS__print_out_measurements() @@ -891,20 +454,23 @@ MEAS__Print_Hists_for_Plugin_Meas; } -/*This is run in the main thread, as part of the PR__shutdown() call - * It frees any memory allocated from the OS +/*This waits for the OS threads in the PR system to end. Causing them to end + * has to be done separately (haven't worked out details as of this comment) */ void -PR_SS__cleanup_at_end_of_shutdown() - { - //All the environment data has been allocated with PR__malloc, so just - // free the memory obtained by PR__malloc, then free the top env. - //These are the only two that use system free - PR_ext__free_free_list( _PRTopEnv->freeLists ); - free( (void *)_PRTopEnv ); +PR_SS__wait_for_PR_to_shutdown() + { + //wait for all to complete + int coreIdx; + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) + { + pthread_join( coreCtlrThdHandles[coreIdx], NULL ); + } } +//============================ + /*Am trying to be cute, avoiding IF statement in coreCtlr that checks for * a special shutdown slaveVP. Ended up with extra-complex shutdown sequence. *This function has the sole purpose of setting the stack and framePtr diff -r bc5030385120 -r 40e7625e57bd PR__WL.c --- a/PR__WL.c Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__WL.c Sat Mar 02 09:43:45 2013 -0800 @@ -24,8 +24,10 @@ - -inline +/*As of Feb 2013, doesn't use magic number -- only one ID shared across all + * langlets + */ +inline int32 * PR__give_ID_from_slave( SlaveVP *animSlv, int32 magicNumber ) { @@ -34,9 +36,9 @@ inline int32 * -PR__give_ID_from_task( void *_task ) - { PRMetaTask task; - task = ((PRMetaTask *)_task)[-1]; +PR__give_ID_from_lang_meta_task( void *_task ) + { PRMetaTask *task; + task = PR_int__give_prolog_of_lang_meta_task(_task); return task->ID; } @@ -99,8 +101,8 @@ * pears -- making that suspend the last thing in the Slv's trace. */ void -PR_WL__send_end_slave_req( RequestHandler handler, SlaveVP *slaveToDissipate, - int32 magicNum ) +PR_WL__send_end_slave_req( void *langReq, RequestHandler handler, + SlaveVP *slaveToDissipate, int32 magicNum ) { PRReqst req; req.reqType = SlvDissipate; @@ -136,11 +138,11 @@ SlaveVP *animSlv, int32 magicNum ) { PRReqst req; - req.reqType = TaskEnd; - req.langReq = langReq; - req.handler = handler; + req.reqType = TaskEnd; + req.langReq = langReq; + req.handler = handler; req.langMagicNumber = magicNum; - animSlv->request = &req; + animSlv->request = &req; PR_WL__suspend_slaveVP_and_send_req( animSlv ); } @@ -160,7 +162,7 @@ PR_WL__add_lang_request_in_mallocd_PRReqst( void *langReqData, SlaveVP *callingSlv ) { PRReqst *req; -//WARNING: not update.. may be buggy +//WARNING: not updated.. may be buggy req = PR_int__malloc( sizeof(PRReqst) ); req->reqType = Language; req->langReq = langReqData; @@ -168,7 +170,8 @@ callingSlv->request = req; } -inline int32 * +inline +int32 * PR_WL__create_taskID_of_size( int32 numInts ) { int32 *taskID; @@ -182,7 +185,8 @@ * to plugin *Then it does suspend, to cause request to be sent. */ -inline void +inline +void PR_WL__send_lang_request( void *langReqData, RequestHandler handler, SlaveVP *callingSlv, int32 magicNum ) { PRReqst req; @@ -197,6 +201,19 @@ PR_WL__suspend_slaveVP_and_send_req( callingSlv ); } +inline +void +PR_WL__send_lang_shutdown_request( SlaveVP *callingSlv, int32 magicNum ) + { PRReqst req; + + req.reqType = LangShutdown; + req.langMagicNumber = magicNum; + req.nextReqst = NULL; + callingSlv->request = &req; + + PR_WL__suspend_slaveVP_and_send_req( callingSlv ); + } + /*This sends a PRLang request -- for probe, exception, and so on.. * @@ -221,7 +238,7 @@ void PR_WL__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ) { PRReqst req; - PRServReq langReq; + PRServiceReq langReq; req.reqType = Language; req.langReq = &langReq; diff -r bc5030385120 -r 40e7625e57bd PR__WL.h --- a/PR__WL.h Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__WL.h Sat Mar 02 09:43:45 2013 -0800 @@ -34,33 +34,64 @@ * aren't meant for use in wrapper libraries, because they are themselves * wrapper-library calls! */ -//========== Startup and shutdown ========== + +//============== Top level Fns called from main =============== void PR__start(); -SlaveVP* -PR_SS__create_shutdown_slave(); +PRProcess * +PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ); void -PR_SS__shutdown(); +PR__end_seedVP( SlaveVP *seedSlv ); void -PR_SS__cleanup_at_end_of_shutdown(); +PR__end_process_from_inside( SlaveVP *seedSlv ); + +void * +PR__give_results_from_process_when_ready( PRProcess *process ); void -PR_SS__register_langlets_langEnv( PRLangEnv *langEnv, SlaveVP *seedVP, int32 VSs_MAGIC_NUMBER ); +PR__wait_for_process_to_end( PRProcess *process ); +fixme; //process->hasWaitingToEnd + +void +PR__wait_for_all_activity_to_end(); + +void +PR__shutdown(); + +#define \ +PR__create_taskID_of_size PR_WL__create_taskID_of_size + +inline +int32 * +PR__give_ID_from_slave( SlaveVP *animSlv, int32 magicNumber ); + +inline +int32 * +PR__give_ID_from_lang_meta_task( void *_task ); + +#define \ +PR__malloc PR_WL__malloc + +#define \ +PR__free PR_WL__free + + //============== include internally used fn prototypes ================ #include "PR__int.h" -//============== =============== -inline -SlaveVP * -PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ); +#define \ +PR_WL__create_slaveVP PR_int__create_slaveVP_helper +#define \ +PR_WL__give_lang_meta_task_from_slave PR_int__give_lang_meta_task_from_slave -#define PR_WL__create_slaveVP PR_int__create_slaveVP_helper +#define \ +PR_WL__give_prolog_of_lang_meta_task PR_int__give_prolog_of_lang_meta_task //============== Request Related =============== @@ -86,13 +117,12 @@ inline void PR_WL__send_service_request( void *langReqData, SlaveVP *callingSlv ); -PRReqst * -PR_PI__take_next_request_out_of( SlaveVP *slaveWithReq ); -//#define PR_PI__take_next_request_out_of( slave ) slave->requests +inline void +PR_WL__send_lang_shutdown_request( SlaveVP *callingSlv, int32 magicNum ); -//inline void * -//PR_PI__take_lang_reqst_from( PRReqst *req ); -#define PR_PI__take_lang_reqst_from( req ) req->langReqData +inline +int32 * +PR_WL__create_taskID_of_size( int32 numInts ); //======================== MEASUREMENT ====================== uint64 @@ -106,15 +136,7 @@ PR_WL__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); #define PR_App__throw_exception PR_WL__throw_exception -#define implement_me printf("Unimpl Fn: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) -//#define fix_me printf("Fix me at: \n%s \n%s : %s\n", __FILE__, __FUNCTION__, __LINE__) -//========================= PR request handlers ======================== -void inline -handleMakeProbe( PRServReq *langReq, void *langEnv ); - -void inline -handleThrowException( PRServReq *langReq, void *langEnv ); //======================================================================= //========================= Services ======================= diff -r bc5030385120 -r 40e7625e57bd PR__int.c --- a/PR__int.c Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__int.c Sat Mar 02 09:43:45 2013 -0800 @@ -73,17 +73,15 @@ newSlv = PR_int__create_slaveVP_helper( fnPtr, dataParam ); - int32 * - langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); - langDatas[0] = NUM_IN_COLLECTION; //size held in prolog - newSlv->langDatas = &(langDatas[1]); //skip over the size + newSlv->langDatas = + (PRLangData **)PR_int__make_collection_of_size( NUM_IN_COLLECTION ); - int32 * - metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); - metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog - newSlv->metaTasks = &(metaTasks[1]); + newSlv->metaTasks = + (PRMetaTask **) PR_int__make_collection_of_size( NUM_IN_COLLECTION ); process->numLiveGenericSlvs += 1; + + return newSlv; } @@ -98,16 +96,13 @@ retSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL ); retSlv->typeOfVP = SlotTaskSlv; - int32 * - langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); - langDatas[0] = NUM_IN_COLLECTION; //size held in prolog - retSlv->langDatas = &(langDatas[1]); //skip over the size + + retSlv->langDatas = + (PRLangData **) PR_int__make_collection_of_size( NUM_IN_COLLECTION ); - int32 * - metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); - metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog - retSlv->metaTasks = &(metaTasks[1]); - + retSlv->metaTasks = + (PRMetaTask **) PR_int__make_collection_of_size( NUM_IN_COLLECTION ); + return retSlv; } @@ -145,29 +140,34 @@ * either a recycled free task slave that finished it's task and has been * idle in the recycle queue, or else create a new slave to be the slot slave. *The master only calls this with a slot slave that needs to be replaced. + * + *The master continues after this call, handing the converted Free task slave + * to a request handler, which places the converted slave into the langlet's + * env, so it will eventually resume */ -inline void -PR_int__replace_with_new_slot_slv( SlaveVP *requestingSlv, PRProcess *process ) +inline +void +PR_int__replace_with_new_slot_slv( SlaveVP *oldSlotSlv ) { SlaveVP *newSlotSlv; - + //get a new slave to be the slot slave - newSlotSlv = PR_int__get_recycled_slot_slave( process ); + newSlotSlv = PR_int__get_recycled_slot_slave(); //a slot slave is pinned to a particular slot on a particular core //Note, this happens before the request is seen by handler, so nothing // has had a chance to change the coreAnimatedBy or anything else.. - newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo; - newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy; + newSlotSlv->animSlotAssignedTo = oldSlotSlv->animSlotAssignedTo; + newSlotSlv->coreAnimatedBy = oldSlotSlv->coreAnimatedBy; //put it into the slot slave matrix - int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; - int32 coreNum = requestingSlv->coreAnimatedBy; + int32 slotNum = oldSlotSlv->animSlotAssignedTo->slotIdx; + int32 coreNum = oldSlotSlv->coreAnimatedBy; _PRTopEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv; //Fix up requester, to be an extra slave now (but not an ended one) // because it's active, doesn't go into freeTaskSlvRecycleQ - requestingSlv->typeOfVP = FreeTaskSlv; - requestingSlv->processSlaveIsIn = process; + //Note that process was set when task was assigned to the slot slave.. + oldSlotSlv->typeOfVP = FreeTaskSlv; } void idle_fn(void* data, SlaveVP *animatingSlv) @@ -241,31 +241,42 @@ PR_int__free( slave ); } -/*This calls recycle handler registered for each langlet's lang data and meta - * task. It also recycles the slave struct. +/*This calls the freer registered for each langlet's lang data and meta + * task. Then it makes the collections empty. It also recycles the slave + * struct. + *Note: it does not clear "next in coll" pointers in the coll elements! * *DOES NOT DECREMENT NUMBER OF LIVE SLAVES IN PROCESS - * - *This assumes that each slave has an array of + * + *Note, the fn applied to all elements of collections checks the "don't delete" + * flag in the lang data and the meta task.. so, if an alternative way of + * freeing the slaveVP struct is created, it should handle the "don't delete" + * flag. (although, an "abort" cleanup should ignore the don't delete flag) */ void -PR_int__recycle_slave( SlaveVP *slave ) +PR_int__recycle_slaveVP( SlaveVP *slave ) { PR_int__apply_Fn_to_all_in_collection( &freeLangDataAsElem, (PRCollElem**) slave->langDatas ); PR_int__apply_Fn_to_all_in_collection( &freeMetaTaskAsElem, (PRCollElem**) slave->metaTasks ); + //now, set the collections to "empty" + PR_int__set_collection_to_empty((PRCollElem**) slave->langDatas); + PR_int__set_collection_to_empty((PRCollElem**) slave->metaTasks); writePrivQ( slave, _PRTopEnv->slaveRecycleQ ); } /*Receives a protoLangData, but in the form of a void, so have to cast + *First checks the "no delete" flag.. */ void freeLangDataAsElem( void *elem ) { PRLangData *protoLangData; protoLangData = (PRLangData *)elem; //recycler actually receives the prolog. + if( protoLangData->goAheadAndFree == FALSE ) + return; //apply the free fn that's stored in the lang data prolog //Note: freeing whole slave, so no need to remove from collection @@ -285,6 +296,9 @@ protoMetaTask = (PRMetaTask *)elem; //recycler receives the prolog, and must call //a PR Fn to convert prolog to lang-specific version. + if( protoMetaTask->goAheadAndFree == FALSE ) + return; + //apply the free fn that's stored in the meta task prolog (*(protoMetaTask->freer))( PR_int__give_lang_meta_task_of_prolog(protoMetaTask) ); } @@ -305,29 +319,34 @@ return (PRLangEnv *) &(((PRLangEnv *)langEnv)[-1]); } -inline +//inline void * -PR_int__create_lang_env_in_process( int32 size, PRProcess process, int32 magicNum ) +PR_int__create_lang_env_in_process( int32 numBytes, PRProcess *process, int32 magicNum ) { PRLangEnv *retEnv; PRCollElem **langEnvs; //make the new lang env, with room for the prolog - retEnv = PR_int__malloc( sizeof(PRLangEnv) + size ); + retEnv = PR_int__malloc( sizeof(PRLangEnv) + numBytes ); + retEnv->chainedLangEnv = NULL; //used while inserting into langEnvs + retEnv->langMagicNumber = magicNum; //used while inserting into langEnvs + retEnv->processEnvIsIn = process; + retEnv->numLiveWork = 0; + retEnv->waitingForWorkToEndQ = makePrivQ(); //process has a PR Collection of lang envs -- get it and insert into it langEnvs = (PRCollElem **)process->langEnvs; PR_int__insert_elem_into_collection( (PRCollElem *)retEnv, langEnvs, magicNum); - int32 idxInProcess = process->numLangEnvs; - process->langEnvsList[idxInProcess] = retEnv; + int32 idxInProcess = process->numLangEnvs; //index starts at 0 for first lang + process->protoLangEnvsList[idxInProcess] = retEnv; retEnv->idxInProcess = idxInProcess; process->numLangEnvs += 1; - return &(retEnv[1]); //skip over prolog + return (void *)&(retEnv[1]); //skip over prolog } inline void * -PR_int__free_lang_env( void *langEnv ) +PR_int__remove_lang_env_from_process_and_free( void *langEnv ) { PRLangEnv *protoLangEnv = PR_int__give_proto_lang_env( langEnv ); PRCollElem **langEnvs; PRLangEnv **langEnvsList; @@ -335,11 +354,11 @@ //process has a PR Collection of lang envs -- get it and remove env PRProcess *process = protoLangEnv->processEnvIsIn; langEnvs = (PRCollElem **)process->langEnvs; - PR_int__remove_elem_from_collection( (PRCollElem *)protoLangEnv, langEnvs ); + PR_int__remove_elem_from_collection( protoLangEnv->langMagicNumber, langEnvs ); int32 count, idx; idx = protoLangEnv->idxInProcess; - count = (process->numLangEnvs - idx - 1) * sizeof(PRLangEnv *); - memmove( langEnvsList[idx], langEnvsList[idx+1], count); + count = (process->numLangEnvs - idx) * sizeof(PRLangEnv *);//idx starts at 0 + memmove( &(langEnvsList[idx]), &(langEnvsList[idx+1]), count); PR_int__free( protoLangEnv ); } @@ -362,7 +381,7 @@ PRLangEnv * PR_int__give_proto_lang_env_for_slave( SlaveVP *slave, int32 magicNum ) { - return PR_int__give_proto_lang_env_for_process( slave->processSlaveIsIn, magicNum ); + return PR_int__give_proto_lang_env_from_process( slave->processSlaveIsIn, magicNum ); } inline @@ -380,7 +399,7 @@ } inline PRLangEnv * -PR_int__give_proto_lang_env_for_process( PRProcess *process, int32 magicNum ) +PR_int__give_proto_lang_env_from_process( PRProcess *process, int32 magicNum ) { PRLangEnv *retLangEnv; PRCollElem **langEnvs; @@ -453,25 +472,29 @@ */ inline void -PR_int__put_task_into_slot( PRMetaTask *task, PRProcess *process, AnimSlot *slot ) +PR_int__put_task_into_slot( void *langMetaTask, AnimSlot *slot ) { int32 slotNum, coreNum; SlaveVP *slotSlv; + PRMetaTask *protoMetaTask; + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); + //get the slot slave to assign the task to.. slotNum = slot->slotIdx; coreNum = slot->coreSlotIsOn; slotSlv = _PRTopEnv->slotTaskSlvs[coreNum][slotNum]; //point slave to task's function - PR_int__reset_slaveVP_to_TopLvlFn( slotSlv, task->topLevelFn, task->initData ); - PR_int__insert_meta_task_into_slave( task, slotSlv ); + PR_int__reset_slaveVP_to_TopLvlFn( slotSlv, protoMetaTask->topLevelFn, protoMetaTask->initData ); + PR_int__insert_meta_task_into_slave( protoMetaTask, slotSlv ); + slotSlv->processSlaveIsIn = protoMetaTask->processTaskIsIn; PR_int__put_slave_into_slot( slotSlv, slot ); } //========================== inline PRMetaTask * -PR_int__give_prolog_of_task( void *task ) +PR_int__give_prolog_of_lang_meta_task( void *task ) { return (PRMetaTask *) &(((PRMetaTask *)task)[-1]); } @@ -497,19 +520,33 @@ retMetaTask->taskType = SlotTask; //just common default retMetaTask->ID = NULL; retMetaTask->freer = freer; + retMetaTask->goAheadAndFree = TRUE; return retMetaTask; //skip over prolog } -/*Might never need this fn -- think the slave dissipator does this work +/*Calls the lang's freer, which is pointed to, and also removes from collection + */ +void +PR_int__free_lang_meta_task_and_remove_from_coll( void *langMetaTask) + { PRMetaTask *protoMetaTask; + + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); + PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber, + (PRCollElem **) protoMetaTask->slaveAssignedTo->metaTasks ); + + (*protoMetaTask->freer)(langMetaTask); + PR_int__free( protoMetaTask ); + } + +/*Just calls the lang's freer, and frees the malloc'd meta-task chunk. Should + * already have been removed from slave's collection and all queues holding it */ void PR_int__free_lang_meta_task( void *langMetaTask) { PRMetaTask *protoMetaTask; - protoMetaTask = PR_int__give_prolog_of_task( langMetaTask ); - PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber, - protoMetaTask->slaveAssignedTo->metaTasks ); + protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask ); (*protoMetaTask->freer)(langMetaTask); PR_int__free( protoMetaTask ); @@ -578,22 +615,16 @@ metaTasks = (PRCollElem **)slave->metaTasks; retMetaTask = PR_int__lookup_elem_in_collection( magicNum, metaTasks ); if( retMetaTask != NULL ) - return &(retMetaTask[1]); //skip over prolog + return PR_int__give_lang_meta_task_of_prolog(retMetaTask); //skip over prolog else - { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave ); + { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, magicNum ); if(protoLangEnv->langMetaTaskCreator == NULL) - PR_int__throw_exception("register a meta task creator"); + PR_int__error("register a meta task creator"); //This will call return (*protoLangEnv->langMetaTaskCreator)( slave ); } } -inline -SlaveVP * -PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ) - { PRMetaTask *metaTask = &(((PRMetaTask*)langMetaTask)[-1]); - return metaTask->slaveAssignedTo; - } //================== langData ============================= inline @@ -628,6 +659,7 @@ retLangData->chainedLangData = NULL; retLangData->langMagicNumber = magicNum; retLangData->freer = freer; + retLangData->goAheadAndFree = TRUE; retLangData->slaveAssignedTo = slave; //multilang has a "collection" of lang datas inside the slave @@ -642,7 +674,7 @@ protoLangData = PR_int__give_prolog_of_lang_data( langData ); PR_int__remove_elem_from_collection( protoLangData->langMagicNumber, - protoLangData->slaveAssignedTo->langDatas ); + (PRCollElem **) protoLangData->slaveAssignedTo->langDatas ); (*protoLangData->freer)(langData); PR_int__free( protoLangData ); @@ -660,9 +692,9 @@ if( retLangData != NULL ) return &( retLangData[1] ); //skip over prolog else - { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave ); + { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, magicNum ); if(protoLangEnv->langDataCreator == NULL) - PR_int__throw_exception("register a lang data creator"); + PR_int__error("register a lang data creator"); //This will call PR_PI__create_lang_data_in_slave return (*protoLangEnv->langDataCreator)( slave ); } @@ -670,6 +702,22 @@ //=============================================== +PRCollElem ** //return an array of pointers +PR_int__make_collection_of_size( int32 numInColl ) + { int32 *prolog; + PRCollElem **coll; + //Note using size of a pointer to a coll element + int32 numBytes = sizeof(int32) + numInColl * sizeof(PRCollElem *); + prolog = PR_WL__malloc( numBytes ); + + //operation of collection relies upon initial entries being NULL + memset(prolog, ZERO, numBytes>>2); //BUG: if size not multiple of 4 + + prolog[0] = numInColl; + coll = (PRCollElem **)&(prolog[1]); + return coll; + } + inline void PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash ) @@ -733,32 +781,51 @@ test = test->chained; if( test == NULL ) return; //not found, nothing to remove } - if( prev == NULL) + if( prev == NULL) //is first elem in chain, so modify ptr in array { coll[idx] = coll[idx]->chained; return; } - else + else //remove link from chain { prev->chained = test->chained; return; } } + +/*The function is allowed to modify its OWN chaining.. this takes the next + * in chain before calling the function (useful when the function conditionally + * frees) + */ inline void -PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem *coll ) +PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem **coll ) { int32 idx, numIdxsInColl; - PRCollElem *test; + PRCollElem *test, *chainedTest; numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs - for( idx = 0; idx < ; idx++ ) + //march down array of elements, for each, march down linked chain of elems + for( idx = 0; idx < numIdxsInColl; idx++ ) { test = coll[idx]; while( test != NULL ) - { (*Fn)((void *)test); - test = test->chained; + { chainedTest = test->chained; //Fn may destroy test or change test->chained + (*Fn)((void *)test); + test = chainedTest; } } } +/*Just sets all entries to NULL -- doesn't modify chaining of any elements + * that may be left in the collection.. + */ +inline +void +PR_int__set_collection_to_empty( PRCollElem **coll ) + { int32 numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs + memset( coll, 0, numIdxsInColl * sizeof(PRCollElem *) ); + } +//========================================== + + //========================================== /*Later, improve this -- for now, just exits the application after printing @@ -772,13 +839,20 @@ exit(1); } +void +PR_int__error( char *msgStr ) + { + printf("%s",msgStr); + fflush(stdin); + exit(1); + } -inline + char * PR_int__strDup( char *str ) { char *retStr; - if( str == NULL ) return (char *)NULL; + if( str == NULL ) return NULL; retStr = (char *)PR_int__malloc( strlen(str) + 1 ); strcpy( retStr, str ); @@ -793,13 +867,16 @@ PR_int__get_master_lock() { int32 *addrOfMasterLock; + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + return; + #endif + addrOfMasterLock = &(_PRTopEnv->masterLock); int numTriesToGetLock = 0; int gotLock = 0; MEAS__Capture_Pre_Master_Lock_Point; - while( !gotLock ) //keep going until get master lock { numTriesToGetLock++; //if too many, means too much contention diff -r bc5030385120 -r 40e7625e57bd PR__int.h --- a/PR__int.h Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__int.h Sat Mar 02 09:43:45 2013 -0800 @@ -20,10 +20,6 @@ */ inline -PRMetaTask * -PR_int__create_generic_slave_meta_task( void *initData ); - -inline void PR_int__reset_slaveVP_to_TopLvlFn( SlaveVP *slaveVP, TopLevelFnPtr fnPtr, void *dataParam); @@ -64,7 +60,7 @@ inline void -PR_int__put_task_into_slot( PRMetaTask *task, PRProcess *process, AnimSlot *slot ); +PR_int__put_task_into_slot( void *task, AnimSlot *slot ); inline void @@ -74,16 +70,10 @@ PRHandle__ServiceReq( SlaveVP *requestingSlv ); void -PR_WL__suspend_slaveVP_and_send_req( SlaveVP *animatingSlv ); - -void -PR_int__dissipate_slaveVP__SL( SlaveVP *animatingSlv ); - -void PR_int__free_slaveVP( SlaveVP *slave ); void -PR_int__recycle_slave( SlaveVP *slave ); +PR_int__recycle_slaveVP( SlaveVP *slave ); void freeLangDataAsElem( void *elem ); @@ -91,6 +81,10 @@ void freeMetaTaskAsElem( void *elem ); + +//============================= +//=== Lange Env +//= inline void * PR_int__give_lang_env( PRLangEnv *protoLangEnv ); @@ -99,13 +93,13 @@ PRLangEnv * PR_int__give_proto_lang_env( void *langEnv ); -inline +//inline void * PR_int__create_lang_env_in_process( int32 size, PRProcess *process, int32 magicNum ); inline void * -PR_int__free_lang_env( void *langEnv ); +PR_int__remove_lang_env_from_process_and_free( void *langEnv ); inline void * @@ -114,42 +108,28 @@ inline void * PR_int__give_lang_env_for_slave( SlaveVP *slave, int32 magicNum ); -#define PR_PI__give_lang_env_for PR_int__give_lang_env_for_slave -#define PR_SS__give_lang_env_for_slave PR_int__give_lang_env_for_slave //No WL version -- not safe! if use env in WL, be sure data rd & wr is stable inline PRLangEnv * -PR_int__give_proto_lang_env_for_slave__ML( SlaveVP *slave, int32 magicNumber ); -#define PR_PI__give_proto_lang_env_for PR_int__give_proto_lang_env_for_slave__ML -#define PR_SS__give_proto_lang_env_for_slave PR_int__give_proto_lang_env_for_slave__ML +PR_int__give_proto_lang_env_for_slave( SlaveVP *slave, int32 magicNumber ); //No WL version -- not safe! if use env in WL, be sure data rd & wr is stable inline void * PR_int__give_lang_env_from_process( PRProcess *process, int32 magicNum ); -#define PR_PI__give_lang_env_from_process PR_int__give_lang_env_from_process -#define PR_SS__give_lang_env_from_process PR_int__give_lang_env_from_process -//#define PR_WL__give_lang_env_from_process PR_int__give_lang_env_from_process //No WL version -- not safe! if use env in WL, be sure data rd & wr is stable inline PRLangEnv * -PR_int__give_proto_lang_env_for_process( PRProcess *process, int32 magicNum ); +PR_int__give_proto_lang_env_from_process( PRProcess *process, int32 magicNum ); -/* -inline -void -PR_int__set_work_in_lang_env( void *_langEnv ); - -inline -void -PR_int__clear_work_in_lang_env( void *_langEnv ); - */ - +//======================= +//=== Meta Task +//= inline PRMetaTask * -PR_int__give_prolog_of_task( void *task ); +PR_int__give_prolog_of_lang_meta_task( void *task ); inline void * @@ -157,11 +137,19 @@ inline void * -PR_int__create_lang_meta_task( int32 size, int32 magicNum ); +PR_int__create_lang_meta_task( int32 size, LangMetaTaskFreer freer, int32 magicNum ); inline void * -PR_int__create_lang_meta_task_in_slave( int32 size, SlaveVP *slave, int32 magicNum ); +PR_int__create_lang_meta_task_in_slave( int32 size, LangMetaTaskFreer freer, + SlaveVP *slave, int32 magicNum ); + +inline +PRMetaTask * +PR_int__create_generic_slave_meta_task( void *initData ); + +void +PR_int__free_lang_meta_task_and_remove_from_coll( void *langMetaTask ); inline void @@ -174,28 +162,35 @@ inline void * PR_int__give_lang_meta_task_from_slave( SlaveVP *slave, int32 magicNumer ); -//#define PR_int__give_lang_meta_task_from_slave__ML( slave, magicNumber )\ - slave->metaTask->langMetaTask; -#define PR_PI__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave -#define PR_SS__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave -#define PR_WL__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave inline SlaveVP * PR_PI__give_slave_lang_meta_task_is_assigned_to( void *langMetaTask ); +//============== +//=== Lang Data +//= inline void * -PR_PI__create_lang_data_in_slave( int32 size, SlaveVP *slave, int32 magicNum ); +PR_PI__create_lang_data_in_slave( int32 size, LangDataFreer freer, + SlaveVP *slave, int32 magicNum ); inline void * PR_int__give_lang_data_from_slave( SlaveVP *slave, int32 magicNumer ); -#define PR_PI__give_lang_data PR_int__give_lang_data_from_slave -#define PR_SS__give_lang_data PR_int__give_lang_data_from_slave #define PR_WL__give_lang_data PR_int__give_lang_data_from_slave inline +void * +PR_int__give_lang_data_of_prolog( PRLangData *langData); + +//================================================== +//=== Collection +//= +PRCollElem ** //return an array of pointers +PR_int__make_collection_of_size( int32 numInColl ); + +inline void PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash ); @@ -209,19 +204,25 @@ inline void -PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem *coll ); +PR_int__set_collection_to_empty( PRCollElem **coll ); + +inline +void +PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem **coll ); + +//=========== +//=== +//= +void +PR_int__error( char *msgStr ); void PR_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); -#define PR_PI__throw_exception PR_int__throw_exception -inline char * +char * PR_int__strDup( char *str ); inline void -PR_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock ); - -inline void PR_int__get_master_lock(); #define PR_int__release_master_lock() _PRTopEnv->masterLock = UNLOCKED diff -r bc5030385120 -r 40e7625e57bd PR__structs.h --- a/PR__structs.h Tue Feb 05 20:23:27 2013 -0800 +++ b/PR__structs.h Sat Mar 02 09:43:45 2013 -0800 @@ -17,7 +17,10 @@ //================================ Typedefs ================================= -// +//=== +//= +#define ZERO 0 + typedef unsigned long long TSCount; typedef struct _AnimSlot AnimSlot; @@ -30,13 +33,13 @@ typedef struct _PRLangData PRLangData; //a prolog typedef struct _PRCollElem PRCollElem; //generic form of the prologs -typedef SlaveVP *(*SlaveAssigner) ( void *, AnimSlot* ); //langEnv, slot for HW info +typedef bool32 (*SlaveAssigner) ( void *, AnimSlot* ); //langEnv, slot for HW info typedef void (*RequestHandler) ( void *, SlaveVP *, void * ); //req, slv, langEnv typedef void *(*CreateHandler) ( void *, SlaveVP *, void * ); //req, slv, langEnv typedef void (*LangShutdownHdlr) ( void * ); //langEnv typedef void *(*LangDataCreator) ( SlaveVP * ); typedef void (*LangDataFreer) ( void * ); //lang data to free -typedef void *(*LangMetaTaskCreator)( SlaveVP * ); +typedef void *(*LangMetaTaskCreator)( SlaveVP * ); //when slave has no meta task for magic num typedef void (*LangMetaTaskFreer) ( void * ); //lang meta task to free typedef void (*MakeSlaveReadyFn) ( SlaveVP *, void * ); //slave and langEnv typedef void (*MakeTaskReadyFn) ( void *, void * ); //langTask and langEnv @@ -73,7 +76,7 @@ void *resultToReturn; PRLangEnv **langEnvs; //used as a hash table - PRLangEnv **langEnvsList; //for fast linear scan of envs + PRLangEnv **protoLangEnvsList; //for fast linear scan of envs int32 numLangEnvs; //for fast linear scan of envs SlaveVP *seedSlv; @@ -86,6 +89,7 @@ //These are used to coord with an OS thread waiting for process to end + bool32 hasWaitingToEnd; bool32 executionIsComplete; pthread_mutex_t doneLock; pthread_cond_t doneCond; @@ -124,9 +128,13 @@ Service, //To invoke a PR provided equivalent of a language request (ex: probe) Hardware, IO, - OSCall + OSCall, + LangShutdown, + ProcessEnd, + PRShutdown }; + struct _PRReqst { enum PRReqstType reqType;//used for special forms that have PR behavior @@ -149,7 +157,7 @@ }; //PRReqst -enum PRServReqType //These are equivalent to lang requests, but for +enum PRServiceReqType //These are equivalent to lang requests, but for { // PR's services available directly to app, like OS make_probe = 1, // and probe services -- like a PR-wide built-in lang throw_excp, @@ -158,13 +166,13 @@ }; typedef struct - { enum PRServReqType reqType; + { enum PRServiceReqType reqType; SlaveVP *requestingSlv; char *nameStr; //for create probe char *msgStr; //for exception void *exceptionData; } -PRServReq; +PRServiceReq; //==================== Core data structures =================== @@ -192,9 +200,9 @@ FreeTaskSlv, //When a suspended task ends, the slave becomes this GenericSlv, //the VP is explicitly seen in the app code, or task suspends SeedSlv, - Master, - Shutdown, - Idle + Master_VP, + ShutdownVP, + IdleVP }; /*This structure embodies the state of a slaveVP. It is reused for masterVP @@ -228,8 +236,8 @@ //For language specific data that needs to be in the slave //These are accessed directly for single-lang, but multi-lang places // a holder here instead, then uses magic num to get lang's version - void *langDatas; //Lang saves lang-specific things in slave here - void *metaTasks; + PRLangData **langDatas; //Lang saves lang-specific things in slave here + PRMetaTask **metaTasks; //=========== MEASUREMENT STUFF ========== MEAS__Insert_Meas_Fields_into_Slave; @@ -335,16 +343,6 @@ LangMetaTaskCreator langMetaTaskCreator; MakeSlaveReadyFn makeSlaveReadyFn; MakeTaskReadyFn makeTaskReadyFn; -/* - CreateTaskHdlr createTaskHdlr; - RequestHandler endTaskHdlr; - CreateSlvHdlr createSlaveHdlr; - RequestHandler dissipateSlaveHdlr; - - LangDataFreer langDataFreer; - LangMetaTaskFreer langMetaTaskFreer; - RequestHandler langDataInitializer; - */ //when multi-lang, master polls lang env's to find one with work in it.. // in single-lang case, flag ignored, master always asks lang for work @@ -354,7 +352,9 @@ int32 idxInProcess; //index into array of langEnvs in the process int32 numReadyWork; - fixme; //make make_ready update the process's numEnvs with work + + int32 numLiveWork; + PrivQueueStruc *waitingForWorkToEndQ; }; //PRLangEnv -- this is the prolog of every lang's lang env @@ -371,10 +371,12 @@ //============================================================= enum PRTaskType taskType; int32 *ID; //is standard PR ID - SlaveVP *slaveAssignedTo; //no valid until task animated + PRProcess *processTaskIsIn; + SlaveVP *slaveAssignedTo; //not valid until task animated TopLevelFnPtr topLevelFn; //This is the Fn executes as the task void *initData; //The data taken by the function LangMetaTaskFreer freer; + bool32 goAheadAndFree; //NOTE: info needed for "wait" functionality is inside lang's metaTask }; @@ -386,6 +388,7 @@ PRLangData *chainedLangData; //============================================================= LangDataFreer freer; + bool32 goAheadAndFree; SlaveVP *slaveAssignedTo; }; //PRLangData -- this is the prolog of each lang's lang data @@ -399,16 +402,6 @@ -//The language env of PR's services langlet -typedef struct - { - PrivQueueStruc *slavesReadyToResumeQ; //Shared (slaves not pinned) - PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) - } -PRServLangEnv; - - - //========================= Extra Stuff Data Strucs ======================= typedef struct { diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h --- a/Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h Sat Mar 02 09:43:45 2013 -0800 @@ -501,7 +501,7 @@ #define MEAS__Make_Meas_Hists_for_Language #endif -#define makeAMeasHist( idx, name, numBins, startVal, binWidth ) \ +#define makeAMeasHist( histInfo, idx, name, numBins, startVal, binWidth ) \ makeHighestDynArrayIndexBeAtLeast( _PRTopEnv->measHistsInfo, idx ); \ _PRTopEnv->measHists[idx] = \ makeFixedBinHist( numBins, startVal, binWidth, name ); diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Measurement_and_Stats/probes.c --- a/Services_Offered_by_PR/Measurement_and_Stats/probes.c Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Measurement_and_Stats/probes.c Sat Mar 02 09:43:45 2013 -0800 @@ -49,7 +49,7 @@ IntervalProbe * create_generic_probe( char *nameStr, SlaveVP *animSlv ) { - PRServReq reqData; + PRServiceReq reqData; reqData.reqType = make_probe; reqData.nameStr = nameStr; @@ -189,7 +189,7 @@ probe = _PRTopEnv->intervalProbes[ probeID ]; probe->schedChoiceWasRecorded = TRUE; probe->coreNum = animatingSlv->coreAnimatedBy; - probe->slaveID = animatingSlv->slaveID; + probe->slaveNum = animatingSlv->slaveNum; probe->slaveCreateSecs = animatingSlv->createPtInSecs; } @@ -265,8 +265,8 @@ if( probe->schedChoiceWasRecorded ) - { printf( "coreNum: %d, slaveID: %d, slaveVPCreated: %0.6f | ", - probe->coreNum, probe->slaveID, probe->slaveCreateSecs ); + { printf( "coreNum: %d, slaveNum: %d, slaveVPCreated: %0.6f | ", + probe->coreNum, probe->slaveNum, probe->slaveCreateSecs ); } if( probe->endSecs == 0 ) //just a single point in time diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Measurement_and_Stats/probes.h --- a/Services_Offered_by_PR/Measurement_and_Stats/probes.h Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Measurement_and_Stats/probes.h Sat Mar 02 09:43:45 2013 -0800 @@ -65,7 +65,7 @@ int32 schedChoiceWasRecorded; int32 coreNum; - int32 slaveID; + int32 slaveNum; float64 slaveCreateSecs; PROBES__Insert_timestamps_and_intervals_into_probe_struct; }; diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Memory_Handling/vmalloc.h --- a/Services_Offered_by_PR/Memory_Handling/vmalloc.h Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Memory_Handling/vmalloc.h Sat Mar 02 09:43:45 2013 -0800 @@ -54,24 +54,18 @@ void * PR_int__malloc( size_t sizeRequested ); -#define PR_PI__malloc PR_int__malloc -#define PR_SS__malloc PR_int__malloc void * PR_WL__malloc( int32 sizeRequested ); /*BUG: -- get master lock */ -#define PR_App__malloc PR_WL__malloc void * PR_int__malloc_aligned( size_t sizeRequested ); -#define PR_PI__malloc_aligned PR_int__malloc_aligned void PR_int__free( void *ptrToFree ); -#define PR_PI__free PR_int__free void PR_WL__free( void *ptrToFree ); -#define PR_App__free PR_WL__free diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/Measurement/PRServ_Measurement.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Services_Offered_by_PR/Services_Language/Measurement/PRServ_Measurement.h Sat Mar 02 09:43:45 2013 -0800 @@ -0,0 +1,16 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _PRServ_MEAS_H +#define _PRServ_MEAS_H + + + #define MEAS__Make_Meas_Hists_for_PRServ + +#endif /* */ + diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ.c --- a/Services_Offered_by_PR/Services_Language/PRServ.c Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Services_Language/PRServ.c Sat Mar 02 09:43:45 2013 -0800 @@ -4,6 +4,30 @@ * Licensed under BSD */ +//=========================================================================== +// +//=========================================================================== +/*These are the library functions *called in the application* + * + *There's a pattern for the outside sequential code to interact with the + * PR_HW code. + *The PR_HW system is inside a boundary.. every PRServ system is in its + * own directory that contains the functions for each of the processor types. + * One of the processor types is the "seed" processor that starts the + * cascade of creating all the processors that do the work. + */ + + +//=========================================================================== +// +//=========================================================================== +/*This file is for the built-in "services" or "utility" langlet, which starts + * automatically when a new process is created. The seed VP initially runs + * within this langlet's environment. + */ + +//=========================================================================== + #include #include #include @@ -11,26 +35,19 @@ #include "Queue_impl/PrivateQueue.h" #include "Hash_impl/PrivateHash.h" -#include "../../PR.h" #include "PRServ.h" +//#include "Measurement/PRServ_Counter_Recording.h" //========================================================================== +//=== prototypes for local helper functions +//= void PRServ__init_Helper(); + //========================================================================== -//=========================================================================== - - -/*These are the library functions *called in the application* - * - */ - - -//=========================================================================== - int32 PRServ__giveMinWorkUnitCycles( float32 percentOverhead ) { @@ -53,12 +70,12 @@ * saves jump point, and second jumps back several times to get reliable time */ void -PRServ__begin_primitive() - { PRServSemData *semData; +PRServ__begin_primitive( SlaveVP *animSlv ) + { PRServLangData *langData; - semData = (PRServSemData *)PR_WL__give_sem_data( animSlv, PRServ_MAGIC_NUMBER); + langData = (PRServLangData *)PR_WL__give_lang_data( animSlv, PRServ_MAGIC_NUMBER); - saveLowTimeStampCountInto( semData->primitiveStartTime ); + saveLowTimeStampCountInto( langData->primitiveStartTime ); } /*Just quick and dirty for now -- make reliable later @@ -67,251 +84,75 @@ * also to throw out any "weird" values due to OS interrupt or TSC rollover */ int32 -PRServ__end_primitive_and_give_cycles( SlaveVP animSlv ) +PRServ__end_primitive_and_give_cycles( SlaveVP *animSlv ) { int32 endTime, startTime; - PRServSemData *semData; + PRServLangData *langData; //TODO: fix by repeating time-measurement saveLowTimeStampCountInto( endTime ); - semData = (PRServSemData *)PR_WL__give_sem_data( animSlv, PRServ_MAGIC_NUMBER); - startTime = semData->primitiveStartTime; - return (endTime - startTime - 2*TSC_LOW_CYCLES); + langData = (PRServLangData *)PR_WL__give_lang_data( animSlv, PRServ_MAGIC_NUMBER); + startTime = langData->primitiveStartTime; + return (endTime - startTime); } - -//=========================================================================== - -SlaveVP * -PRServ__create_thread( TopLevelFnPtr fnPtr, void *initData, - SlaveVP *creatingThd ) - { - return PRServ__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID, - ANY_CORE, creatingThd ); +inline +int32 * +PRServ__give_self_taskID( SlaveVP *animSlv ) + { + return PR__give_ID_from_slave( animSlv, PRServ_MAGIC_NUMBER ); } -SlaveVP * -PRServ__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID, - SlaveVP *creatingThd ) - { - return PRServ__create_thread_w_ID_and_affinity( fnPtr, initData, thdID, - ANY_CORE, creatingThd ); + +/* + *This function returns information about the version of PR, the language + * the program is being run in, its version, and information on the + * hardware. + */ +char * +PRServ___give_environment_string() + { char *buffer = PR_WL__malloc(10000); + int32 j; + + j = sizeof(int32); //put total num chars here when done + //-------------------------- + j += sprintf(buffer+j, "#\n# >> Build information <<\n"); + j += sprintf(buffer+j, "# GCC VERSION: %d.%d.%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__); + j += sprintf(buffer+j, "# Build Date: %s %s\n", __DATE__, __TIME__); + + j += sprintf(buffer+j, "#\n# >> Hardware information <<\n"); + j += sprintf(buffer+j, "# Hardware Architecture: "); + #ifdef __x86_64 + j += sprintf(buffer+j, "x86_64"); + #endif //__x86_64 + #ifdef __i386 + j += sprintf(buffer+j, "x86"); + #endif //__i386 + j += sprintf(buffer+j, "\n"); + j += sprintf(buffer+j, "# Number of Cores: %d\n", NUM_CORES); + //-------------------------- + + //PR Plugins + j += sprintf(buffer+j, "#\n# >> PR Plugins <<\n"); + j += sprintf(buffer+j, "# Language : "); + j += sprintf(buffer+j, _LANG_NAME_); + j += sprintf(buffer+j, "\n"); + //Meta info gets set by calls from the language during its init, + // and info registered by calls from inside the application + j += sprintf(buffer+j, "# Assigner: %s\n", _PRTopEnv->metaInfo->assignerInfo); + + //-------------------------- + //Application + j += sprintf(buffer+j, "#\n# >> Application <<\n"); + j += sprintf(buffer+j, "# Name: %s\n", _PRTopEnv->metaInfo->appInfo); + j += sprintf(buffer+j, "# Data Set:\n%s\n",_PRTopEnv->metaInfo->inputInfo); + + ((int32 *)buffer)[0] = j - sizeof(int32); //insert the number of chars + //-------------------------- + return (char *) &(((int32 *)buffer)[1]); //return pointer to first char } -SlaveVP * -PRServ__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, - int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ) - { PRServSemReq reqData; - - //the semantic request data is on the stack and disappears when this - // call returns -- it's guaranteed to remain in the VP's stack for as - // long as the VP is suspended. - reqData.reqType = create_slave; //know type because in a PR create req - reqData.coreToAssignOnto = coreToAssignOnto; - - PR_WL__send_create_slaveVP_req( &reqData, fnPtr, initData, thdID, - creatingThd, PRServ_MAGIC_NUMBER ); - return creatingThd->dataRetFromReq; - } - -/*This is always the last thing done in the code animated by a thread VP. - * Normally, this would be the last line of the thread's top level function. - * But, if the thread exits from any point, it has to do so by calling - * this. - * - *It simply sends a dissipate request, which handles all the state cleanup. - */ -void -PRServ__end_thread( SlaveVP *thdToEnd ) - { - PR_WL__send_dissipate_req( thdToEnd, PRServ_MAGIC_NUMBER ); - } - - - -//=========================================================================== - - -//======================= task submit and end ============================== -/* - */ -void -PRServ__submit_task( PRServTaskType *taskType, void *args, SlaveVP *animSlv) - { PRServSemReq reqData; - - reqData.reqType = submit_task; - - reqData.taskType = taskType; - reqData.args = args; - reqData.callingSlv = animSlv; - - //Create task is a special form, so have to pass as parameters, the - // top-level-fn of task and the data for that fn, plus lang's req, - // animating slave, and lang's magic number - PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID, animSlv, PRServ_MAGIC_NUMBER ); - } - -void -PRServ__submit_task_with_ID( PRServTaskType *taskType, void *args, int32 *taskID, - SlaveVP *animSlv) - { PRServSemReq reqData; - - reqData.reqType = submit_task; - - reqData.taskType = taskType; - reqData.args = args; - reqData.callingSlv = animSlv; - - PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID, animSlv, PRServ_MAGIC_NUMBER ); - } - - -/*This call is the last to happen in every task. It causes the slave to - * suspend and get the next task out of the task-queue. Notice there is no - * assigner here.. only one slave, no slave ReadyQ, and so on.. - *Can either make the assigner take the next task out of the taskQ, or can - * leave all as it is, and make task-end take the next task. - *Note: this fits the case in the new PR for no-context tasks, so will use - * the built-in taskQ of new PR, and should be local and much faster. - * - *The task-stub is saved in the animSlv, so the request handler will get it - * from there, along with the task-type which has arg types, and so on.. - * - * NOTE: if want, don't need to send the animating SlaveVP around.. - * instead, can make a single slave per core, and coreCtrlr looks up the - * slave from having the core number. - * - *But, to stay compatible with all the other PR languages, leave it in.. - */ -void -PRServ__end_task( SlaveVP *animSlv ) - { PRServSemReq reqData; - - reqData.reqType = end_task; - reqData.callingSlv = animSlv; - - PR_WL__send_end_task_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); - } - - -/*Waits for all tasks that are direct children to end, then resumes calling - * task or thread - */ -void -PRServ__taskwait(SlaveVP *animSlv) - { - PRServSemReq reqData; - - reqData.reqType = taskwait; - reqData.callingSlv = animSlv; - - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); - } - - - -//========================== send and receive ============================ -// - -inline int32 * -PRServ__give_self_taskID( SlaveVP *animSlv ) - { - return PR__give_task_ID( animSlv, PRServ_MAGIC_NUMBER ); - } - -//================================ send =================================== - -void -PRServ__send_of_type_to( void *msg, const int32 type, int32 *receiverID, - SlaveVP *senderSlv ) - { PRServSemReq reqData; - - reqData.reqType = send_type_to; - - reqData.msg = msg; - reqData.msgType = type; - reqData.receiverID = receiverID; - reqData.senderSlv = senderSlv; - - reqData.nextReqInHashEntry = NULL; - - PR_WL__send_sem_request( &reqData, senderSlv, PRServ_MAGIC_NUMBER ); - - //When come back from suspend, no longer own data reachable from msg - } - -void -PRServ__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ) - { PRServSemReq reqData; - - reqData.reqType = send_from_to; - - reqData.msg = msg; - reqData.senderID = senderID; - reqData.receiverID = receiverID; - reqData.senderSlv = senderSlv; - - reqData.nextReqInHashEntry = NULL; - - PR_WL__send_sem_request( &reqData, senderSlv, PRServ_MAGIC_NUMBER ); - } - - -//================================ receive ================================ - -/*The "type" version of send and receive creates a many-to-one relationship. - * The sender is anonymous, and many sends can stack up, waiting to be - * received. The same receiver can also have send from-to's - * waiting for it, and those will be kept separate from the "type" - * messages. - */ -void * -PRServ__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ) - { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] ); - PRServSemReq reqData; - - reqData.reqType = receive_type_to; - - reqData.msgType = type; - reqData.receiverID = receiverID; - reqData.receiverSlv = receiverSlv; - - reqData.nextReqInHashEntry = NULL; - - PR_WL__send_sem_request( &reqData, receiverSlv, PRServ_MAGIC_NUMBER ); - - return receiverSlv->dataRetFromReq; - } - - - -/*Call this at the point a receiving task wants in-coming data. - * Use this from-to form when know senderID -- it makes a direct channel - * between sender and receiver. - */ -void * -PRServ__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ) - { - PRServSemReq reqData; - - reqData.reqType = receive_from_to; - - reqData.senderID = senderID; - reqData.receiverID = receiverID; - reqData.receiverSlv = receiverSlv; - - reqData.nextReqInHashEntry = NULL; - DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); - - PR_WL__send_sem_request( &reqData, receiverSlv, PRServ_MAGIC_NUMBER ); - - return receiverSlv->dataRetFromReq; - } - - - - //========================================================================== // /*A function singleton is a function whose body executes exactly once, on a @@ -329,22 +170,24 @@ void asm_write_ret_from_singleton(PRServSingleton *singletonPtrAddr); /*Fn singleton uses ID as index into array of singleton structs held in the - * semantic environment. + * language environment. */ void PRServ__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; // - reqData.reqType = singleton_fn_start; + reqData.reqType = prserv_singleton_fn_start; reqData.singletonID = singletonID; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleStartFnSingleton, + animSlv, PRServ_MAGIC_NUMBER ); if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton { - PRServSemEnv *semEnv = PR_WL__give_sem_env_for( animSlv, PRServ_MAGIC_NUMBER ); - asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); + PRServLangEnv *langEnv = + PR_int__give_lang_env_for_slave( animSlv, PRServ_MAGIC_NUMBER ); + asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID])); } } @@ -355,15 +198,16 @@ void PRServ__start_data_singleton( PRServSingleton **singletonAddr, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; if( *singletonAddr && (*singletonAddr)->hasFinished ) goto JmpToEndSingleton; - reqData.reqType = singleton_data_start; + reqData.reqType = prserv_singleton_data_start; reqData.singletonPtrAddr = singletonAddr; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleStartDataSingleton, + animSlv, PRServ_MAGIC_NUMBER ); if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr { //Assembly code changes the return addr on the stack to the one // saved into the singleton by the end-singleton-fn @@ -384,17 +228,20 @@ void PRServ__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; //don't need this addr until after at least one singleton has reached // this function - PRServSemEnv *semEnv = PR_WL__give_sem_env_for( animSlv, PRServ_MAGIC_NUMBER ); - asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); + PRServLangEnv * + langEnv = PR_int__give_lang_env_for_slave( animSlv, PRServ_MAGIC_NUMBER ); + + asm_write_ret_from_singleton( &(langEnv->fnSingletons[ singletonID]) ); - reqData.reqType = singleton_fn_end; + reqData.reqType = prserv_singleton_fn_end; reqData.singletonID = singletonID; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleEndFnSingleton, + animSlv, PRServ_MAGIC_NUMBER ); EndSingletonInstrAddr: return; @@ -403,7 +250,7 @@ void PRServ__end_data_singleton( PRServSingleton **singletonPtrAddr, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; //don't need this addr until after singleton struct has reached // this function for first time @@ -413,10 +260,11 @@ // function in different places for different data-singletons. asm_save_ret_to_singleton(*singletonPtrAddr); - reqData.reqType = singleton_data_end; + reqData.reqType = prserv_singleton_data_end; reqData.singletonPtrAddr = singletonPtrAddr; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleEndDataSingleton, + animSlv, PRServ_MAGIC_NUMBER ); } /*This executes the function in the masterVP, so it executes in isolation @@ -433,14 +281,15 @@ PRServ__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, void *data, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; // - reqData.reqType = atomic; + reqData.reqType = prserv_atomic; reqData.fnToExecInMaster = ptrToFnToExecInMaster; reqData.dataForFn = data; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleAtomic, + animSlv, PRServ_MAGIC_NUMBER ); } @@ -460,14 +309,15 @@ void PRServ__start_transaction( int32 transactionID, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; // reqData.callingSlv = animSlv; - reqData.reqType = trans_start; + reqData.reqType = prserv_trans_start; reqData.transID = transactionID; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleTransStart, + animSlv, PRServ_MAGIC_NUMBER ); } /*This suspends to the master, then uses transactionID as index into an @@ -482,36 +332,16 @@ void PRServ__end_transaction( int32 transactionID, SlaveVP *animSlv ) { - PRServSemReq reqData; + PRServLangReq reqData; // reqData.callingSlv = animSlv; - reqData.reqType = trans_end; + reqData.reqType = prserv_trans_end; reqData.transID = transactionID; - PR_WL__send_sem_request( &reqData, animSlv, PRServ_MAGIC_NUMBER ); + PR_WL__send_lang_request( &reqData, (RequestHandler)&PRServ__handleTransEnd, + animSlv, PRServ_MAGIC_NUMBER ); } //======================== Internal ================================== -/* - */ -SlaveVP * -PRServ__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, - SlaveVP *creatingSlv, int32 coreToAssignOnto ) - { PRServSemReq reqData; - - //the semantic request data is on the stack and disappears when this - // call returns -- it's guaranteed to remain in the VP's stack for as - // long as the VP is suspended. - reqData.reqType = create_slave_w_aff; //not used, May 2012 - reqData.coreToAssignOnto = coreToAssignOnto; - reqData.fnPtr = fnPtr; - reqData.initData = initData; - reqData.callingSlv = creatingSlv; - - PR_WL__send_create_slaveVP_req( &reqData, creatingSlv, PRServ_MAGIC_NUMBER ); - - return creatingSlv->dataRetFromReq; - } - diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ.h --- a/Services_Offered_by_PR/Services_Language/PRServ.h Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Services_Language/PRServ.h Sat Mar 02 09:43:45 2013 -0800 @@ -1,93 +1,105 @@ /* - * Copyright 2009 OpenSourceStewardshipFoundation.org + * Copyright 2009 OpenSourceResearchInstitute.org * Licensed under GNU General Public License version 2 * * Author: seanhalle@yahoo.com * */ +#ifndef _PRServ_H +#define _PRServ_H #include "Queue_impl/PrivateQueue.h" #include "Hash_impl/PrivateHash.h" -//#include "../Measurement_and_Stats/" - -#ifndef _PRServ_H -#define _PRServ_H +#include "PR_impl/PR.h" //=========================================================================== - //uniquely identifies PRServ -- should be a jenkins char-hash of "PRServ" onto int32 -#define PRServ_MAGIC_NUMBER 0000000002 + //uniquely identifies PRServ -- should be a jenkins char-hash of "PRServ" to int32 +#define PRServ_MAGIC_NUMBER 0000000001 -#define NUM_STRUCS_IN_SEM_ENV 1000 +#define NUM_STRUCS_IN_LANG_ENV 1000 + //This is hardware dependent -- it's the number of cycles of scheduling + // overhead -- if a work unit is fewer than this, it is better being + // combined sequentially with other work + //This value depends on both PR overhead and PRServ's plugin. At some point + // it will be derived by perf-counter measurements during init of PRServ +#define MIN_WORK_UNIT_CYCLES 20000 //=========================================================================== /*This header defines everything specific to the PRServ semantic plug-in */ -typedef struct _PRServSemReq PRServSemReq; -//typedef struct _PRServTaskStub PRServTaskStub; -//typedef void (*PRServTaskFnPtr ) ( void *, SlaveVP *); -//typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master +typedef struct _PRServLangReq PRServLangReq; +typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master //=========================================================================== - //=========================================================================== -/*This is placed into semData, used for dependencies and wait construct*/ -struct _PRServTaskStub +/*Semantic layer-specific data sent inside a request from lib called in app + * to request handler called in AnimationMaster + */ + +typedef struct { - //====== The first fields must match PRLangMetaTask fields ====== - int32 langMagicNumber; //magic num must be 1st field of langMetaTask - PRMetaTask *protoMetaTask; //back-link must always be 2nd field - //====== end PRLangMetaTask fields ========= - + SlaveVP *VPCurrentlyExecuting; + PrivQueueStruc *waitingVPQ; + } +PRServTrans; + +/*WARNING: assembly hard-codes position of endInstrAddr as first field + */ +typedef struct + { + void *endInstrAddr; + int32 hasBeenStarted; + int32 hasFinished; + PrivQueueStruc *waitQ; + } +PRServSingleton; + +/*Note: may not need this anymore -- switched to embedding pointer to handler*/ +enum PRServLangReqType + { + prserv_malloc_req = 1, + prserv_free_req, + prserv_singleton_fn_start, + prserv_singleton_fn_end, + prserv_singleton_data_start, + prserv_singleton_data_end, + prserv_atomic, + prserv_trans_start, + prserv_trans_end }; +struct _PRServLangReq + { enum PRServLangReqType reqType; + SlaveVP *callingSlv; -struct _PRServSemReq - { enum PRServReqType reqType; - SlaveVP *callingSlv; - void *args; -// PRServTaskStub *taskStub; //not needed -- get via PR accessor from slv - - SlaveVP *senderSlv; - SlaveVP *receiverSlv; - int32 *senderID; - int32 *receiverID; - int32 msgType; - void *msg; - PRServSemReq *nextReqInHashEntry; -//In PRReq: int32 *taskID; - - TopLevelFnPtr fnPtr; - void *initData; - int32 coreToAssignOnto; - -//These, below, should move to util language.. int32 sizeToMalloc; void *ptrToFree; int32 singletonID; + PRServSingleton **singletonPtrAddr; + PtrToAtomicFn fnToExecInMaster; void *dataForFn; int32 transID; } -/* PRServSemReq */; +/* PRServLangReq */; typedef struct - { PRLangEnv *protoLangEnv; + { PrivQueueStruc *slavesReadyToResumeQ; //Shared (slaves not pinned) - PrivQueueStruc *freeTaskSlvRecycleQ; //Shared - PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) - HashTable *argPtrHashTbl; - HashTable *commHashTbl; - int32 nextCoreToGetNewSlv; + PrivQueueStruc *taskReadyQ; //will never be used in seed langlet + int32 primitiveStartTime; //fix limit on num with dynArray + PRServSingleton fnSingletons[NUM_STRUCS_IN_LANG_ENV]; + PRServTrans transactionStrucs[NUM_STRUCS_IN_LANG_ENV]; #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC ListOfArrays* unitList; @@ -104,33 +116,24 @@ ListOfArrays* counterList[NUM_CORES]; #endif } -PRServSemEnv; +PRServLangEnv; -typedef struct _TransListElem TransListElem; -struct _TransListElem +typedef struct _PRServTransListElem PRServTransListElem; +struct _PRServTransListElem { int32 transID; - TransListElem *nextTrans; + PRServTransListElem *nextTrans; }; //TransListElem -/* PR now handles what this used to be used for -enum PRServSlvType - { FreeTaskSlv = 1, - SlotTaskSlv, - ThreadSlv - }; -*/ - typedef struct { int32 highestTransEntered; - TransListElem *lastTransEntered; + PRServTransListElem *lastTransEntered; int32 primitiveStartTime; -// PRServTaskStub *taskStub; //get from slave via PR accessor } -PRServSemData; +PRServLangData; //=========================================================================== @@ -149,36 +152,66 @@ int32 PRServ__give_number_of_cores_to_schedule_onto(); +char * +PRServ___give_environment_string(); + //======================= -void +PRServLangEnv * PRServ__start( SlaveVP *seedSlv ); void -PRServ__cleanup_after_shutdown(); +PRServ__end(); -//======================= void -PRServ__resume_slaveVP( SlaveVP *seedSlv, PRServLangEnv *servicesLangEnv ); - +PRServ__end_seedVP( SlaveVP *seedSlv ); //======================= -#define PRServ__malloc( numBytes, callingSlave ) PR_App__malloc( numBytes, callingSlave) - -#define PRServ__free(ptrToFree, callingSlave ) PR_App__free( ptrToFree, callingSlave ) - - -//======================= +inline int32 * +PRServ__create_taskID_of_size( int32 numInts, SlaveVP *animSlv ); //========================= +void +PRServ__taskwait(SlaveVP *animSlv); + +inline int32 * +PRServ__give_self_taskID( SlaveVP *animSlv ); + +//======================= Concurrency Stuff ====================== +void +PRServ__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ); + +void +PRServ__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ); + +void +PRServ__start_data_singleton( PRServSingleton **singeltonAddr, SlaveVP *animSlv ); + +void +PRServ__end_data_singleton( PRServSingleton **singletonAddr, SlaveVP *animSlv ); + +void +PRServ__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, + void *data, SlaveVP *animSlv ); + +void +PRServ__start_transaction( int32 transactionID, SlaveVP *animSlv ); + +void +PRServ__end_transaction( int32 transactionID, SlaveVP *animSlv ); //========================= Internal use only ============================= -SlaveVP * -PRServ__assign_work_to_slot( void *_semEnv, AnimSlot *slot ); +bool32 +PRServ__assign_work_to_slot( void *_langEnv, AnimSlot *slot ); + +//===================== ===================== + +#include "PRServ_Request_Handlers.h" //===================== Measurement of Lang Overheads ===================== +#include "Measurement/PRServ_Measurement.h" //=========================================================================== #endif /* _PRServ_H */ diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ_PluginFns.c --- a/Services_Offered_by_PR/Services_Language/PRServ_PluginFns.c Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Services_Language/PRServ_PluginFns.c Sat Mar 02 09:43:45 2013 -0800 @@ -12,17 +12,6 @@ #include "PRServ_Request_Handlers.h" //=========================== Local Fn Prototypes =========================== -void -resume_slaveVP( SlaveVP *slave, PRServSemEnv *semEnv ); - -inline void -handleSemReq( PRReqst *req, SlaveVP *requestingSlv, PRServSemEnv *semEnv ); - -inline void -handleDissipate( SlaveVP *requestingSlv, PRServSemEnv *semEnv ); - -inline void -handleCreate( PRReqst *req, SlaveVP *requestingSlv, PRServSemEnv *semEnv ); //============================== Assigner ================================== // @@ -51,161 +40,91 @@ * to suspend both kinds, but also to keep explicit slave stacks clean from * the junk tasks are allowed to leave behind. */ -SlaveVP * -PRServ__assign_work_to_slot( void *_semEnv, AnimSlot *slot ) +bool32 +PRServ__assign_work_to_slot( void *_langEnv, AnimSlot *slot ) { SlaveVP *returnSlv; - PRServSemEnv *semEnv; + PRServLangEnv *langEnv; int32 coreNum, slotNum; - PRMetaTask *returnMetaTask = NULL, *newTaskStub; coreNum = slot->coreSlotIsOn; slotNum = slot->slotIdx; - semEnv = (PRServSemEnv *)_semEnv; + langEnv = (PRServLangEnv *)_langEnv; //Check for suspended slaves that are ready to resume - returnSlv = readPrivQ( semEnv->slavesReadyToResumeQ ); + returnSlv = readPrivQ( langEnv->slavesReadyToResumeQ ); if( returnSlv != NULL ) //Yes, have a slave, so return it. { returnSlv->coreAnimatedBy = coreNum; - returnMetaTask = returnSlv->metaTasks; - goto ReturnTheMetaTask; + + //PR calls this Fn, which in turn uses PR's primitive to assign + // a slave to a slot. + //Note: this represents a security risk, if langlet has a bug and gives + // the wrong slot.. assuming will have a tool in future that analyzes + // plugin code before certifying it.. + PR_int__put_slave_into_slot( returnSlv, slot ); + goto Success; } - newTaskStub = readPrivQ( semEnv->taskReadyQ ); - if( newTaskStub != NULL ) - { returnMetaTask = newTaskStub->protoMetaTask; - goto ReturnTheMetaTask; - } + + //If here, didn't assign any work + Fail: + return FALSE; + //fixme; //figure out what to do -- go through holistic code still? -ReturnTheMetaTask: //doing gotos to here should help with holistic.. + Success: //doing gotos to here should help with holistic.. #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC //This no longer works -- should be moved into PR in master //This assumes the task has already been assigned to a slave, which happens // inside Master.. if( returnMetaTask == NULL ) - { returnSlv = semEnv->process->idleSlv[coreNum][slotNum]; + { returnSlv = langEnv->process->idleSlv[coreNum][slotNum]; //things that would normally happen in resume(), but these VPs // never go there returnSlv->numTimesAssignedToASlot++; Unit newU; - newU.vp = returnSlv->slaveID; + newU.vp = returnSlv->slaveNum; newU.task = returnSlv->numTimesAssignedToASlot; - addToListOfArrays(Unit,newU,semEnv->unitList); + addToListOfArrays(Unit,newU,langEnv->unitList); if (returnSlv->numTimesAssignedToASlot > 1) { Dependency newD; - newD.from_vp = returnSlv->slaveID; + newD.from_vp = returnSlv->slaveNum; newD.from_task = returnSlv->numTimesAssignedToASlot - 1; - newD.to_vp = returnSlv->slaveID; + newD.to_vp = returnSlv->slaveNum; newD.to_task = returnSlv->numTimesAssignedToASlot; - addToListOfArrays(Dependency, newD, semEnv->ctlDependenciesList); + addToListOfArrays(Dependency, newD, langEnv->ctlDependenciesList); } returnMetaTask = returnSlv->metaTasks; } else //returnSlv != NULL { //assignSlv->numTimesAssigned++; Unit prev_in_slot = - semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; + langEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; if(prev_in_slot.vp != 0) { Dependency newD; newD.from_vp = prev_in_slot.vp; newD.from_task = prev_in_slot.task; - newD.to_vp = returnSlv->slaveID; + newD.to_vp = returnSlv->slaveNum; newD.to_task = returnSlv->numTimesAssignedToASlot; - addToListOfArrays(Dependency,newD,semEnv->hwArcs); + addToListOfArrays(Dependency,newD,langEnv->hwArcs); } - prev_in_slot.vp = returnSlv->slaveID; + prev_in_slot.vp = returnSlv->slaveNum; prev_in_slot.task = returnSlv->numTimesAssignedToASlot; - semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = + langEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = prev_in_slot; } #endif - return( returnMetaTask ); +/* PR handles work available in lang env and in process.. + if( isEmptyPrivQ(langEnv->slavesReadyToResumeQ) && + isEmptyPrivQ(langEnv->taskReadyQ) ) + PR_int__clear_work_in_lang_env(langEnv); + */ + + return TRUE; } -//=========================== Request Handler ============================ -// -/* - * (Not inline because invoked indirectly via a pointer) - */ - -void -handleSemReq( PRReqst *req, SlaveVP *reqSlv, PRServSemEnv *semEnv ) - { PRServSemReq *semReq; - - semReq = PR_PI__take_sem_reqst_from(req); - if( semReq == NULL ) return; - switch( semReq->reqType ) //sem handlers are all in other file - { - case send_type_to: handleSendTypeTo( semReq, semEnv); - break; - case send_from_to: handleSendFromTo( semReq, semEnv); - break; - case receive_type_to: handleReceiveTypeTo(semReq, semEnv); - break; - case receive_from_to: handleReceiveFromTo(semReq, semEnv); - break; - case taskwait: handleTaskwait( semReq, reqSlv, semEnv); - break; - - //==================================================================== - case malloc_req: handleMalloc( semReq, reqSlv, semEnv); - break; - case free_req: handleFree( semReq, reqSlv, semEnv); - break; - case singleton_fn_start: handleStartFnSingleton(semReq, reqSlv, semEnv); - break; - case singleton_fn_end: handleEndFnSingleton( semReq, reqSlv, semEnv); - break; - case singleton_data_start:handleStartDataSingleton(semReq,reqSlv,semEnv); - break; - case singleton_data_end: handleEndDataSingleton(semReq, reqSlv, semEnv); - break; - case atomic: handleAtomic( semReq, reqSlv, semEnv); - break; - case trans_start: handleTransStart( semReq, reqSlv, semEnv); - break; - case trans_end: handleTransEnd( semReq, reqSlv, semEnv); - break; - } - } - - - //=========================== Helper ============================== -void -resume_slaveVP( SlaveVP *slave, PRServSemEnv *semEnv ) - { - //both suspended tasks and suspended explicit slaves resumed with this - writePrivQ( slave, semEnv->slavesReadyToResumeQ ); - if( semEnv->protoSemEnv->hasWork != TRUE ) - semEnv->protoSemEnv->hasWork = TRUE; - - #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS -/* - int lastRecordIdx = slave->counter_history_array_info->numInArray -1; - CounterRecord* lastRecord = slave->counter_history[lastRecordIdx]; - saveLowTimeStampCountInto(lastRecord->unblocked_timestamp); -*/ - #endif - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - slave->numTimesAssignedToASlot++; //Somewhere here! - Unit newU; - newU.vp = slave->slaveID; - newU.task = slave->numTimesAssignedToASlot; - addToListOfArrays(Unit,newU,semEnv->unitList); - - if (slave->numTimesAssignedToASlot > 1) - { Dependency newD; - newD.from_vp = slave->slaveID; - newD.from_task = slave->numTimesAssignedToASlot - 1; - newD.to_vp = slave->slaveID; - newD.to_task = slave->numTimesAssignedToASlot; - addToListOfArrays(Dependency, newD ,semEnv->ctlDependenciesList); - } - #endif - } diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.c --- a/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.c Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.c Sat Mar 02 09:43:45 2013 -0800 @@ -17,1048 +17,30 @@ //=========================== Local Fn Prototypes =========================== -void -resume_slaveVP( SlaveVP *slave, PRServSemEnv *semEnv ); - - - -//========================================================================== -// Helpers -// - -/*Only clone the elements of req used in these reqst handlers - */ -PRServSemReq * -cloneReq( PRServSemReq *semReq ) - { PRServSemReq *clonedReq; - - clonedReq = PR_PI__malloc( sizeof(PRServSemReq) ); - clonedReq->reqType = semReq->reqType; - clonedReq->senderSlv = semReq->senderSlv; - clonedReq->receiverSlv= semReq->receiverSlv; - clonedReq->msg = semReq->msg; - clonedReq->nextReqInHashEntry = NULL; - - return clonedReq; - } - - - -HashEntry * -giveEntryElseInsertReqst32( int32 *key, PRServSemReq *semReq, - HashTable *commHashTbl ) - { HashEntry *entry; - PRServSemReq *waitingReq; - - entry = getEntryFromTable32( key, commHashTbl ); - if( entry == NULL ) - { //no waiting sends or receives, so add this request and exit - // note: have to clone the request because it's on stack of sender - addValueIntoTable32( key, cloneReq( semReq ), commHashTbl ); - return NULL; - } - waitingReq = (PRServSemReq *)entry->content; - if( waitingReq == NULL ) //might happen when last waiting gets paired - { //no waiting sends or receives, so add this request and exit - entry->content = semReq; - return NULL; - } - return entry; - } - - -inline PRServPointerEntry * -create_pointer_entry( ) - { PRServPointerEntry *newEntry; - - newEntry = PR_PI__malloc( sizeof(PRServPointerEntry) ); - newEntry->hasEnabledNonFinishedWriter = FALSE; - newEntry->numEnabledNonDoneReaders = 0; - newEntry->waitersQ = makePrivQ(); - - return newEntry; - } - -/*malloc's space and initializes fields -- and COPIES the arg values - * to new space - */ -inline PRServTaskStub * -create_task_stub( PRServTaskType *taskType, void **args ) - { void **newArgs; - PRServTaskStub* newStub = PR_int__malloc( sizeof(PRMetaTask) + taskType->sizeOfArgs ); - newStub->numBlockingProp = taskType->numCtldArgs; - newStub->taskType = taskType; - newStub->ptrEntries = - PR_int__malloc( taskType->numCtldArgs * sizeof(PRServPointerEntry *) ); - newArgs = (void **)( (uint8 *)newStub + sizeof(PRMetaTask) ); - newStub->args = newArgs; - newStub->numLiveChildTasks = 0; - newStub->numLiveChildThreads = 0; - newStub->isEnded = FALSE; - - //Copy the arg-pointers.. can be more arguments than just the ones - // that StarSs uses to control ordering of task execution. - memcpy( newArgs, args, taskType->sizeOfArgs ); - - return newStub; - } - -inline PRServTaskStubCarrier * -create_task_carrier( PRServTaskStub *taskStub, int32 argNum, int32 rdOrWrite ) - { PRServTaskStubCarrier *newCarrier; - - newCarrier = PR_PI__malloc( sizeof(PRServTaskStubCarrier) ); - newCarrier->taskStub = taskStub; - newCarrier->argNum = argNum; - newCarrier->isReader = rdOrWrite == READER; - } - - - -//=========================== ============================== - -/*Application invokes this via wrapper library, when it explicitly creates a - * thread with the "PRServ__create_thread()" command. - * - *Slave creation is a special form, so PR does handling before calling this. - * It does creation of the new slave, and hands it to this handler. - *This handler is registered with PR during PRServ__start(). - * - *So, here, create a task Stub that contains a marker stating this is a thread. - * Then, attach the task stub to the slave's meta Task via a PR command. - * - *When slave dissipates, PR will call the registered recycler for the task stub. - */ -inline void -handleCreateThd( PRReqst *req, SlaveVP *requestingSlv, SlaveVP *newSlv, PRServSemEnv *semEnv ) - { PRServSemReq *semReq; - PRServTaskStub *taskStub, *parentTaskStub; - - semReq = PR_PI__take_sem_reqst_from( req ); - - parentTaskStub = PR_PI__give_lang_meta_task( requestingSlv ); - parentTaskStub->numLiveChildThreads += 1; - - taskStub = create_thread_task_stub(); //only used for wait info - taskStub->parentTaskStub = parentTaskStub; - - //note, semantic data will be initialized by separate, registered - // initializer, at the point it is accessed the first time. - - //================= Assign the new thread to a core =================== - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - newSlv->coreAnimatedBy = 0; - - #else - //Assigning slaves to cores is part of SSR code.. - int32 coreToAssignOnto = semReq->coreToAssignOnto; - if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES ) - { //out-of-range, so round-robin assignment - newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv; - - if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 ) - semEnv->nextCoreToGetNewSlv = 0; - else - semEnv->nextCoreToGetNewSlv += 1; - } - else //core num in-range, so use it - { newSlv->coreAnimatedBy = coreToAssignOnto; - } - #endif - //======================================================================== - - - - DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", - requestingSlv->slaveID, newSlv->slaveID) - - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newD; - newD.from_vp = requestingSlv->slaveID; - newD.from_task = requestingSlv->numTimesAssignedToASlot; - newD.to_vp = newSlv->slaveID; - newD.to_task = 1; - addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); - #endif - - //For PRServ, caller needs ptr to created thread returned to it - requestingSlv->dataRetFromReq = newSlv; - PR_PI__make_slave_ready(requestingSlv , semEnv ); - PR_PI__make_slave_ready( newSlv, semEnv ); - } - -/*Initialize semantic data struct.. this initializer doesn't need any input, - * but some languages may need something from inside the request that was sent - * to create a slave.. in that case, just make initializer do the malloc then - * use the PR_PI__give_sem_data inside the create handler, and fill in the - * semData values there. - */ -void * PRServ__create_lang_data_in_slave( ) - { PRServSemData *semData; - - semData = PR_PI__malloc( sizeof(PRServSemData) ); - - semData->highestTransEntered = -1; - semData->lastTransEntered = NULL; - return semData; - } - -/*SlaveVP dissipate -- this is NOT task-end!, only call this to end explicitly - * created threads - */ -inline void -handleDissipate( SlaveVP *requestingSlv, PRServSemEnv *semEnv ) - { PRServSemData *semData; - PRServTaskStub *parentTaskStub, *ownTaskStub; - - DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d", - requestingSlv->slaveID) - - ownTaskStub = PR_PI__give_lang_meta_task( requestingSlv, PRServ_MAGIC_NUMBER ); - parentTaskStub = ownTaskStub->parentTaskStub; - parentTaskStub->numLiveChildThreads -= 1; //parent wasn't freed, even if ended - - //if all children ended, then free this task's stub - // else, keep stub around, and last child will free it (below) - if( ownTaskStub->numLiveChildTasks == 0 && - ownTaskStub->numLiveChildThreads == 0 ) - free_task_stub( ownTaskStub ); - else - ownTaskStub->isEnded = TRUE; //for children to see when they end - - //Now, check on parents waiting on child threads to end - if( parentTaskStub->isWaitingForChildThreadsToEnd && - parentTaskStub->numLiveChildThreads == 0 ) - { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE; - if( parentTaskStub->isWaitingForChildTasksToEnd ) - return; //still waiting on tasks (should be impossible) - else //parent free to resume - PR_PI__make_slave_ready( PR_PI__give_slave_assigned_to(parentTaskStub), semEnv ); - } - - //check if this is last child of ended parent (note, not possible to - // have more than one level of ancestor waiting to be freed) - if( parentTaskStub->isEnded && - parentTaskStub->numLiveChildTasks == 0 && - parentTaskStub->numLiveChildThreads == 0 ) - { free_task_stub( parentTaskStub ); //just stub, semData already freed - } - - FreeSlaveStateAndReturn: - //Used to free the semData and requesting slave's base state, but - // now PR does those things, so nothing more to do.. -//PR handles this: PR_PI__free( semData ); -//PR handles this: PR_PI__dissipate_slaveVP( requestingSlv ); - return; - } - -/*Register this with PR, during PRServ start - * - *At some point, may change PR so that it recycles semData, in which case this - * only gets called when a process shuts down.. at that point, PR will call - * dissipate on all the slaves it has in the recycle Q. - */ -void -freePRServSemData( void *_semData ) - { // - PR_PI__free( _semData ); - } - -void resetPRServSemData( void *_semData ) - { PRServSemData *semData = (PRServSemData *)_semData; - - semData->highestTransEntered = -1; - semData->lastTransEntered = NULL; - } - -//========================================================================== -// -// -/*Submit Task - * - *PR creates a PRMetaTask and passes it in. This handler adds language- - * specific stuff to it. The language-specific stuff is linked to the - * PRMetaTask, but if the task is suspended for any reason, the lang-specific - * part is moved to the semData of the slave that is animating the task. - *So, while the PRMetaTask is inside the creating language's semantic - * env, waiting to be assigned to a slave for animation, the lang-specific - * task info is accessed from the PRMetaTask. But once the task suspends, - * that lang-specific task info transfers to the slave's semData. All lang - * constructs that want to access it must get it from the semData. - *However, taskEnd still accesses the lang-specific task info from the - * PRMetaTask, whether it suspended or not.. and the task code can access - * data to be used within the application behavior via - * PR__give_task_info( animatingSlave ). - * - *Uses a hash table to match the arg-pointers to each other. So, an - * argument-pointer is one-to-one with a hash-table entry. - * - *If overlapping region detection is enabled, then a hash entry is one - * link in a ring of all entries that overlap each other. For example, - * say region A shared common addresses with region B, but the pointers - * to them are different, then the hash entries for the two would be - * linked in a ring. When a pointer is processed, all the pointers in - * the ring are processed (Doesn't differentiate independent siblings - * from parent-child or conjoined twins overlap..) - * NOT ENABLED AS OF MAY 25 2012 - * - *A hash entry has a queue of tasks that are waiting to access the - * pointed-to region. The queue goes in the order of creation of - * the tasks. Each entry in the queue has a pointer to the task-stub - * and whether the task reads-only vs writes to the hash-entry's region. - * - *A hash entry also has a count of the enabled but not yet finished readers - * of the region. It also has a flag that says whether a writer has been - * enabled and is not yet finished. - * - *There are two kinds of events that access a hash entry: creation of a - * task and end of a task. - * - * - * ========================== creation ========================== - * - *At creation, make a task-stub. Set the count of blocking propendents - * to the number of controlled arguments (a task can have - * arguments that are not controlled by the language, like simple integer - * inputs from the sequential portion. Note that all controlled arguments - * are pointers, and marked as controlled in the application code). - * - *The controlled arguments are then processed one by one. - *Processing an argument means getting the hash of the pointer. Then, - * looking up the hash entry. (If none, create one). - *With the hash entry: - * - *If the arg is a reader, and the entry does not have an enabled - * non-finished writer, and the queue is empty (could be prev readers, - * then a writer that got queued and now new readers that have to also be - * queued). - *The reader is free. So, decrement the blocking-propendent count in - * the task-stub. If the count is zero, then put the task-stub into the - * readyQ. - *At the same time, increment the hash-entry's count of enabled and - * non-finished readers. - * - *Otherwise, the reader is put into the hash-entry's Q of waiters - * - *If the arg is a writer, plus the entry does not have a current writer, - * plus the number of enabled non-finished readers is zero, plus the Q is - * empty, then the writer is free. Mark the entry has having an - * enabled and non-finished writer. Decrement the blocking-propendent - * count in the writer's task-stub. If the count is zero, then put the - * task-stub into the readyQ. - * - *Otherwise, put the writer into the entry's Q of waiters. - * - *No matter what, if the hash entry was chained, put it at the start of - * the chain. (Means no-longer-used pointers accumulate at end of chain, - * decide garbage collection of no-longer-used pointers later) - * - */ -inline -void * -handleSubmitTask( PRServSemReq *semReq, PRServSemEnv *semEnv ) - { uint32 key[3]; - HashEntry *rawHashEntry; //has char *, but use with uint32 * - PRServPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer - void **args; - PRServTaskStub *taskStub, *parentTaskStub; - PRServTaskType *taskType; - PRServTaskStubCarrier *taskCarrier; - - HashTable * - argPtrHashTbl = semEnv->argPtrHashTbl; - - - /* ========================== creation ========================== - *Make a task-stub. Set the count of blocking propendents - * to the number of controlled arguments (a task can have - * arguments that are not controlled by the language, like simple integer - * inputs from the sequential portion. Note that all controlled arguments - * are pointers, and marked as controlled in the application code). - */ - args = semReq->args; - taskType = semReq->taskType; //this is PRServ task type struct - taskStub = create_task_stub( taskType, args );//copies arg ptrs - - taskStub->numBlockingProp = taskType->numCtldArgs; - //PR does this (metaTask contains taskID): taskStub->taskID = semReq->taskID; - - parentTaskStub = (PRServTaskStub *)PR_PI__give_lang_meta_task(semReq->callingSlv, PRServ_MAGIC_NUMBER); - taskStub->parentTaskStub = parentTaskStub; - parentTaskStub->numLiveChildTasks += 1; - - //DEBUG__printf3(dbgRqstHdlr,"Submit req from slaveID: %d, from task: %d, for task: %d", semReq->callingSlv->slaveID, parentSemData->taskStub->taskID[1], taskStub->taskID[1]) - DEBUG__printf2(dbgRqstHdlr,"Submit req from slaveID: %d, for task: %d", semReq->callingSlv->slaveID, taskStub->taskID[1]) - - /*=============== Process args ================= - *The controlled arguments are processed one by one. - *Processing an argument means getting the hash of the pointer. Then, - * looking up the hash entry. (If none, create one). - */ - int32 argNum; - for( argNum = 0; argNum < taskType->numCtldArgs; argNum++ ) - { - key[0] = 2; //two 32b values in key - *( (uint64*)&key[1]) = (uint64)args[argNum]; //write 64b into two 32b - - /*If the hash entry was chained, put it at the - * start of the chain. (Means no-longer-used pointers accumulate - * at end of chain, decide garbage collection later) */ - rawHashEntry = getEntryFromTable32( key, argPtrHashTbl ); - if( rawHashEntry == NULL ) - { //adding a value auto-creates the hash-entry - ptrEntry = create_pointer_entry(); - rawHashEntry = addValueIntoTable32( key, ptrEntry, argPtrHashTbl ); - } - else - { ptrEntry = (PRServPointerEntry *)rawHashEntry->content; - if( ptrEntry == NULL ) - { ptrEntry = create_pointer_entry(); - rawHashEntry = addValueIntoTable32(key, ptrEntry, argPtrHashTbl); - } - } - taskStub->ptrEntries[argNum] = ptrEntry; - - /*Have the hash entry. - *If the arg is a reader and the entry does not have an enabled - * non-finished writer, and the queue is empty. */ - if( taskType->argTypes[argNum] == READER ) - { if( !ptrEntry->hasEnabledNonFinishedWriter && - isEmptyPrivQ( ptrEntry->waitersQ ) ) - { /*The reader is free. So, decrement the blocking-propendent - * count in the task-stub. If the count is zero, then put the - * task-stub into the readyQ. At the same time, increment - * the hash-entry's count of enabled and non-finished readers.*/ - taskStub->numBlockingProp -= 1; - if( taskStub->numBlockingProp == 0 ) - { writePrivQ( taskStub, semEnv->taskReadyQ ); - if( semEnv->protoSemEnv->hasWork != TRUE ) - semEnv->protoSemEnv->hasWork = TRUE; - } - ptrEntry->numEnabledNonDoneReaders += 1; - } - else - { /*Otherwise, the reader is put into the hash-entry's Q of - * waiters*/ - taskCarrier = create_task_carrier( taskStub, argNum, READER ); - writePrivQ( taskCarrier, ptrEntry->waitersQ ); - } - } - else //arg is a writer - { /*the arg is a writer, plus the entry does not have a current - * writer, plus the number of enabled non-finished readers is - * zero, (the Q must be empty, else bug!) then the writer is free*/ - if( !ptrEntry->hasEnabledNonFinishedWriter && - ptrEntry->numEnabledNonDoneReaders == 0 ) - { /*Mark the entry has having a enabled and non-finished writer. - * Decrement the blocking-propenden count in the writer's - * task-stub. If the count is zero, then put the task-stub - * into the readyQ.*/ - taskStub->numBlockingProp -= 1; - if( taskStub->numBlockingProp == 0 ) - { writePrivQ( taskStub, semEnv->taskReadyQ ); - if( semEnv->protoSemEnv->hasWork != TRUE ) - semEnv->protoSemEnv->hasWork = TRUE; - } - ptrEntry->hasEnabledNonFinishedWriter = TRUE; - } - else - {/*Otherwise, put the writer into the entry's Q of waiters.*/ - taskCarrier = create_task_carrier( taskStub, argNum, WRITER ); - writePrivQ( taskCarrier, ptrEntry->waitersQ ); - } - } - } //for argNum - - //resume the parent, creator - PR_PI__make_slave_ready( semReq->callingSlv, semEnv ); - - return; - } - - -/* ========================== end of task =========================== - * - *At the end of a task, - *The task's controlled arguments are processed one by one. - *Processing an argument means getting the hash of the pointer. Then, - * looking up the hash entry (and putting the entry at the start of the - * chain, if there was a chain). - *With the hash entry: - * - *If the arg is a reader, then decrement the enabled and non-finished - * reader-count in the hash-entry. If the count becomes zero, then take - * the next entry from the Q. It should be a writer, or else there's a - * bug in this algorithm. - *Set the hash-entry to have an enabled non-finished writer. Decrement - * the blocking-propendent-count of the writer's task-stub. If the count - * has reached zero, then put the task-stub into the readyQ. - * - *If the arg is a writer, then clear the enabled non-finished writer flag - * of the hash-entry. Take the next entry from the waiters Q. - *If it is a writer, then turn the flag back on. Decrement the writer's - * blocking-propendent-count in its task-stub. If it becomes zero, then - * put the task-stub into the readyQ. - * - *If waiter is a reader, then do a loop, getting all waiting readers. - * For each, increment the hash-entry's count of enabled - * non-finished readers. Decrement the blocking propendents count of the - * reader's task-stub. If it reaches zero, then put the task-stub into the - * readyQ. - *Repeat until encounter a writer -- put that writer back into the Q. - * - *May 2012 -- not keeping track of how many references to a given ptrEntry - * exist, so no way to garbage collect.. - *TODO: Might be safe to delete an entry when task ends and waiterQ empty - * and no readers and no writers.. - */ -inline void -handleEndTask( void *langMetaTask, PRServSemReq *semReq, PRServSemEnv *semEnv ) - { PRServPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer - void **args; - PRServSemData *endingSlvSemData; - PRServTaskStub *endingTaskStub, *waitingTaskStub, *parentStub; - PRServTaskType *endingTaskType; - PRServTaskStubCarrier *waitingTaskCarrier; - PRServPointerEntry **ptrEntries; - - -// endingTaskStub = (PRServTaskStub *)PR_PI__give_lang_spec_task_info( semReq->callingSlv ); - - endingTaskStub = (PRServTaskStub *)langMetaTask; - args = endingTaskStub->args; - endingTaskType = endingTaskStub->taskType; - ptrEntries = endingTaskStub->ptrEntries; //saved in stub when create - - DEBUG__printf2(dbgRqstHdlr,"EndTask req from slaveID: %d, task: %d",semReq->callingSlv->slaveID, endingTaskStub->taskID[1]) - - //"wait" functionality: Check if parent was waiting on this task - parentStub = endingTaskStub->parentTaskStub; - parentStub->numLiveChildTasks -= 1; - if( parentStub->isWaitingForChildTasksToEnd && - parentStub->numLiveChildTasks == 0) - { - parentStub->isWaitingForChildTasksToEnd = FALSE; - PR_PI__make_slave_ready( PR_PI__give_slave_assigned_to(parentStub), semEnv ); - } - - //Check if parent ended, and this was last descendent, then free it - if( parentStub->isEnded && parentStub->numLiveChildTasks == 0 ) - { free_task_stub( parentStub ); - } - - - //Now, update state of dependents and start ready tasks - /*The task's controlled arguments are processed one by one. - *Processing an argument means getting arg-pointer's entry. - */ - int32 argNum; - for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ ) - { - ptrEntry = ptrEntries[argNum]; - //check if the ending task was reader of this arg - if( endingTaskType->argTypes[argNum] == READER ) - { //then decrement the enabled and non-finished reader-count in - // the hash-entry. - ptrEntry->numEnabledNonDoneReaders -= 1; - - //If the count becomes zero, then take the next entry from the Q. - //It should be a writer, or else there's a bug in this algorithm. - if( ptrEntry->numEnabledNonDoneReaders == 0 ) - { waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); - if( waitingTaskCarrier == NULL ) - { //TODO: looks safe to delete the ptr entry at this point - continue; //next iter of loop - } - if( waitingTaskCarrier->isReader ) - PR_App__throw_exception("READER waiting", NULL, NULL); - - waitingTaskStub = waitingTaskCarrier->taskStub; - - //Set the hash-entry to have an enabled non-finished writer. - ptrEntry->hasEnabledNonFinishedWriter = TRUE; - - // Decrement the blocking-propendent-count of the writer's - // task-stub. If the count has reached zero, then put the - // task-stub into the readyQ. - waitingTaskStub->numBlockingProp -= 1; - if( waitingTaskStub->numBlockingProp == 0 ) - { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); - if( semEnv->protoSemEnv->hasWork != TRUE ) - semEnv->protoSemEnv->hasWork = TRUE; - } - } - } - else //the ending task is a writer of this arg - { //clear the enabled non-finished writer flag of the hash-entry. - ptrEntry->hasEnabledNonFinishedWriter = FALSE; - - //Take the next waiter from the hash-entry's Q. - waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); - if( waitingTaskCarrier == NULL ) - { //TODO: looks safe to delete ptr entry at this point - continue; //go to next iter of loop, done here. - } - waitingTaskStub = waitingTaskCarrier->taskStub; - - //If task is a writer of this hash-entry's pointer - if( !waitingTaskCarrier->isReader ) - { // then turn the flag back on. - ptrEntry->hasEnabledNonFinishedWriter = TRUE; - //Decrement the writer's blocking-propendent-count in task-stub - // If it becomes zero, then put the task-stub into the readyQ. - waitingTaskStub->numBlockingProp -= 1; - if( waitingTaskStub->numBlockingProp == 0 ) - { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); - if( semEnv->protoSemEnv->hasWork != TRUE ) - semEnv->protoSemEnv->hasWork = TRUE; - } - } - else - { //Waiting task is a reader, so do a loop, of all waiting readers - // until encounter a writer or waitersQ is empty - while( TRUE ) //The checks guarantee have a waiting reader - { //Increment the hash-entry's count of enabled non-finished - // readers. - ptrEntry->numEnabledNonDoneReaders += 1; - - //Decrement the blocking propendents count of the reader's - // task-stub. If it reaches zero, then put the task-stub - // into the readyQ. - waitingTaskStub->numBlockingProp -= 1; - if( waitingTaskStub->numBlockingProp == 0 ) - { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); - if( semEnv->protoSemEnv->hasWork != TRUE ) - semEnv->protoSemEnv->hasWork = TRUE; - } - //Get next waiting task - waitingTaskCarrier = peekPrivQ( ptrEntry->waitersQ ); - if( waitingTaskCarrier == NULL ) break; //no more waiting readers - if( !waitingTaskCarrier->isReader ) break; //no more waiting readers - waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); - waitingTaskStub = waitingTaskCarrier->taskStub; - }//while waiter is a reader - }//if-else, first waiting task is a reader - }//if-else, check of ending task, whether writer or reader - }//for argnum in ending task - - - //done ending the task, if still has live children, then keep stub around - // else, free the stub and args copy - if( endingTaskStub->numLiveChildTasks == 0 && - endingTaskStub->numLiveChildThreads == 0 ) - { free_task_stub( endingTaskStub ); - } - - return; - } - - -inline void -free_task_stub( PRServTaskStub *stubToFree ) - { if(stubToFree->ptrEntries != NULL ) //a thread stub has NULL entry - { PR_PI__free( stubToFree->ptrEntries ); - } - PR_PI__free( stubToFree ); - } - -//========================== Task Comm handlers =========================== - - - -//============================ Send Handlers ============================== -/*Send of Type -- The semantic request has the receiving task ID and Type - * - *Messages of a given Type have to be kept separate.. so need a separate - * entry in the hash table for each pair: receiverID, Type - * - *Also, if same sender sends multiple before any get received, then need to - * stack the sends up -- even if a send waits until it's paired, several - * separate tasks can send to the same receiver, and doing hash on the - * receive task, so they will stack up. - */ -inline void -handleSendTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv ) - { SlaveVP *senderSlv, *receiverSlv; - int32 *senderID, *receiverID; - int32 *key, keySz, receiverIDNumInt; - PRServSemReq *waitingReq; - HashEntry *entry; - HashTable *commHashTbl = semEnv->commHashTbl; - - receiverID = semReq->receiverID; //For "send", know both send & recv procrs - senderSlv = semReq->senderSlv; - - DEBUG__printf2(dbgRqstHdlr,"SendType req from sender slaveID: %d, recTask: %d", senderSlv->slaveID, receiverID[1]) - - - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself - keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); - key = PR_PI__malloc( keySz ); - key[0] = receiverIDNumInt + 1; //loc 0 is num int32 in key - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); - key[ 1 + receiverIDNumInt ] = semReq->msgType; - - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); - if( entry == NULL ) //was just inserted, means task has to wait - { return; - } - - //if here, found a waiting request with same key - waitingReq = (PRServSemReq *)entry->content; - - //At this point, know have waiting request(s) -- either sends or recv - //Note, can only have max of one receive waiting, and cannot have both - // sends and receives waiting (they would have paired off) - // but can have multiple sends from diff sending VPs, all same msg-type - if( waitingReq->reqType == send_type_to ) - { //waiting request is another send, so stack this up on list - // but first clone the sending request so it persists. - PRServSemReq *clonedReq = cloneReq( semReq ); - clonedReq-> nextReqInHashEntry = waitingReq->nextReqInHashEntry; - waitingReq->nextReqInHashEntry = clonedReq; - DEBUG__printf2( dbgRqstHdlr, "linked requests: %p, %p ", clonedReq,\ - waitingReq ) - return; - } - else - { - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newD; - newD.from_vp = senderID->slaveID; - newD.from_task = senderID->numTimesAssignedToASlot; - newD.to_vp = receiverID->slaveID; - newD.to_task = receiverID->numTimesAssignedToASlot +1; - //(newD,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newD,semEnv->dynDependenciesList); - int32 groupId = semReq->msgType; - if(semEnv->ntonGroupsInfo->numInArray <= groupId){ - makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); - } - if(semEnv->ntonGroups[groupId] == NULL){ - semEnv->ntonGroups[groupId] = new_NtoN(groupId); - } - Unit u; - u.vp = senderID->slaveID; - u.task = senderID->numTimesAssignedToASlot; - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); - u.vp = receiverID->slaveID; - u.task = receiverID->numTimesAssignedToASlot +1; - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); - #endif - - //set receiver slave, from the waiting request - receiverSlv = waitingReq->receiverSlv; - - //waiting request is a receive_type_to, so it pairs to this send - //First, remove the waiting receive request from the entry - entry->content = waitingReq->nextReqInHashEntry; - PR_PI__free( waitingReq ); //Don't use contents -- so free it - - if( entry->content == NULL ) - { //TODO: mod hash table to double-link, so can delete entry from - // table without hashing the key and looking it up again - deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees hashEntry - } - - //attach msg that's in this send request to receiving task's Slv - // when comes back from suspend will have msg in dataRetFromReq - receiverSlv->dataRetFromReq = semReq->msg; - - //bring both processors back from suspend - PR_PI__make_slave_ready( senderSlv, semEnv ); - PR_PI__make_slave_ready( receiverSlv, semEnv ); - - return; - } - } - - -/*If Send or Receive are called within a task, it causes the task to suspend, - * which converts the slave animating it to a free slave and suspends that slave. - *Which means that send and receive operate upon slaves, no matter whether they - * were called from within a task or a slave. - * - *Looks like can make single handler for both kinds of send.. - */ -//TODO: combine both send handlers into single handler -inline void -handleSendFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv) - { SlaveVP *senderSlv, *receiverSlv; - int32 *senderID, *receiverID; - int32 *key, keySz, receiverIDNumInt, senderIDNumInt; - PRServSemReq *waitingReq; - HashEntry *entry; - HashTable *commHashTbl = semEnv->commHashTbl; - - DEBUG__printf2(dbgRqstHdlr,"SendFromTo req from task %d to %d", - semReq->senderID[1],semReq->receiverID[1]) - - receiverID = semReq->receiverID; //For "send", know both send & recv procrs - senderID = semReq->senderID; - senderSlv = semReq->senderSlv; - - - receiverIDNumInt = receiverID[0] + 1; //include the count in the key - senderIDNumInt = senderID[0] + 1; - keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); - key = PR_PI__malloc( keySz ); - key[0] = receiverIDNumInt + senderIDNumInt; - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); - memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); - - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); - if( entry == NULL ) //was just inserted, means task has to wait - { return; - } - - waitingReq = (PRServSemReq *)entry->content; - - //At this point, know have waiting request(s) -- either sends or recv - if( waitingReq->reqType == send_from_to ) - { printf("\n ERROR: shouldn't be two send-from-tos waiting \n"); - } - else - { //waiting request is a receive, so it completes pair with this send - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newD; - newD.from_vp = sendPr->slaveID; - newD.from_task = sendPr->numTimesAssignedToASlot; - newD.to_vp = receivePr->slaveID; - newD.to_task = receivePr->numTimesAssignedToASlot +1; - //addToListOfArraysDependency(newD,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); - #endif - - //set receiver slave, from the waiting request - receiverSlv = waitingReq->receiverSlv; - - //First, remove the waiting receive request from the entry - entry->content = waitingReq->nextReqInHashEntry; - PR_PI__free( waitingReq ); //Don't use contents -- so free it - - //can only be one waiting req for "from-to" semantics - if( entry->content != NULL ) - { - printf("\nERROR in handleSendFromTo\n"); - } - deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry - - //attach msg that's in this send request to receiving procr - // when comes back from suspend, will have msg in dataRetFromReq - receiverSlv->dataRetFromReq = semReq->msg; - - //bring both processors back from suspend - PR_PI__make_slave_ready( senderSlv, semEnv ); - PR_PI__make_slave_ready( receiverSlv, semEnv ); - - return; - } - } - - - -//============================== Receives =========================== -// - - -inline void -handleReceiveTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv) - { SlaveVP *senderSlv, *receiverSlv; - int32 *receiverID; - int32 *key, keySz, receiverIDNumInt; - PRServSemReq *waitingReq; - HashEntry *entry; - HashTable *commHashTbl = semEnv->commHashTbl; - - DEBUG__printf2(dbgRqstHdlr,"ReceiveType req to ID: %d type: %d",semReq->receiverID[1], semReq->msgType) - - receiverID = semReq->receiverID; //For "send", know both send & recv procrs - receiverSlv = semReq->receiverSlv; - - - //key is the receiverID plus the type -- have to copy them into key - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself - keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); - key = PR_PI__malloc( keySz ); - key[0] = receiverIDNumInt + 1; //loc 0 is num int32s in key - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); - key[ 1 + receiverIDNumInt ] = semReq->msgType; - - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );//clones - if( entry == NULL ) //was just inserted, means task has to wait - { return; - } - - waitingReq = (PRServSemReq *)entry->content; //previously cloned by insert - - //At this point, know have waiting request(s) -- should be send(s) - if( waitingReq->reqType == send_type_to ) - { - //set sending slave from the request - senderSlv = waitingReq->senderSlv; - - //waiting request is a send, so pair it with this receive - //first, remove the waiting send request from the list in entry - entry->content = waitingReq->nextReqInHashEntry; - if( entry->content == NULL ) - { deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry - } - - //attach msg that's in the send request to receiving procr - // when comes back from suspend, will have msg in dataRetFromReq - receiverSlv->dataRetFromReq = waitingReq->msg; - - //bring both processors back from suspend - PR_PI__free( waitingReq ); - - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newD; - newD.from_vp = sendPr->slaveID; - newD.from_task = sendPr->numTimesAssignedToASlot; - newD.to_vp = receivePr->slaveID; - newD.to_task = receivePr->numTimesAssignedToASlot +1; - //addToListOfArraysDependency(newD,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newD,semEnv->dynDependenciesList); - int32 groupId = semReq->msgType; - if(semEnv->ntonGroupsInfo->numInArray <= groupId){ - makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); - } - if(semEnv->ntonGroups[groupId] == NULL){ - semEnv->ntonGroups[groupId] = new_NtoN(groupId); - } - Unit u; - u.vp = sendPr->slaveID; - u.task = sendPr->numTimesAssignedToASlot; - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); - u.vp = receivePr->slaveID; - u.task = receivePr->numTimesAssignedToASlot +1; - addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); - #endif - - PR_PI__make_slave_ready( senderSlv, semEnv ); - PR_PI__make_slave_ready( receiverSlv, semEnv ); - - return; - } - printf("\nLang Impl Error: Should never be two waiting receives!\n"); - } - - -/* - */ -inline void -handleReceiveFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv) - { SlaveVP *senderSlv, *receiverSlv; - int32 *senderID, *receiverID; - int32 *key, keySz, receiverIDNumInt, senderIDNumInt; - PRServSemReq *waitingReq; - HashEntry *entry; - HashTable *commHashTbl = semEnv->commHashTbl; - - DEBUG__printf2(dbgRqstHdlr,"RecFromTo req from ID: %d to ID: %d",semReq->senderID[1],semReq->receiverID[1]) - - receiverID = semReq->receiverID; //For "send", know both send & recv procrs - senderID = semReq->senderID; - receiverSlv = semReq->receiverSlv; - - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself - senderIDNumInt = senderID[0] + 1; - keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); - key = PR_PI__malloc( keySz ); - key[0] = receiverIDNumInt + senderIDNumInt; //loc 0 is num int32s in key - memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); - memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32)); - - entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); - if( entry == NULL ) //was just inserted, means task has to wait - { return; - } - - waitingReq = (PRServSemReq *)entry->content; - - //At this point, know have a request to rendez-vous -- should be send - if( waitingReq->reqType == send_from_to ) - { //waiting request is a send, so pair it with this receive - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newD; - newD.from_vp = sendPr->slaveID; - newD.from_task = sendPr->numTimesAssignedToASlot; - newD.to_vp = receivePr->slaveID; - newD.to_task = receivePr->numTimesAssignedToASlot +1; - //addToListOfArraysDependency(newD,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); - #endif - - //have receiver slave, now set sender slave - senderSlv = waitingReq->senderSlv; - - //For from-to, should only ever be a single reqst waiting tobe paird - entry->content = waitingReq->nextReqInHashEntry; - if( entry->content != NULL ) printf("\nERROR in handleRecvFromTo\n"); - deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees entry too - - //attach msg that's in the send request to receiving procr - // when comes back from suspend, will have msg in dataRetFromReq - receiverSlv->dataRetFromReq = waitingReq->msg; - - //bring both processors back from suspend - PR_PI__free( waitingReq ); - - PR_PI__make_slave_ready( senderSlv, semEnv ); - PR_PI__make_slave_ready( receiverSlv, semEnv ); - - return; - } - printf("\nLang Impl Error: Should never be two waiting receives!\n"); - } - - -/*Waits for all tasks that are direct children to end, then resumes calling - * task or thread - */ -inline void -handleTaskwait( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv) - { PRServTaskStub* taskStub; - - DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d", - requestingSlv->slaveID) - - taskStub = (PRServTaskStub *)PR_PI__give_lang_meta_task( requestingSlv, PRServ_MAGIC_NUMBER); - - if( taskStub->numLiveChildTasks == 0 ) - { //nobody to wait for, resume - PR_PI__make_slave_ready( requestingSlv, semEnv ); - } - else //have to wait, mark waiting - { - taskStub->isWaitingForChildTasksToEnd = TRUE; - } - } //========================================================================== /* */ void -handleMalloc( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ) +PRServ__handleMalloc( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ) { void *ptr; - DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveID) + DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveNum) - ptr = PR_PI__malloc( semReq->sizeToMalloc ); + ptr = PR_PI__malloc( langReq->sizeToMalloc ); requestingSlv->dataRetFromReq = ptr; - PR_PI__make_slave_ready( requestingSlv, semEnv ); + PR_PI__make_slave_ready( requestingSlv, langEnv ); } /* */ void -handleFree( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ) +PRServ__handleFree( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ) { - DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveID) - PR_PI__free( semReq->ptrToFree ); - PR_PI__make_slave_ready( requestingSlv, semEnv ); + DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveNum) + PR_PI__free( langReq->ptrToFree ); + PR_PI__make_slave_ready( requestingSlv, langEnv ); } @@ -1067,14 +49,15 @@ /*Uses ID as index into array of flags. If flag already set, resumes from * end-label. Else, sets flag and resumes normally. */ -void inline -handleStartSingleton_helper( PRServSingleton *singleton, SlaveVP *reqstingSlv, - PRServSemEnv *semEnv ) +void +//inline +PRServ__handleStartSingleton_helper( PRServSingleton *singleton, SlaveVP *reqstingSlv, + PRServLangEnv *langEnv ) { if( singleton->hasFinished ) { //the code that sets the flag to true first sets the end instr addr reqstingSlv->dataRetFromReq = singleton->endInstrAddr; - PR_PI__make_slave_ready( reqstingSlv, semEnv ); + PR_PI__make_slave_ready( reqstingSlv, langEnv ); return; } else if( singleton->hasBeenStarted ) @@ -1086,42 +69,45 @@ { //hasn't been started, so this is the first attempt at the singleton singleton->hasBeenStarted = TRUE; reqstingSlv->dataRetFromReq = 0x0; - PR_PI__make_slave_ready( reqstingSlv, semEnv ); + PR_PI__make_slave_ready( reqstingSlv, langEnv ); return; } } -void inline -handleStartFnSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ) +void +//inline +PRServ__handleStartFnSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ) { PRServSingleton *singleton; - DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingSlv->slaveID) + DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingSlv->slaveNum) - singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); - handleStartSingleton_helper( singleton, requestingSlv, semEnv ); + singleton = &(langEnv->fnSingletons[ langReq->singletonID ]); + PRServ__handleStartSingleton_helper( singleton, requestingSlv, langEnv ); } -void inline -handleStartDataSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ) +void +//inline +PRServ__handleStartDataSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ) { PRServSingleton *singleton; - DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveID) - if( *(semReq->singletonPtrAddr) == NULL ) + DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveNum) + if( *(langReq->singletonPtrAddr) == NULL ) { singleton = PR_PI__malloc( sizeof(PRServSingleton) ); singleton->waitQ = makePRQ(); singleton->endInstrAddr = 0x0; singleton->hasBeenStarted = FALSE; singleton->hasFinished = FALSE; - *(semReq->singletonPtrAddr) = singleton; + *(langReq->singletonPtrAddr) = singleton; } else - singleton = *(semReq->singletonPtrAddr); - handleStartSingleton_helper( singleton, requestingSlv, semEnv ); + singleton = *(langReq->singletonPtrAddr); + PRServ__handleStartSingleton_helper( singleton, requestingSlv, langEnv ); } -void inline -handleEndSingleton_helper( PRServSingleton *singleton, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ) +void +//inline +PRServ__handleEndSingleton_helper( PRServSingleton *singleton, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ) { PrivQueueStruc *waitQ; int32 numWaiting, i; SlaveVP *resumingSlv; @@ -1139,33 +125,33 @@ { //they will resume inside start singleton, then jmp to end singleton resumingSlv = readPrivQ( waitQ ); resumingSlv->dataRetFromReq = singleton->endInstrAddr; - PR_PI__make_slave_ready( resumingSlv, semEnv ); + PR_PI__make_slave_ready( resumingSlv, langEnv ); } - PR_PI__make_slave_ready( requestingSlv, semEnv ); + PR_PI__make_slave_ready( requestingSlv, langEnv ); } -void inline -handleEndFnSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ) +void +PRServ__handleEndFnSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ) { PRServSingleton *singleton; - DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingSlv->slaveID) + DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingSlv->slaveNum) - singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); - handleEndSingleton_helper( singleton, requestingSlv, semEnv ); + singleton = &(langEnv->fnSingletons[ langReq->singletonID ]); + PRServ__handleEndSingleton_helper( singleton, requestingSlv, langEnv ); } -void inline -handleEndDataSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ) +void +PRServ__handleEndDataSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ) { PRServSingleton *singleton; - DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingSlv->slaveID) + DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingSlv->slaveNum) - singleton = *(semReq->singletonPtrAddr); - handleEndSingleton_helper( singleton, requestingSlv, semEnv ); + singleton = *(langReq->singletonPtrAddr); + PRServ__handleEndSingleton_helper( singleton, requestingSlv, langEnv ); } @@ -1173,11 +159,11 @@ * pointer out of the request and call it, then resume the VP. */ void -handleAtomic( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ) +PRServ__handleAtomic( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ) { - DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingSlv->slaveID) - semReq->fnToExecInMaster( semReq->dataForFn ); - PR_PI__make_slave_ready( requestingSlv, semEnv ); + DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingSlv->slaveNum) + langReq->fnToExecInMaster( langReq->dataForFn ); + PR_PI__make_slave_ready( requestingSlv, langEnv ); } /*First, it looks at the VP's semantic data, to see the highest transactionID @@ -1195,35 +181,35 @@ *If NULL, then write requesting into the field and resume. */ void -handleTransStart( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ) - { PRServSemData *semData; - TransListElem *nextTransElem; +PRServ__handleTransStart( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ) + { PRServLangData *langData; + PRServTransListElem *nextTransElem; - DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingSlv->slaveID) + DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingSlv->slaveNum) //check ordering of entering transactions is correct - semData = requestingSlv->semanticData; - if( semData->highestTransEntered > semReq->transID ) + langData = PR_PI__give_lang_data_from_slave(requestingSlv, PRServ_MAGIC_NUMBER); + if( langData->highestTransEntered > langReq->transID ) { //throw PR exception, which shuts down PR. PR_PI__throw_exception( "transID smaller than prev", requestingSlv, NULL); } //add this trans ID to the list of transactions entered -- check when // end a transaction - semData->highestTransEntered = semReq->transID; - nextTransElem = PR_PI__malloc( sizeof(TransListElem) ); - nextTransElem->transID = semReq->transID; - nextTransElem->nextTrans = semData->lastTransEntered; - semData->lastTransEntered = nextTransElem; + langData->highestTransEntered = langReq->transID; + nextTransElem = PR_PI__malloc( sizeof(PRServTransListElem) ); + nextTransElem->transID = langReq->transID; + nextTransElem->nextTrans = langData->lastTransEntered; + langData->lastTransEntered = nextTransElem; //get the structure for this transaction ID PRServTrans * - transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); + transStruc = &(langEnv->transactionStrucs[ langReq->transID ]); if( transStruc->VPCurrentlyExecuting == NULL ) { transStruc->VPCurrentlyExecuting = requestingSlv; - PR_PI__make_slave_ready( requestingSlv, semEnv ); + PR_PI__make_slave_ready( requestingSlv, langEnv ); } else { //note, might make future things cleaner if save request with VP and @@ -1248,15 +234,15 @@ * resume both. */ void -handleTransEnd(PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv) - { PRServSemData *semData; +PRServ__handleTransEnd(PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv) + { PRServLangData *langData; SlaveVP *waitingSlv; PRServTrans *transStruc; - TransListElem *lastTrans; + PRServTransListElem *lastTrans; - DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingSlv->slaveID) + DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingSlv->slaveNum) - transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); + transStruc = &(langEnv->transactionStrucs[ langReq->transID ]); //make sure transaction ended in same VP as started it. if( transStruc->VPCurrentlyExecuting != requestingSlv ) @@ -1265,21 +251,163 @@ } //make sure nesting is correct -- last ID entered should == this ID - semData = requestingSlv->semanticData; - lastTrans = semData->lastTransEntered; - if( lastTrans->transID != semReq->transID ) + langData = PR_PI__give_lang_data_from_slave(requestingSlv, PRServ_MAGIC_NUMBER); + lastTrans = langData->lastTransEntered; + if( lastTrans->transID != langReq->transID ) { PR_PI__throw_exception( "trans incorrectly nested", requestingSlv, NULL ); } - semData->lastTransEntered = semData->lastTransEntered->nextTrans; + langData->lastTransEntered = langData->lastTransEntered->nextTrans; waitingSlv = readPrivQ( transStruc->waitingVPQ ); transStruc->VPCurrentlyExecuting = waitingSlv; if( waitingSlv != NULL ) - PR_PI__make_slave_ready( waitingSlv, semEnv ); + PR_PI__make_slave_ready( waitingSlv, langEnv ); - PR_PI__make_slave_ready( requestingSlv, semEnv ); + PR_PI__make_slave_ready( requestingSlv, langEnv ); } + + +//========================================================================== +// Helpers +// +void +PRServ__make_task_ready( void *taskStub, void *_langEnv ) + { + writePrivQ( taskStub, ((PRServLangEnv*)_langEnv)->taskReadyQ ); + } + + +/*Proto Runtime has a special call-chain for resuming a slaveVP. The langlet + * supplies a function to perform the resume, but then registers it with + * PR, and instead calls PR's version.. PR then decides whether to handle + * the resume itself, or pass resume along to this registered handler. + */ +void +PRServ__resume_slave( SlaveVP *slave, void *_langEnv ) + { PRServLangEnv *langEnv = (PRServLangEnv *)_langEnv; + + //both suspended tasks and suspended explicit slaves resumed with this + writePrivQ( slave, langEnv->slavesReadyToResumeQ ); +//PR handles this.. PR_int__set_work_in_lang_env(langEnv); + + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS +/* + int lastRecordIdx = slave->counter_history_array_info->numInArray -1; + CounterRecord* lastRecord = slave->counter_history[lastRecordIdx]; + saveLowTimeStampCountInto(lastRecord->unblocked_timestamp); +*/ + #endif + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + slave->numTimesAssignedToASlot++; //Somewhere here! + Unit newU; + newU.vp = slave->slaveNum; + newU.task = slave->numTimesAssignedToASlot; + addToListOfArrays(Unit,newU,langEnv->unitList); + + if (slave->numTimesAssignedToASlot > 1) + { Dependency newD; + newD.from_vp = slave->slaveNum; + newD.from_task = slave->numTimesAssignedToASlot - 1; + newD.to_vp = slave->slaveNum; + newD.to_task = slave->numTimesAssignedToASlot; + addToListOfArrays(Dependency, newD ,langEnv->ctlDependenciesList); + } + #endif + } + +void +PRServ__handleDissipateSeed(void *langReq, SlaveVP *seedSlv, VSsLangEnv *langEnv ) + { + + DEBUG__printf1(dbgRqstHdlr,"Dissipate in PRServ %d", + requestingSlv->slaveNum); + //This should only ever be called for the seed slave -- for which there's + // nothing to do.. + if( seedSlv->typeOfVP != SeedSlv ) + { + PR_int__throw_exception( "PR__end_seed called on non-seed slave\n", NULL, NULL); + } + } + +void +PRServ__handle_end_process_from_inside( void *langReq, SlaveVP *reqSlave, PRServLangEnv *langEnv ) + { PR_SS__end_process_normally( reqSlave->processSlaveIsIn ); + } + + +/*Initialize semantic data struct.. this initializer doesn't need any input, + * but some languages may need something from inside the request that was sent + * to create a slave.. in that case, just make initializer do the malloc then + * use the PR_PI__give_lang_data inside the create handler, and fill in the + * langData values there. + */ +void * +PRServ__create_lang_data_in_slave( SlaveVP *slave ) + { PRServLangData *langData; + + + langData = PR_PI__create_lang_data_in_slave( sizeof(PRServLangData), + &PRServ__free_lang_data, slave, PRServ_MAGIC_NUMBER ); + + langData->highestTransEntered = -1; + langData->lastTransEntered = NULL; + return langData; + } + + +/*Register this by passing a pointer to this to PR's lang data creator Fn + * + *It deletes all the transactions that the slave had entered.. + *Probably a bug -- need to do something more to free blocked slaves waiting. + * + *At some point, may change PR so that it recycles langData, in which case this + * only gets called when a process shuts down.. at that point, PR will call + * dissipate on all the slaves it has in the recycle Q. + */ +void +PRServ__free_lang_data( void *_langData ) + { PRServLangData *langData; + PRServTransListElem *transElem, *nextTransElem; + + langData = (PRServLangData *)_langData; + transElem = langData->lastTransEntered; + + //Each trans the slave has entered was saved in a linked list elem inside + // lang data -- delete those linked list elements + //Bug: if this is not part of shutdown, then update state of transactions + // to free blocked VPs + while( transElem != NULL) + { nextTransElem = transElem->nextTrans; + PR_int__free( transElem ); + transElem = nextTransElem; + } + PR_PI__free( _langData ); + } + + +void +PRServ__lang_meta_task_freer( void *_langMetaTask ) + { //no PRServ meta tasks created, so nothing to do + } + + +/*Will be used by a langData recycler, when (and if) such a thing added + * to PR + */ +void +resetPRServLangData( void *_langData ) + { PRServLangData *langData = (PRServLangData *)_langData; + + langData->highestTransEntered = -1; + langData->lastTransEntered = NULL; + } + +//========================================================================== +// +// + + diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.h --- a/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.h Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Services_Language/PRServ_Request_Handlers.h Sat Mar 02 09:43:45 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2009 OpenSourceStewardshipFoundation.org + * Copyright 2009 OpenSourceResearchInstitute.org * Licensed under GNU General Public License version 2 * * Author: seanhalle@yahoo.com @@ -14,46 +14,55 @@ /*This header defines everything specific to the PRServ semantic plug-in */ +void +PRServ__handleMalloc( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv); +void +PRServ__handleFree( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv ); + +//============================================ +void +PRServ__handleStartFnSingleton( PRServLangReq *langReq, SlaveVP *reqstingSlv, + PRServLangEnv *langEnv ); +void +PRServ__handleEndFnSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ); inline void -handleSubmitTask( PRServSemReq *semReq, PRServSemEnv *semEnv); +PRServ__handleStartDataSingleton( PRServLangReq *langReq, SlaveVP *reqstingSlv, + PRServLangEnv *langEnv ); inline void -handleEndTask( PRServSemReq *semReq, PRServSemEnv *semEnv); -inline void -handleSendTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv); -inline void -handleSendFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv); -inline void -handleReceiveTypeTo( PRServSemReq *semReq, PRServSemEnv *semEnv); -inline void -handleReceiveFromTo( PRServSemReq *semReq, PRServSemEnv *semEnv); -inline void -handleTaskwait(PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv); +PRServ__handleEndDataSingleton( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ); +void +PRServ__handleTransStart( PRServLangReq *langReq, SlaveVP *requestingSlv, + PRServLangEnv *langEnv ); +void +PRServ__handleTransEnd(PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv*langEnv); -inline void -handleMalloc( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv); -inline void -handleFree( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv ); -inline void -handleTransEnd(PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv*semEnv); -inline void -handleTransStart( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ); -inline void -handleAtomic( PRServSemReq *semReq, SlaveVP *requestingSlv, PRServSemEnv *semEnv); -inline void -handleStartFnSingleton( PRServSemReq *semReq, SlaveVP *reqstingSlv, - PRServSemEnv *semEnv ); -inline void -handleEndFnSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ); -inline void -handleStartDataSingleton( PRServSemReq *semReq, SlaveVP *reqstingSlv, - PRServSemEnv *semEnv ); -inline void -handleEndDataSingleton( PRServSemReq *semReq, SlaveVP *requestingSlv, - PRServSemEnv *semEnv ); -inline void -free_task_stub( PRMetaTask *stubToFree ); +void +PRServ__handleAtomic( PRServLangReq *langReq, SlaveVP *requestingSlv, PRServLangEnv *langEnv); +//================================== +void +PRServ__make_task_ready( void *taskStub, void *_langEnv ); +void +PRServ__resume_slave( SlaveVP *slave, void *langEnv ); + +void +PRServ__handleDissipateSeed(void *langReq, SlaveVP *seedSlv, PRServLangEnv *langEnv ); + +void +PRServ__handle_end_process_from_inside( void *langReq, SlaveVP *reqSlave, PRServLangEnv *langEnv ); + +void +PRServ__handle_shutdown( void *_langEnv ); + +void * +PRServ__create_lang_data_in_slave( SlaveVP *slave ); + +void +PRServ__free_lang_data( void *_langData ); + +void +PRServ__lang_meta_task_freer( void *_langMetaTask ); #endif /* _PRServ_REQ_H */ diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ_SS.c --- a/Services_Offered_by_PR/Services_Language/PRServ_SS.c Tue Feb 05 20:23:27 2013 -0800 +++ b/Services_Offered_by_PR/Services_Language/PRServ_SS.c Sat Mar 02 09:43:45 2013 -0800 @@ -12,8 +12,7 @@ #include "Hash_impl/PrivateHash.h" #include "PRServ.h" -#include "Measurement/PRServ_Counter_Recording.h" - +#include "PR_impl/Services_Offered_by_PR/Measurement_and_Stats/PR_MEAS__Counter_Recording.h" //========================================================================== @@ -22,90 +21,69 @@ /* */ -void +PRServLangEnv * PRServ__start( SlaveVP *seedSlv ) - { PRServSemEnv *semEnv; - int32 i, coreNum, slotNum; - PRServSemData *semData; - PRServTaskStub *threadTaskStub, *parentTaskStub; + { PRServLangEnv *langEnv; + int32 i; - semEnv = PR_WL__malloc( sizeof(PRServSemEnv) ); + langEnv = + PR_SS__create_lang_env( sizeof(PRServLangEnv), seedSlv, PRServ_MAGIC_NUMBER); - PR_SS__register_langlets_semEnv( semEnv, seedSlv, PRServ_MAGIC_NUMBER ); + + //create the ready queues + langEnv->slavesReadyToResumeQ = makePRQ(); + langEnv->taskReadyQ = makePRQ(); - //seed slave is a thread slave, so make a thread's task stub for it - // and then make another to stand for the seed's parent task. Make - // the parent be already ended, and have one child (the seed). This - // will make the dissipate handler do the right thing when the seed - // is dissipated. - threadTaskStub = create_thread_task_stub( initData ); - parentTaskStub = create_thread_task_stub( NULL ); - parentTaskStub->isEnded = TRUE; - parentTaskStub->numLiveChildThreads = 1; //so dissipate works for seed - threadTaskStub->parentTaskStub = parentTaskStub; - - PR_SS__set_langMetaTask_for_seedSlv( threadTaskStub, seedSlv ); - - //Hook up the semantic layer's plug-ins to the Master virt procr - PR_SS__register_create_task_handler( &createTaskHandler, seedVP, PRServ_MAGIC_NUMBER ); - PR_SS__register_end_task_handler( &endTaskHandler, seedVP, PRServ_MAGIC_NUMBER ); - PR_SS__register_create_slave_handler( &createThreadHandler, seedVP, PRServ_MAGIC_NUMBER ); - PR_SS__register_dissipate_slave_handler( &endThreadHandler, seedVP, PRServ_MAGIC_NUMBER ); - PR_SS__register_request_handler( &PRServ__Request_Handler, seedVP, PRServ_MAGIC_NUMBER ); - PR_SS__register_assigner( &PRServ__assign_work_to_slot, seedVP, PRServ_MAGIC_NUMBER ); - RequestHandler createInitialSemDataFn; - RequestHandler resetSemDataFn; - + //register the langlet's handlers with PR + PR_SS__register_assigner( &PRServ__assign_work_to_slot, seedSlv, PRServ_MAGIC_NUMBER ); + PR_SS__register_lang_shutdown_handler( &PRServ__handle_shutdown, seedSlv, PRServ_MAGIC_NUMBER ); + PR_SS__register_lang_data_creator( &PRServ__create_lang_data_in_slave, seedSlv, PRServ_MAGIC_NUMBER ); +// PR_SS__register_lang_meta_task_creator( &PRServ__create_empty_lang_meta_task_in_slave, seedSlv, PRServ_MAGIC_NUMBER ); + PR_SS__register_make_slave_ready_fn( &PRServ__resume_slave, seedSlv, PRServ_MAGIC_NUMBER ); + PR_SS__register_make_task_ready_fn( &PRServ__make_task_ready, seedSlv, PRServ_MAGIC_NUMBER ); + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS - _PRTopEnv->counterHandler = &PRServ__counter_handler; - PRServ__init_counter_data_structs(); + _PRTopEnv->counterHandler = &PR_MEAS__counter_handler; + PR_MEAS__init_counter_data_structs_for_lang( seedSlv, PRServ_MAGIC_NUMBER ); #endif - - //create the ready queues, hash tables used for matching and so forth - semEnv->slavesReadyToResumeQ = makePRQ(); - semEnv->taskReadyQ = makePRQ(); - semEnv->argPtrHashTbl = makeHashTable32( 16, &PR_int__free ); - semEnv->commHashTbl = makeHashTable32( 16, &PR_int__free ); - - semEnv->nextCoreToGetNewSlv = 0; - - //TODO: bug -- turn these arrays into dyn arrays to eliminate limit - //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); - //semanticEnv->transactionStrucs = makeDynArrayInfo( ); - for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) + //langEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); + //langEnv->transactionStrucs = makeDynArrayInfo( ); + for( i = 0; i < NUM_STRUCS_IN_LANG_ENV; i++ ) { - semEnv->fnSingletons[i].endInstrAddr = NULL; - semEnv->fnSingletons[i].hasBeenStarted = FALSE; - semEnv->fnSingletons[i].hasFinished = FALSE; - semEnv->fnSingletons[i].waitQ = makePRQ(); - semEnv->transactionStrucs[i].waitingVPQ = makePRQ(); + langEnv->fnSingletons[i].endInstrAddr = NULL; + langEnv->fnSingletons[i].hasBeenStarted = FALSE; + langEnv->fnSingletons[i].hasFinished = FALSE; + langEnv->fnSingletons[i].waitQ = makePRQ(); + langEnv->transactionStrucs[i].waitingVPQ = makePRQ(); } #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - semEnv->unitList = makeListOfArrays(sizeof(Unit),128); - semEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); - semEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); - semEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); - semEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semEnv->ntonGroups),8); + langEnv->unitList = makeListOfArrays(sizeof(Unit),128); + langEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); + langEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); + langEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); + langEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(langEnv->ntonGroups),8); - semEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); - memset(semEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); + langEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); + memset(langEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); #endif + + return langEnv; } -/*Frees any memory allocated by PRServ__init() then calls PR_int__shutdown +/*This shuts down the langlet + * Frees any memory allocated by PRServ__init() and deletes any slaves or tasks + * still in ready Qs. */ void -PRServ__cleanup_after_shutdown() - { PRServSemEnv *semanticEnv; +PRServ__handle_shutdown( void *_langEnv ) + { PRServLangEnv *langEnv = (PRServLangEnv *)_langEnv; - semanticEnv = _PRTopEnv->semanticEnv; - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC //UCC FILE* output; @@ -131,10 +109,10 @@ //set_dot_file(output); //FIXME: first line still depends on counters being enabled, replace w/ unit struct! //forAllInDynArrayDo(_PRTopEnv->counter_history_array_info, &print_dot_node_info ); - forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file); - forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); - forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file); + forAllInListOfArraysDo(langEnv->unitList, &print_unit_to_file); + forAllInListOfArraysDo( langEnv->commDependenciesList, &print_comm_dependency_to_file ); + forAllInListOfArraysDo( langEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); + forAllInDynArrayDo(langEnv->ntonGroupsInfo,&print_nton_to_file); //fprintf(output,"}\n"); fflush(output); @@ -164,11 +142,11 @@ //set_dot_file(output); //FIXME: first line still depends on counters being enabled, replace w/ unit struct! //forAllInDynArrayDo(_PRTopEnv->counter_history_array_info, &print_dot_node_info ); - forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file ); - forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file ); + forAllInListOfArraysDo( langEnv->unitList, &print_unit_to_file ); + forAllInListOfArraysDo( langEnv->commDependenciesList, &print_comm_dependency_to_file ); + forAllInListOfArraysDo( langEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); + forAllInListOfArraysDo( langEnv->dynDependenciesList, &print_dyn_dependency_to_file ); + forAllInListOfArraysDo( langEnv->hwArcs, &print_hw_dependency_to_file ); //fprintf(output,"}\n"); fflush(output); @@ -179,10 +157,10 @@ } - freeListOfArrays(semanticEnv->unitList); - freeListOfArrays(semanticEnv->commDependenciesList); - freeListOfArrays(semanticEnv->ctlDependenciesList); - freeListOfArrays(semanticEnv->dynDependenciesList); + freeListOfArrays(langEnv->unitList); + freeListOfArrays(langEnv->commDependenciesList); + freeListOfArrays(langEnv->ctlDependenciesList); + freeListOfArrays(langEnv->dynDependenciesList); #endif #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS @@ -201,12 +179,13 @@ printf("Saving Counter measurements to File: %s ...\n", filename); output = fopen(filename,"w+"); if(output!=NULL){ + int i; set_counter_file(output); - int i; - for(i=0;icounterList[i], &print_counter_events_to_file ); - fflush(output); - } + for(i=0;icounterList[i], &PR_MEAS__print_counter_event_to_file ); + fflush(output); + } } else printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); @@ -215,21 +194,39 @@ } #endif -/* It's all allocated inside PR's big chunk -- that's about to be freed, so - * nothing to do here - - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) + //Things to free: + // tasks and slaves in ready Qs + // ready Qs + // tasks and slaves in the comm hash table + // comm hash table + // tasks in the argPtrHashTbl + // the argPtrHashTbl + PrivQueueStruc *queue; + SlaveVP *slave; + + //dissipate any slaves still in the readyQ, because this is last lang + queue = langEnv->slavesReadyToResumeQ; + slave = readPrivQ( queue ); + while( slave != NULL ) + { + PR_int__recycle_slaveVP( slave ); //recycler is for all of PR + slave = readPrivQ( queue ); + } + freePrivQ( queue ); + + //no any tasks in the readyQ + queue = langEnv->taskReadyQ; + freePrivQ( queue ); + + int32 i; + for( i = 0; i < NUM_STRUCS_IN_LANG_ENV; i++ ) { - PR_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); - PR_int__free( semanticEnv->readyVPQs[coreIdx] ); + freePrivQ( langEnv->fnSingletons[i].waitQ ); + freePrivQ( langEnv->transactionStrucs[i].waitingVPQ ); } - PR_int__free( semanticEnv->readyVPQs ); - freeHashTable( semanticEnv->commHashTbl ); - PR_int__free( _PRTopEnv->semanticEnv ); - */ - PR_SS__cleanup_at_end_of_shutdown(); + PR_int__remove_lang_env_from_process_and_free( langEnv ); } diff -r bc5030385120 -r 40e7625e57bd Services_Offered_by_PR/Services_Language/PRServ_singleton_asm.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Services_Offered_by_PR/Services_Language/PRServ_singleton_asm.s Sat Mar 02 09:43:45 2013 -0800 @@ -0,0 +1,21 @@ + +//Assembly code takes the return addr off the stack and saves +// into the singleton. The first field in the singleton is the +// "endInstrAddr" field, and the return addr is at 0x4(%ebp) +.globl asm_save_ret_to_singleton +asm_save_ret_to_singleton: + movq 0x8(%rbp), %rax #get ret address, ebp is the same as in the calling function + movq %rax, (%rdi) #write ret addr to endInstrAddr field + ret + + +//Assembly code changes the return addr on the stack to the one +// saved into the singleton by the end-singleton-fn +//The stack's return addr is at 0x4(%%ebp) +.globl asm_write_ret_from_singleton +asm_write_ret_from_singleton: + movq (%rdi), %rax #get endInstrAddr field + movq %rax, 0x8(%rbp) #write return addr to the stack of the caller + ret + +