seanhalle@230: /* seanhalle@270: * Copyright 2012 OpenSourceResearchInstitute.org seanhalle@230: * seanhalle@230: * Licensed under BSD seanhalle@230: */ seanhalle@230: seanhalle@230: seanhalle@230: seanhalle@230: #include seanhalle@230: #include seanhalle@230: seanhalle@260: #include "PR.h" seanhalle@261: #include "VSs_impl/VSs.h" seanhalle@230: seanhalle@273: //========================= Local Declarations ======================== seanhalle@273: inline PRProcess * seanhalle@273: pickAProcess( AnimSlot *slot ); seanhalle@273: inline bool32 seanhalle@273: assignWork( PRProcess *process, AnimSlot *slot ); seanhalle@230: seanhalle@273: inline void seanhalle@273: PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ); seanhalle@273: inline void seanhalle@273: PRHandle__EndTask( PRReqst *req, SlaveVP *slave ); seanhalle@273: inline void seanhalle@273: PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave ); seanhalle@273: inline void seanhalle@273: PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ); seanhalle@268: seanhalle@273: inline void seanhalle@273: PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ); seanhalle@268: seanhalle@273: inline void seanhalle@273: handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); seanhalle@273: inline void seanhalle@273: handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ); seanhalle@230: seanhalle@273: //=========================================================================== seanhalle@272: seanhalle@272: /*Note: there used to be a coreController that was another animation seanhalle@272: * layer below both the masterVP and the slaveVPs.. in that case, the seanhalle@272: * masterVP was a virtual processor whose processor-state was the same seanhalle@272: * as a slaveVP's processor sate, both implemented as a SlaveVP struct. seanhalle@272: * Have removed that, and seanhalle@272: * changed the masterVP implementation. Instead of being a special version seanhalle@272: * of a proto-runtime virtual processor, using the slaveVP stuct, the seanhalle@272: * Master "virtual processor" is now implemented as a pthread pinned to seanhalle@272: * a physical core. seanhalle@260: */ seanhalle@260: seanhalle@272: /*This is the behavior of the Master. The physical processor switches seanhalle@272: * between animating the master, and animating a slave. When a slave seanhalle@272: * suspends, the PR "suspend" primitive switches the physical core over seanhalle@272: * to animating the masterVP, which is implemented as a pinned pthread. seanhalle@272: * This function is the behavior of that masterVP. seanhalle@272: *This function's job is to manage processing seanhalle@272: * requests and to trigger assignment of new work to the physical core, seanhalle@272: * and to manage sharing the core among processes. seanhalle@272: */ seanhalle@261: inline seanhalle@270: bool32 seanhalle@269: masterFunction( AnimSlot *slot ) seanhalle@261: { //Scan the animation slots seanhalle@261: int32 magicNumber; seanhalle@261: SlaveVP *slave; seanhalle@268: PRLangEnv *langEnv; seanhalle@261: PRReqst *req; seanhalle@268: PRProcess *process; seanhalle@273: bool32 didAssignWork; seanhalle@260: seanhalle@268: //Check if newly-done slave in slot, which will need request handled seanhalle@272: //NOTE: left over from when had a coreController & MasterVP managed seanhalle@272: // several slots seanhalle@268: if( slot->workIsDone ) seanhalle@268: { slot->workIsDone = FALSE; seanhalle@268: slot->needsWorkAssigned = TRUE; seanhalle@273: seanhalle@273: //An Idle VP has no request to handle, so skip to assign.. seanhalle@273: if( slot->slaveAssignedToSlot->typeOfVP != IdleVP ) seanhalle@273: { seanhalle@273: HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot seanhalle@273: MEAS__startReqHdlr; seanhalle@261: seanhalle@261: seanhalle@273: //process the request made by the slave (held inside slave struc) seanhalle@273: slave = slot->slaveAssignedToSlot; seanhalle@273: req = slave->request; seanhalle@268: seanhalle@273: //If the requesting slave is a slot slave, and request is not seanhalle@273: // task-end, then turn it into a free task slave & continue seanhalle@273: if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd ) seanhalle@273: PR_int__replace_with_new_slot_slv( slave ); seanhalle@268: seanhalle@273: //Handle task create and end first -- they're special cases.. seanhalle@273: switch( req->reqType ) seanhalle@273: { case TaskEnd: seanhalle@273: { //do PR handler, which calls lang's hdlr and does recycle of seanhalle@273: // free task slave if needed -- PR handler checks for free task Slv seanhalle@273: PRHandle__EndTask( req, slave ); break; seanhalle@273: } seanhalle@273: case TaskCreate: seanhalle@273: { //Do PR's create-task handler, which calls the lang's hdlr seanhalle@273: // PR handler checks for free task Slv seanhalle@273: PRHandle__CreateTask( req, slave ); break; seanhalle@273: } seanhalle@273: case SlvCreate: PRHandle__CreateSlave( req, slave ); break; seanhalle@273: case SlvDissipate: PRHandle__EndSlave( req, slave ); break; seanhalle@273: case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env seanhalle@273: case Hardware: //for future expansion seanhalle@273: case IO: //for future expansion seanhalle@273: case OSCall: //for future expansion seanhalle@273: PR_int__throw_exception("Not implemented", slave, NULL); break; seanhalle@273: case LangShutdown: PRHandle__LangShutdown( req, slave ); break; seanhalle@273: case Language: //normal lang request seanhalle@273: { magicNumber = req->langMagicNumber; seanhalle@273: langEnv = PR_PI__give_lang_env_for_slave( slave, magicNumber ); seanhalle@273: (*req->handler)( req->langReq, slave, langEnv ); seanhalle@273: } seanhalle@267: } seanhalle@273: seanhalle@268: MEAS__endReqHdlr; seanhalle@267: HOLISTIC__Record_AppResponder_end; seanhalle@273: }//if not idleVP seanhalle@268: } //if have request to be handled seanhalle@268: seanhalle@272: //NOTE: IF statement is leftover from when master managed many slots seanhalle@273: didAssignWork = FALSE; seanhalle@273: if( slot->needsWorkAssigned ) //can probably remove IF, now that only one slot seanhalle@268: { seanhalle@268: HOLISTIC__Record_Assigner_start; seanhalle@272: seanhalle@268: //Pick a process to get this slot seanhalle@268: process = pickAProcess( slot ); seanhalle@268: seanhalle@268: //Scan lang environs, looking for langEnv with ready work. seanhalle@268: // call the Assigner for that lang Env, to get a slave for the slot seanhalle@273: if( process != NULL ) seanhalle@273: { didAssignWork = seanhalle@273: assignWork( process, slot ); seanhalle@273: } seanhalle@268: HOLISTIC__Record_Assigner_end; seanhalle@272: seanhalle@273: if( !didAssignWork ) //if no work assigned, be sure idle slave is in slot seanhalle@273: { slot->slaveAssignedToSlot = _PRTopEnv->idleSlv[slot->coreSlotIsOn][0]; seanhalle@273: } seanhalle@273: // fixme; //make into a loop that tries more processes if fails to assign seanhalle@268: }//if slot needs slave assigned seanhalle@270: seanhalle@273: return didAssignWork; seanhalle@261: } seanhalle@260: seanhalle@268: /*When several processes exist, use some pattern for picking one to give seanhalle@268: * the animation slot to. seanhalle@268: *First, it has to be a process that has work available. seanhalle@268: *For now, just do a round-robin seanhalle@261: */ seanhalle@268: inline seanhalle@268: PRProcess * seanhalle@268: pickAProcess( AnimSlot *slot ) seanhalle@268: { int32 idx; seanhalle@268: PRProcess *process; seanhalle@268: seanhalle@268: for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++) seanhalle@268: { seanhalle@268: process = _PRTopEnv->processes[ idx ]; seanhalle@268: if( process->numEnvsWithWork != 0 ) seanhalle@268: { _PRTopEnv->currProcessIdx = idx; seanhalle@268: return process; seanhalle@268: } seanhalle@261: } seanhalle@268: for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++) seanhalle@268: { seanhalle@268: process = _PRTopEnv->processes[ idx ]; seanhalle@268: if( process->numEnvsWithWork != 0 ) seanhalle@268: { _PRTopEnv->currProcessIdx = idx; seanhalle@268: return process; seanhalle@268: } seanhalle@268: } seanhalle@268: //none found seanhalle@268: return NULL; seanhalle@260: } seanhalle@260: seanhalle@261: /*This does: seanhalle@268: * 1) searches the language environments for one with work ready seanhalle@261: * if finds one, asks its assigner to return work seanhalle@261: * 2) checks what kind of work: new task, resuming task, resuming slave seanhalle@261: * if new task, gets the slot slave and assigns task to it and returns slave seanhalle@261: * else, gets the slave attached to the metaTask and returns that. seanhalle@261: * 3) if no work found, then prune former task slaves waiting to be recycled. seanhalle@261: * If no work and no slaves to prune, check for shutdown conditions. seanhalle@261: * seanhalle@268: * language env keeps its own work in its own structures, and has its own seanhalle@261: * assigner. It chooses seanhalle@261: * However, include a switch that switches-in an override assigner, which seanhalle@268: * sees all the work in all the language env's. This is most likely seanhalle@261: * generated by static tools and included in the executable. That means it seanhalle@261: * has to be called via a registered pointer from here. The idea is that seanhalle@261: * the static tools know which languages are grouped together.. and the seanhalle@261: * override enables them to generate a custom assigner that uses info from seanhalle@261: * all the languages in a unified way.. Don't really expect this to happen, seanhalle@261: * but am making it possible. seanhalle@260: */ seanhalle@268: inline seanhalle@270: bool32 seanhalle@261: assignWork( PRProcess *process, AnimSlot *slot ) seanhalle@272: { int32 coreNum; seanhalle@260: seanhalle@261: coreNum = slot->coreSlotIsOn; seanhalle@260: seanhalle@267: if( process->overrideAssigner != NULL ) seanhalle@268: { if( process->numEnvsWithWork != 0 ) seanhalle@268: { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot seanhalle@268: goto ReturnAfterAssigningWork; //quit for-loop, cause found work seanhalle@261: } seanhalle@268: else seanhalle@261: goto NoWork; seanhalle@261: } seanhalle@261: seanhalle@268: //If here, then no override assigner, so search language envs for work seanhalle@273: int32 envIdx, numEnvs; PRLangEnv **protoLangEnvsList, *protoLangEnv; seanhalle@273: protoLangEnvsList = process->protoLangEnvsList; seanhalle@268: numEnvs = process->numLangEnvs; seanhalle@268: for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array seanhalle@273: { protoLangEnv = protoLangEnvsList[envIdx]; seanhalle@273: if( protoLangEnv->numReadyWork > 0 ) seanhalle@272: { bool32 seanhalle@272: didAssignWork = seanhalle@273: (*protoLangEnv->workAssigner)( PR_int__give_lang_env(protoLangEnv), slot ); //assigner calls PR to put slave/task into slot seanhalle@272: seanhalle@272: if(didAssignWork) seanhalle@273: { protoLangEnv->numReadyWork -= 1; seanhalle@273: if( protoLangEnv->numReadyWork == 0 ) seanhalle@272: { process->numEnvsWithWork -= 1; seanhalle@272: } seanhalle@272: goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work seanhalle@272: } seanhalle@272: else seanhalle@272: goto NoWork; //quit for-loop, cause found work seanhalle@272: seanhalle@268: //NOTE: bad search alg -- should start where left off, then wrap around seanhalle@260: } seanhalle@260: } seanhalle@268: //If reach here, then have searched all langEnv's & none have work.. seanhalle@260: seanhalle@268: NoWork: //No work, if end up here.. seanhalle@260: { seanhalle@260: #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC seanhalle@272: returnSlv = process->idleSlv[coreNum][0]; //only one slot now, so [0] seanhalle@260: seanhalle@260: //things that would normally happen in resume(), but idle VPs seanhalle@260: // never go there seanhalle@261: returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID seanhalle@260: Unit newU; seanhalle@268: newU.vp = returnSlv->slaveNum; seanhalle@261: newU.task = returnSlv->numTimesAssignedToASlot; seanhalle@261: addToListOfArrays(Unit,newU,process->unitList); seanhalle@260: seanhalle@261: if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit seanhalle@260: { Dependency newD; // to this one seanhalle@268: newD.from_vp = returnSlv->slaveNum; seanhalle@261: newD.from_task = returnSlv->numTimesAssignedToASlot - 1; seanhalle@268: newD.to_vp = returnSlv->slaveNum; seanhalle@261: newD.to_task = returnSlv->numTimesAssignedToASlot; seanhalle@261: addToListOfArrays(Dependency, newD ,process->ctlDependenciesList); seanhalle@260: } seanhalle@268: #endif seanhalle@268: HOLISTIC__Record_Assigner_end; seanhalle@269: return FALSE; seanhalle@260: } seanhalle@268: seanhalle@268: ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic.. seanhalle@268: { seanhalle@268: HOLISTIC__Record_Assigner_end; seanhalle@269: return TRUE; seanhalle@260: } seanhalle@260: } seanhalle@260: seanhalle@260: seanhalle@273: //================================= seanhalle@273: //=== seanhalle@273: //= seanhalle@273: /*Create task is a special form, that has PR behavior in addition to plugin seanhalle@273: * behavior. Master calls this first, and it then calls the plugin's seanhalle@273: * create task handler. seanhalle@273: * seanhalle@273: *Note: the requesting slave must be either generic slave or free task slave seanhalle@273: */ seanhalle@273: inline seanhalle@273: void seanhalle@273: PRHandle__CreateTask( PRReqst *req, SlaveVP *slave ) seanhalle@273: { PRMetaTask *protoMetaTask; seanhalle@273: PRProcess *process; seanhalle@273: PRLangEnv *protoLangEnv; seanhalle@273: void *task; seanhalle@273: seanhalle@273: process = slave->processSlaveIsIn; seanhalle@273: seanhalle@273: protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, seanhalle@273: req->langMagicNumber ); seanhalle@273: seanhalle@273: //Do the langlet's create-task handler, which keeps the task seanhalle@273: // inside the langlet's lang env, but returns the langMetaTask seanhalle@273: // so that PR can then put stuff into the prolog seanhalle@273: //typedef void * (*CreateHandler)( void *, SlaveVP *, void * ); //req, slv, langEnv seanhalle@273: // seanhalle@273: task = seanhalle@273: (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); seanhalle@273: protoMetaTask = PR_int__give_prolog_of_lang_meta_task( task ); seanhalle@273: protoMetaTask->ID = req->ID; //may be NULL seanhalle@273: protoMetaTask->topLevelFn = req->topLevelFn; seanhalle@273: protoMetaTask->initData = req->initData; seanhalle@273: protoMetaTask->processTaskIsIn = process; seanhalle@273: seanhalle@273: process->numLiveTasks += 1; seanhalle@273: protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead seanhalle@273: seanhalle@273: return; seanhalle@273: } seanhalle@273: seanhalle@273: /*When a task ends, have two scenarios: 1) task ran to completion, or 2) task seanhalle@273: * has been suspended at some point in its code. seanhalle@273: *For 1, just decr count of live tasks (and check for end condition) -- the seanhalle@273: * master loop will decide what goes into the slot freed up by this task end, seanhalle@273: * so, here, don't worry about assigning a new task to the slot slave. seanhalle@273: *For 2, the task's slot slave has been converted to a free task slave, which seanhalle@273: * now has nothing more to do, so send it to the recycle Q (which includes seanhalle@273: * freeing all the langData and meta task structs alloc'd for it). Then seanhalle@273: * decrement the live task count and check end condition. seanhalle@273: * seanhalle@273: *PR has to update count of live tasks, and check end of process condition. seanhalle@273: * The "main" can invoke constructs that wait for a process to end, so when seanhalle@273: * end detected, have to resume what's waiting.. seanhalle@273: *Thing is, that wait involves the main OS thread. That means seanhalle@273: * PR internals have to do OS thread signaling. Want to do that in the seanhalle@273: * core controller, which has the original stack of an OS thread. So the seanhalle@273: * end process handling happens in the core controller. seanhalle@273: * seanhalle@273: *So here, when detect process end, signal to the core controller, which will seanhalle@273: * then do the condition variable notify to the OS thread that's waiting. seanhalle@273: * seanhalle@273: *Note: slave may be either a slot slave or a free task slave. seanhalle@273: */ seanhalle@273: inline seanhalle@273: void seanhalle@273: PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv ) seanhalle@273: { void *langEnv; seanhalle@273: PRLangEnv *protoLangEnv; seanhalle@273: PRProcess *process; seanhalle@273: void *langMetaTask; seanhalle@273: seanhalle@273: process = requestingSlv->processSlaveIsIn; seanhalle@273: langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req seanhalle@273: protoLangEnv = PR_int__give_proto_lang_env( langEnv ); seanhalle@273: seanhalle@273: langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber); seanhalle@273: seanhalle@273: //Do the langlet's request handler seanhalle@273: //Want to keep PR structs hidden from plugin, so extract langReq.. seanhalle@273: //This is supposed to free any langlet-malloc'd mem, including meta task seanhalle@273: (*req->handler)( req->langReq, requestingSlv, langEnv ); seanhalle@273: seanhalle@273: protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead seanhalle@273: if( protoLangEnv->numLiveWork == 0 && seanhalle@273: numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) seanhalle@273: { SlaveVP * seanhalle@273: waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); seanhalle@273: //can't resume into langlet that just ended its last work! seanhalle@273: // and don't have env that the waiter was created in, so resume seanhalle@273: // into PRServ env.. seanhalle@273: void * seanhalle@273: resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); seanhalle@273: while( waitingSlave != NULL ) seanhalle@273: { //resume a slave that was waiting for work in this env to finish seanhalle@273: PR_PI__make_slave_ready( waitingSlave, resumeEnv ); seanhalle@273: //get next waiting slave, repeat.. seanhalle@273: waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); seanhalle@273: } seanhalle@273: } seanhalle@273: seanhalle@273: seanhalle@273: //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv seanhalle@273: if( requestingSlv->typeOfVP == FreeTaskSlv ) seanhalle@273: PR_int__recycle_slaveVP( requestingSlv ); //Doesn't decr num live slaves seanhalle@273: seanhalle@273: process->numLiveTasks -= 1; seanhalle@273: //NOTE: end-task is unrelated to work available (just in case wondering) seanhalle@273: seanhalle@273: //check End Of Process Condition seanhalle@273: if( process->numLiveTasks == 0 && seanhalle@273: process->numLiveGenericSlvs == 0 ) seanhalle@273: { //Tell the core controller to do wakeup of any waiting OS thread seanhalle@273: PR_SS__end_process_normally( process ); seanhalle@273: } seanhalle@273: } seanhalle@273: seanhalle@273: seanhalle@268: seanhalle@268: /*This is first thing called when creating a slave.. it hands off to the seanhalle@268: * langlet's creator, then adds updates of its own.. seanhalle@268: * seanhalle@268: *There's a question of things like lang data, meta tasks, and such.. seanhalle@268: *In creator, only PR related things happen, and things for the langlet whose seanhalle@261: * creator construct was used. seanhalle@268: * seanhalle@268: *Other langlets still get a chance to create langData -- but by registering a seanhalle@268: * "createLangData" handler in the langEnv. When a construct of the langlet seanhalle@268: * calls "PR__give_lang_data()", if there is no langData for that langlet, seanhalle@268: * the PR will call the creator in the langlet's langEnv, place whatever it seanhalle@268: * makes as the langData in that slave for that langlet, and return that langData seanhalle@261: * seanhalle@261: *So, as far as counting things, a langlet is only allowed to count creation seanhalle@261: * of slaves it creates itself.. may have to change this later.. add a way for seanhalle@261: * langlet to register a trigger Fn called each time a slave gets created.. seanhalle@261: * need more experience with what langlets will do at create time.. think Cilk seanhalle@261: * has interesting create behavior.. not sure how that will differ in light seanhalle@261: * of true tasks and langlet approach. Look at it after all done and start seanhalle@261: * modifying the langs to be langlets.. seanhalle@261: * seanhalle@261: *PR itself needs to create the slave, then update numLiveSlaves in process, seanhalle@261: * copy processID from requestor to newly created seanhalle@261: */ seanhalle@268: inline seanhalle@268: void seanhalle@272: PRHandle__CreateSlave( PRReqst *req, SlaveVP *slave ) seanhalle@268: { SlaveVP *newSlv; seanhalle@261: PRProcess *process; seanhalle@268: PRLangEnv *protoLangEnv; seanhalle@261: seanhalle@268: process = slave->processSlaveIsIn; seanhalle@273: protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, req->langMagicNumber ); seanhalle@272: seanhalle@272: //create handler, or a future request handler will call PR_PI__make_slave_ready seanhalle@272: // which will in turn handle updating which langlets and which processes have seanhalle@272: // work available. seanhalle@272: //NOTE: create slv has diff prototype than standard reqst hdlr seanhalle@268: newSlv = seanhalle@268: (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv)); seanhalle@268: seanhalle@261: newSlv->typeOfVP = GenericSlv; seanhalle@261: newSlv->processSlaveIsIn = process; seanhalle@268: newSlv->ID = req->ID; seanhalle@272: process->numLiveGenericSlvs += 1; //not same as work ready! seanhalle@273: protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead seanhalle@260: } seanhalle@260: seanhalle@268: /*The dissipate handler has to, update the number of slaves of the type, within seanhalle@261: * the process, and call the langlet handler linked into the request, seanhalle@261: * and after that returns, then call the PR function that frees the slave state seanhalle@261: * (or recycles the slave). seanhalle@261: * seanhalle@261: *The PR function that frees the slave state has to also free all of the seanhalle@268: * langData in the slave.. or else reset all of the langDatas.. by, say, marking seanhalle@268: * them, then in PR__give_langData( magicNum ) call the langlet registered seanhalle@268: * "resetLangData" Fn. seanhalle@261: */ seanhalle@268: inline seanhalle@268: void seanhalle@272: PRHandle__EndSlave( PRReqst *req, SlaveVP *slave ) seanhalle@261: { PRProcess *process; seanhalle@268: PRLangEnv *protoLangEnv; seanhalle@261: seanhalle@261: process = slave->processSlaveIsIn; seanhalle@261: seanhalle@261: //do the language's dissipate handler seanhalle@273: protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, slave->request->langMagicNumber ); seanhalle@268: seanhalle@268: if(req->handler != NULL) seanhalle@268: (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); seanhalle@261: seanhalle@273: protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead seanhalle@273: if( protoLangEnv->numLiveWork == 0 && seanhalle@273: numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 ) seanhalle@273: { SlaveVP * seanhalle@273: waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); seanhalle@273: //can't resume into langlet that just ended its last work! seanhalle@273: // and don't have env that the waiter was created in, so resume seanhalle@273: // into PRServ env.. seanhalle@273: void * seanhalle@273: resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER ); seanhalle@273: while( waitingSlave != NULL ) seanhalle@273: { //resume a slave that was waiting for work in this env to finish seanhalle@273: PR_PI__make_slave_ready( waitingSlave, resumeEnv ); seanhalle@273: //get next waiting slave, repeat.. seanhalle@273: waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ ); seanhalle@273: } seanhalle@273: } seanhalle@273: seanhalle@272: process->numLiveGenericSlvs -= 1; seanhalle@273: PR_int__recycle_slaveVP( slave ); seanhalle@272: //NOTE: dissipate is unrelated to work available (just in case wondering) seanhalle@272: seanhalle@261: //check End Of Process Condition seanhalle@261: if( process->numLiveTasks == 0 && seanhalle@266: process->numLiveGenericSlvs == 0 ) seanhalle@273: PR_SS__end_process_normally( process ); seanhalle@261: } seanhalle@261: seanhalle@273: //======================= seanhalle@273: //=== seanhalle@273: //= seanhalle@273: /*Langlet shutdown triggers this, which calls the registered shutdown seanhalle@273: * handler for the langlet, and removes the lang's env from the process seanhalle@261: */ seanhalle@268: inline seanhalle@268: void seanhalle@273: PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv ) seanhalle@273: { void *langEnv; seanhalle@273: PRLangEnv *protoLangEnv; seanhalle@273: PRProcess *process; seanhalle@268: seanhalle@273: process = requestingSlv->processSlaveIsIn; seanhalle@273: protoLangEnv = PR_int__give_proto_lang_env_from_process( process, req->langMagicNumber ); seanhalle@273: langEnv = PR_int__give_lang_env( protoLangEnv ); seanhalle@268: seanhalle@273: //call the langlet's registered handler seanhalle@273: (*protoLangEnv->shutdownHdlr)( langEnv ); seanhalle@267: seanhalle@273: PR_int__remove_lang_env_from_process_and_free( langEnv ); //removes from process and frees seanhalle@261: } seanhalle@261: seanhalle@272: seanhalle@272: /*This is for OS requests and PR infrastructure requests, which are not seanhalle@272: * part of the PRServ language -- this is for things that have to be in the seanhalle@272: * infrastructure of PR itself, such as I/O requests, which have to go through seanhalle@272: * pthreads inside the core controller.. seanhalle@272: * seanhalle@272: *As of Jan 2013, doesn't do much of anything.. seanhalle@272: */ seanhalle@272: void inline seanhalle@272: PRHandle__ServiceReq( SlaveVP *requestingSlv ) seanhalle@273: { PRReqst *req; seanhalle@273: PRServiceReq *langReq; seanhalle@273: PRLangEnv *protoLangEnv; seanhalle@273: int32 magicNumber; seanhalle@272: seanhalle@272: seanhalle@272: req = requestingSlv->request; seanhalle@272: seanhalle@272: magicNumber = req->langMagicNumber; seanhalle@273: protoLangEnv = PR_int__give_proto_lang_env_for_slave( requestingSlv, magicNumber ); seanhalle@272: seanhalle@272: langReq = PR_PI__take_lang_reqst_from(req); seanhalle@272: if( langReq == NULL ) return; seanhalle@272: switch( langReq->reqType ) //lang handlers are all in other file seanhalle@272: { seanhalle@273: case make_probe: handleMakeProbe( langReq, protoLangEnv ); seanhalle@272: break; seanhalle@273: case throw_excp: handleThrowException( langReq, protoLangEnv ); seanhalle@272: break; seanhalle@272: } seanhalle@272: } seanhalle@273: seanhalle@273: seanhalle@273: /*These handlers are special -- they don't belong to a language, because they seanhalle@273: * deal with things internal to PR, so put them here.. seanhalle@273: */ seanhalle@273: inline seanhalle@273: void seanhalle@273: handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) seanhalle@273: { IntervalProbe *newProbe; seanhalle@273: seanhalle@273: newProbe = PR_int__malloc( sizeof(IntervalProbe) ); seanhalle@273: newProbe->nameStr = PR_int__strDup( langReq->nameStr ); seanhalle@273: newProbe->hist = NULL; seanhalle@273: newProbe->schedChoiceWasRecorded = FALSE; seanhalle@273: seanhalle@273: //This runs in masterVP, so no race-condition worries seanhalle@273: //BUG: move to process seanhalle@273: newProbe->probeID = seanhalle@273: addToDynArray( newProbe, _PRTopEnv->dynIntervalProbesInfo ); seanhalle@273: seanhalle@273: langReq->requestingSlv->dataRetFromReq = newProbe; seanhalle@273: seanhalle@273: (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); seanhalle@273: } seanhalle@273: seanhalle@273: inline seanhalle@273: void seanhalle@273: handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv ) seanhalle@273: { seanhalle@273: PR_int__throw_exception( langReq->msgStr, langReq->requestingSlv, langReq->exceptionData ); seanhalle@273: seanhalle@273: (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) ); seanhalle@273: } seanhalle@273: