# HG changeset patch # User Sean Halle # Date 1358206283 28800 # Node ID e5bd470b562b4b7df73fb22b1b5e2ebc3d84c92f # Parent 608833ae2c5db11e31aa853f987e62c812835a18 Checkpoint 2 -- split up header file, and about to delete single lang version of AnimationMaster diff -r 608833ae2c5d -r e5bd470b562b AnimationMaster.c --- a/AnimationMaster.c Sun Nov 04 18:39:28 2012 -0800 +++ b/AnimationMaster.c Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2010 OpenSourceStewardshipFoundation + * Copyright 2010 OpenSourceResearchInstitute * * Licensed under BSD */ @@ -12,9 +12,23 @@ #include "PR.h" #include "VSs_impl/VSs.h" -inline void -replaceWithNewSlotSlv( SlaveVP *slave ); +/* +void PRHandle_CreateTask_SL(SlaveVP *slave); +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_Dissipate( PRReqst *req, SlaveVP *slave ); + + +//inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot ); +inline void masterFunction_MultiLang( AnimSlot *slot ); +inline PRProcess * pickAProcess( AnimSlot *slot ); +inline SlaveVP * assignWork( PRProcess *process, AnimSlot *slot ); /*The animationMaster embodies most of the animator of the language. The * animator is what emodies the behavior of language constructs. @@ -40,6 +54,81 @@ * */ +//This version of the master selects one of three loops, depending upon +// whether stand-alone single language (just slaves), or standalone with +// tasks, or multi-lang (implies multi-process) +void animationMaster( void *_environment, SlaveVP *masterVP ) + { + TopEnv *masterEnv = (TopEnv *)_environment; + int32 slotIdx; + AnimSlot *currSlot; + //Used while scanning and filling animation slots + AnimSlot **animSlots; + + //Local copies, for performance + int32 thisCoresIdx; + + //======================== Initializations ======================== + thisCoresIdx = masterVP->coreAnimatedBy; + animSlots = masterEnv->allAnimSlots[thisCoresIdx]; + + HOLISTIC__Insert_Master_Global_Vars; + + //======================== animationMaster ======================== + //Have three different modes, and the master behavior is different for + // each, so jump to the loop that corresponds to the mode. + // + switch(masterEnv->mode) + { +/* + { case SingleLang: + while(1) + { MEAS__Capture_Pre_Master_Point + for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) + { + currSlot = animSlots[ slotIdx ]; + + masterFunction_StandaloneSlavesOnly( masterEnv, currSlot ); + } + MEAS__Capture_Post_Master_Point; + masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master + flushRegisters(); + } + + case SingleLang: + { PRLangEnv *protoLangEnv = _PRTopEnv->protoLangEnv; + while(1) + { MEAS__Capture_Pre_Master_Point + for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) + { + currSlot = animSlots[ slotIdx ]; + + masterFunction_SingleLang( protoLangEnv, currSlot ); + } + MEAS__Capture_Post_Master_Point; + masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master + flushRegisters(); + } + } + */ + case MultiLang: + { while(1) + { MEAS__Capture_Pre_Master_Point + for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) + { + currSlot = animSlots[ slotIdx ]; + + masterFunction_MultiLang( currSlot ); + } + MEAS__Capture_Post_Master_Point; + masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master + flushRegisters(); + } + } + } + } + + //===================== The versions of the Animation Master ================= // @@ -71,7 +160,7 @@ * order that application code in the slaves executes. * *To control order of animation of slaves, the request handler has a - * semantic environment that holds data structures used to hold slaves + * language environment that holds data structures used to hold slaves * and choose when they're ready to be animated. * *Once a slave is marked as ready to be animated by the request handler, @@ -93,23 +182,23 @@ *========================================================================== *In summary, the animationMaster scans the slots, finds slaves * just-finished, which hold requests, pass those to the request handler, - * along with the semantic environment, and the request handler then manages - * the structures in the semantic env, which controls the order of + * along with the language environment, and the request handler then manages + * the structures in the language env, which controls the order of * animation of slaves, and so embodies the behavior of the language * constructs. *The animationMaster then rescans the slots, offering each empty one to - * the Assigner, along with the semantic environment. The Assigner chooses - * among the ready slaves in the semantic Env, finding the one best suited + * the Assigner, along with the language environment. The Assigner chooses + * among the ready slaves in the language env, finding the one best suited * to be animated by that slot's associated core. * *========================================================================== *Implementation Details: * - *There is a separate masterVP for each core, but a single semantic + *There is a separate masterVP for each core, but a single language * environment shared by all cores. Each core also has its own scheduling * slots, which are used to communicate slaves between animationMaster and * coreController. There is only one global variable, _PRTopEnv, which - * holds the semantic env and other things shared by the different + * holds the language env and other things shared by the different * masterVPs. The request handler and Assigner are registered with * the animationMaster by the language's init function, and a pointer to * each is in the _PRTopEnv. (There are also some pthread related global @@ -128,7 +217,7 @@ *The core controllers access _PRTopEnv to get the masterVP, and when * they start, the slots are all empty, so they run their associated core's * masterVP. The first of those to get the master lock sees the seed slave - * in the shared semantic environment, so when it runs the Assigner, that + * in the shared language environment, so when it runs the Assigner, that * returns the seed slave, which the animationMaster puts into a scheduling * slot then switches to the core controller. That then switches the core * over to the seed slave, which then proceeds to execute language @@ -148,246 +237,100 @@ * executing the animationMaster code, which drives for more than one. In * practice, the best balance should be discovered by profiling. */ -void animationMaster( void *initData, SlaveVP *masterVP ) +/* +void masterFunction_StandaloneSlavesOnly( AnimSlot *slot ) { - //Used while scanning and filling animation slots - int32 slotIdx, numSlotsFilled; - AnimSlot *currSlot, **animSlots; - SlaveVP *assignedSlaveVP; //the slave chosen by the assigner - - //Local copies, for performance - MasterEnv *masterEnv; - SlaveAssigner slaveAssigner; - RequestHandler requestHandler; - void *semanticEnv; - int32 thisCoresIdx; - - //======================== Initializations ======================== - masterEnv = (MasterEnv*)_PRTopEnv; - - thisCoresIdx = masterVP->coreAnimatedBy; - animSlots = masterEnv->allAnimSlots[thisCoresIdx]; - - requestHandler = masterEnv->requestHandler; - slaveAssigner = masterEnv->slaveAssigner; - semanticEnv = masterEnv->semanticEnv; - - HOLISTIC__Insert_Master_Global_Vars; + SlaveVP *slave; + PRReqst *req; + PRLangEnv *langEnv = _PRTopEnv->langEnv; + //======================== animationMaster ======================== - while(1){ - - MEAS__Capture_Pre_Master_Point + + //Check if newly-done slave in slot, which will need request handled + if( slot->workIsDone ) + { slot->workIsDone = FALSE; + slot->needsWorkAssigned = TRUE; - //Scan the animation slots - numSlotsFilled = 0; - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) - { - currSlot = animSlots[ slotIdx ]; - //Check if newly-done slave in slot, which will need request handled - if( currSlot->workIsDone ) - { - currSlot->workIsDone = FALSE; - currSlot->needsWorkAssigned = TRUE; - - HOLISTIC__Record_AppResponder_start; - MEAS__startReqHdlr; - - currSlot->workIsDone = FALSE; - currSlot->needsWorkAssigned = TRUE; - SlaveVP *currSlave = currSlot->slaveAssignedToSlot; - - justAddedReqHdlrChg(); - //handle the request, either by PR or by the language - if( currSlave->requests->reqType != LangReq ) - { //The request is a standard PR one, not one defined by the - // language, so PR handles it, then queues slave to be assigned - handleReqInPR( currSlave ); - writePrivQ( currSlave, PRReadyQ ); //Q slave to be assigned below - } - else - { MEAS__startReqHdlr; + HOLISTIC__Record_AppResponder_start; + MEAS__startReqHdlr; + //process the request made by the slave (held inside slave struc) + slave = slot->slaveAssignedToSlot; + req = slave->request; - //Language handles request, which is held inside slave struc - (*requestHandler)( currSlave, semanticEnv ); - - MEAS__endReqHdlr; - } - } - - //process the requests made by the slave (held inside slave struc) - (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv ); - - HOLISTIC__Record_AppResponder_end; - MEAS__endReqHdlr; - } - //If slot empty, hand to Assigner to fill with a slave - if( currSlot->needsWorkAssigned ) - { //Call plugin's Assigner to give slot a new slave - HOLISTIC__Record_Assigner_start; - assignedSlaveVP = - (*slaveAssigner)( semanticEnv, currSlot ); - - //put the chosen slave into slot, and adjust flags and state - if( assignedSlaveVP != NULL ) - { currSlot->slaveAssignedToSlot = assignedSlaveVP; - assignedSlaveVP->animSlotAssignedTo = currSlot; - currSlot->needsWorkAssigned = FALSE; - numSlotsFilled += 1; - - HOLISTIC__Record_Assigner_end; + //Handle task create and end first -- they're special cases.. + switch( req->reqType ) + { case SlvCreate: PRHandle_CreateSlave( slave ); break; + case SlvDissipate: PRHandle_Dissipate( slave ); break; + case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own language env + case Hardware: //for future expansion + case IO: //for future expansion + case OSCall: //for future expansion + PR_int__throw_exception("Not implemented"); break; + case Language: //normal lang request + { + (*langEnv->requestHdlr)( req->langReq, slave, langEnv ); } } + HOLISTIC__Record_AppResponder_end; + MEAS__endReqHdlr; } + //If slot empty, hand to Assigner to fill with a slave + if( slot->needsWorkAssigned ) + { //Call plugin's Assigner to give slot a new slave + HOLISTIC__Record_Assigner_start; - MEAS__Capture_Post_Master_Point; + if( langEnv->hasWork ) + { (*langEnv->slaveAssigner)( langEnv, slot ); //calls PR fn that inserts work into slot + goto ReturnAfterAssigningWork; //quit for-loop, cause found work + } + else + goto NoWork; + } - masterSwitchToCoreCtlr( masterVP ); - flushRegisters(); - DEBUG__printf(FALSE,"came back after switch to core -- so lock released!"); - }//while(1) + NoWork: + //No work, if reach here.. + { + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + coreNum = slot->coreSlotIsOn; + returnSlv = process->idleSlv[coreNum][slotNum]; + + //things that would normally happen in resume(), but idle VPs + // never go there + returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID + Unit newU; + newU.vp = returnSlv->slaveNum; + newU.task = returnSlv->numTimesAssignedToASlot; + addToListOfArrays(Unit,newU,process->unitList); + + if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit + { Dependency newD; // to this one + newD.from_vp = returnSlv->slaveNum; + newD.from_task = returnSlv->numTimesAssignedToASlot - 1; + newD.to_vp = returnSlv->slaveNum; + newD.to_task = returnSlv->numTimesAssignedToASlot; + addToListOfArrays(Dependency, newD ,process->ctlDependenciesList); + } + #endif + HOLISTIC__Record_Assigner_end; + return; + } + + ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic.. + { + HOLISTIC__Record_Assigner_end; + return; + } } - - -/* 2) This version is for a single language that has only tasks, which - * cannot be suspended. - */ -void animationMaster( void *initData, SlaveVP *masterVP ) - { - //Used while scanning and filling animation slots - int32 slotIdx, numSlotsFilled; - AnimSlot *currSlot, **animSlots; - SlaveVP *assignedSlaveVP; //the slave chosen by the assigner - - //Local copies, for performance - MasterEnv *masterEnv; - SlaveAssigner slaveAssigner; - RequestHandler requestHandler; - PRSemEnv *semanticEnv; - int32 thisCoresIdx; - - //#ifdef MODE__MULTI_LANG - SlaveVP *slave; - PRProcess *process; - int32 langMagicNumber; - //#endif - - //======================== Initializations ======================== - masterEnv = (MasterEnv*)_PRTopEnv; - - thisCoresIdx = masterVP->coreAnimatedBy; - animSlots = masterEnv->allAnimSlots[thisCoresIdx]; - - requestHandler = masterEnv->requestHandler; - slaveAssigner = masterEnv->slaveAssigner; - semanticEnv = masterEnv->semanticEnv; - - //initialize, for non-multi-lang, non multi-proc case - // default handler gets put into master env by a registration call by lang - endTaskHandler = masterEnv->defaultTaskHandler; - - HOLISTIC__Insert_Master_Global_Vars; - - //======================== animationMaster ======================== - //Do loop gets requests handled and work assigned to slots.. - // work can either be a task or a resumed slave - //Having two cases makes this logic complex.. can be finishing either, and - // then the next available work may be either.. so really have two distinct - // loops that are inter-twined.. - while(1){ - - MEAS__Capture_Pre_Master_Point - - //Scan the animation slots - numSlotsFilled = 0; - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) - { - currSlot = animSlots[ slotIdx ]; - - //Check if newly-done slave in slot, which will need request handled - if( currSlot->workIsDone ) - { currSlot->workIsDone = FALSE; - - 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 = currSlot->slaveAssignedToSlot; - - //check if the completed work was a task.. - if( slave->metaTask->isATask ) - { - if( slave->request->type == TaskEnd ) - { //do task end handler, which is registered separately - //note, end hdlr may use semantic data from reqst.. - //#ifdef MODE__MULTI_LANG - //get end-task handler - //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); - taskEndHandler = slave->metaTask->endTaskHandler; - //#endif - (*taskEndHandler)( slave, semanticEnv ); - - goto AssignWork; - } - else //is a task, and just suspended - { //turn slot slave into free task slave & make replacement - if( slave->typeOfVP == SlotTaskSlv ) changeSlvType(); - - //goto normal slave request handling - goto SlaveReqHandling; - } - } - else //is a slave that suspended - { - SlaveReqHandling: - (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) - - HOLISTIC__Record_AppResponder_end; - MEAS__endReqHdlr; - - goto AssignWork; - } - } //if has suspended slave that needs handling - - //if slot empty, hand to Assigner to fill with a slave - if( currSlot->needsWorkAssigned ) - { //Call plugin's Assigner to give slot a new slave - HOLISTIC__Record_Assigner_start; - - AssignWork: - - assignedSlaveVP = assignWork( semanticEnv, currSlot ); - - //put the chosen slave into slot, and adjust flags and state - if( assignedSlaveVP != NULL ) - { currSlot->slaveAssignedToSlot = assignedSlaveVP; - assignedSlaveVP->animSlotAssignedTo = currSlot; - currSlot->needsWorkAssigned = FALSE; - numSlotsFilled += 1; - } - else - { - currSlot->needsWorkAssigned = TRUE; //local write - } - HOLISTIC__Record_Assigner_end; - }//if slot needs slave assigned - }//for( slotIdx.. - - MEAS__Capture_Post_Master_Point; - - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master - flushRegisters(); - }//while(1) - } +*/ /*This is the master when just multi-lang, but not multi-process mode is on. * This version has to handle both tasks and slaves, and do extra work of - * looking up the semantic env and handlers to use, for each completed bit of + * looking up the language env and handlers to use, for each completed bit of * work. - *It also has to search through the semantic envs to find one with work, + *It also has to search through the language envs to find one with work, * then ask that env's assigner to return a unit of that work. * *The language is written to startup in the same way as if it were the only @@ -429,9 +372,9 @@ * *The multi-lang thing complicates matters.. * - *For request handling, it means have to first fetch the semantic environment + *For request handling, it means have to first fetch the language environment * of the language, and then do the request handler pointed to by that - * semantic env. + * language env. *For assigning, things get more complex because of competing goals.. One * goal is for language specific stuff to be used during assignment, so * assigner can make higher quality decisions.. but with multiple languages, @@ -452,9 +395,9 @@ * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies * a task-end handler that kicks the next unit of work from HWSim internal * priority queue, over to PR readyQ) - *2) can have each language have its own semantic env, that holds its own + *2) can have each language have its own language env, that holds its own * work, which is assigned by its own assigner.. then the master searches - * through all the semantic envs to find one with work and asks it give work.. + * through all the language envs to find one with work and asks it give work.. * (this has downside of blinding assigners to each other.. but does work * for HWSim case) *3) could make PR have a different readyQ for each core, and ask the lang @@ -477,383 +420,217 @@ * the languages in a unified way.. Don't really expect this to happen, * but making it possible. */ -#ifdef MODE__MULTI_LANG -void animationMaster( void *initData, SlaveVP *masterVP ) - { - //Used while scanning and filling animation slots - int32 slotIdx, numSlotsFilled; - AnimSlot *currSlot, **animSlots; - SlaveVP *assignedSlaveVP; //the slave chosen by the assigner +/* +inline +void +masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot ) + { //Scan the animation slots + SlaveVP *slave; + PRReqst *req; + + //Check if newly-done slave in slot, which will need request handled + if( slot->workIsDone ) + { slot->workIsDone = FALSE; + slot->needsWorkAssigned = TRUE; + + 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; + + //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_SL( 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_SL( slave ); break; + } + case SlvCreate: PRHandle_CreateSlave_SL( slave ); break; + case SlvDissipate: PRHandle_Dissipate_SL( slave ); break; + case Service: PR_int__handle_PRServiceReq_SL( slave ); break; //resume into PR's own language 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 + { + (*protoLangEnv->requestHdlr)( req->langReq, slave, (void*)PR_int__give_lang_env(protoLangEnv )); + } + } + + MEAS__endReqHdlr; + HOLISTIC__Record_AppResponder_end; + } //if have request to be handled + + //If slot empty, hand to Assigner to fill with a slave + if( slot->needsWorkAssigned ) + { //Call plugin's Assigner to give slot a new slave + HOLISTIC__Record_Assigner_start; + + if( protoLangEnv->hasWork ) + { (*protoLangEnv->slaveAssigner)( protoLangEnv, slot ); //calls PR fn that inserts work into slot + goto ReturnAfterAssigningWork; //quit for-loop, cause found work + } + else + goto NoWork; + } - //Local copies, for performance - MasterEnv *masterEnv; - SlaveAssigner slaveAssigner; - RequestHandler requestHandler; - PRSemEnv *semanticEnv; - int32 thisCoresIdx; + NoWork: + //No work, if reach here.. + { + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + coreNum = slot->coreSlotIsOn; + returnSlv = process->idleSlv[coreNum][slotNum]; + + //things that would normally happen in resume(), but idle VPs + // never go there + returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID + Unit newU; + newU.vp = returnSlv->slaveNum; + newU.task = returnSlv->numTimesAssignedToASlot; + addToListOfArrays(Unit,newU,process->unitList); - //#ifdef MODE__MULTI_LANG - SlaveVP *slave; - PRProcess *process; - int32 langMagicNumber; - //#endif - - //======================== Initializations ======================== - masterEnv = (MasterEnv*)_PRTopEnv; - - thisCoresIdx = masterVP->coreAnimatedBy; - animSlots = masterEnv->allAnimSlots[thisCoresIdx]; - - requestHandler = masterEnv->requestHandler; - slaveAssigner = masterEnv->slaveAssigner; - semanticEnv = masterEnv->semanticEnv; - - //initialize, for non-multi-lang, non multi-proc case - // default handler gets put into master env by a registration call by lang - endTaskHandler = masterEnv->defaultTaskHandler; - - HOLISTIC__Insert_Master_Global_Vars; - - //======================== animationMaster ======================== - //Do loop gets requests handled and work assigned to slots.. - // work can either be a task or a resumed slave - //Having two cases makes this logic complex.. can be finishing either, and - // then the next available work may be either.. so really have two distinct - // loops that are inter-twined.. - while(1){ - - MEAS__Capture_Pre_Master_Point - - //Scan the animation slots - numSlotsFilled = 0; - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) + if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit + { Dependency newD; // to this one + newD.from_vp = returnSlv->slaveNum; + newD.from_task = returnSlv->numTimesAssignedToASlot - 1; + newD.to_vp = returnSlv->slaveNum; + newD.to_task = returnSlv->numTimesAssignedToASlot; + addToListOfArrays(Dependency, newD ,process->ctlDependenciesList); + } + #endif + HOLISTIC__Record_Assigner_end; + return; + } + + ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic.. { - currSlot = animSlots[ slotIdx ]; - - //Check if newly-done slave in slot, which will need request handled - if( currSlot->workIsDone ) - { currSlot->workIsDone = FALSE; - - 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 = currSlot->slaveAssignedToSlot; - - //check if the completed work was a task.. - if( slave->taskMetaInfo->isATask ) - { - if( slave->reqst->type == TaskEnd ) - { //do task end handler, which is registered separately - //note, end hdlr may use semantic data from reqst.. - //#ifdef MODE__MULTI_LANG - //get end-task handler - //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); - taskEndHandler = slave->taskMetaInfo->endTaskHandler; - //#endif - (*taskEndHandler)( slave, semanticEnv ); - - goto AssignWork; - } - else //is a task, and just suspended - { //turn slot slave into free task slave & make replacement - if( slave->typeOfVP == SlotTaskSlv ) changeSlvType(); - - //goto normal slave request handling - goto SlaveReqHandling; - } - } - else //is a slave that suspended - { - SlaveReqHandling: - (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) - - HOLISTIC__Record_AppResponder_end; - MEAS__endReqHdlr; - - goto AssignWork; - } - } //if has suspended slave that needs handling - - //if slot empty, hand to Assigner to fill with a slave - if( currSlot->needsWorkAssigned ) - { //Call plugin's Assigner to give slot a new slave - HOLISTIC__Record_Assigner_start; - - AssignWork: - - assignedSlaveVP = assignWork( semanticEnv, currSlot ); - - //put the chosen slave into slot, and adjust flags and state - if( assignedSlaveVP != NULL ) - { currSlot->slaveAssignedToSlot = assignedSlaveVP; - assignedSlaveVP->animSlotAssignedTo = currSlot; - currSlot->needsWorkAssigned = FALSE; - numSlotsFilled += 1; - } - else - { - currSlot->needsWorkAssigned = TRUE; //local write - } - HOLISTIC__Record_Assigner_end; - }//if slot needs slave assigned - }//for( slotIdx.. - - MEAS__Capture_Post_Master_Point; - - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master - flushRegisters(); - }//while(1) - } -#endif //MODE__MULTI_LANG - - - -//This is the master when both multi-lang and multi-process modes are turned on -//#ifdef MODE__MULTI_LANG -//#ifdef MODE__MULTI_PROCESS -void animationMaster( void *initData, SlaveVP *masterVP ) - { - int32 slotIdx; - AnimSlot *currSlot; - //Used while scanning and filling animation slots - AnimSlot **animSlots; - - //Local copies, for performance - MasterEnv *masterEnv; - int32 thisCoresIdx; - - //======================== Initializations ======================== - masterEnv = (MasterEnv*)_PRTopEnv; - - thisCoresIdx = masterVP->coreAnimatedBy; - animSlots = masterEnv->allAnimSlots[thisCoresIdx]; - - HOLISTIC__Insert_Master_Global_Vars; - - //======================== animationMaster ======================== - //Do loop gets requests handled and work assigned to slots.. - // work can either be a task or a resumed slave - //Having two cases makes this logic complex.. can be finishing either, and - // then the next available work may be either.. so really have two distinct - // loops that are inter-twined.. - while(1) - { - MEAS__Capture_Pre_Master_Point - - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) - { - currSlot = animSlots[ slotIdx ]; - - masterFunction_multiLang( currSlot ); - } - - MEAS__Capture_Post_Master_Point; - - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master - flushRegisters(); - } - } -#endif //MODE__MULTI_LANG -#endif //MODE__MULTI_PROCESS - - -//This version of the master selects one of three loops, depending upon -// whether stand-alone single language (just slaves), or standalone with -// tasks, or multi-lang (implies multi-process) -void animationMaster( void *initData, SlaveVP *masterVP ) - { - int32 slotIdx; - AnimSlot *currSlot; - //Used while scanning and filling animation slots - AnimSlot **animSlots; - - //Local copies, for performance - MasterEnv *masterEnv; - int32 thisCoresIdx; - - //======================== Initializations ======================== - masterEnv = (MasterEnv*)_PRTopEnv; - - thisCoresIdx = masterVP->coreAnimatedBy; - animSlots = masterEnv->allAnimSlots[thisCoresIdx]; - - HOLISTIC__Insert_Master_Global_Vars; - - //======================== animationMaster ======================== - //Have three different modes, and the master behavior is different for - // each, so jump to the loop that corresponds to the mode. - // - switch(mode) - { case StandaloneSlavesOnly: - while(1) - { MEAS__Capture_Pre_Master_Point - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) - { - currSlot = animSlots[ slotIdx ]; - - masterFunction_StandaloneSlavesOnly( currSlot ); - } - MEAS__Capture_Post_Master_Point; - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master - flushRegisters(); - } - case StandaloneWTasks: - while(1) - { MEAS__Capture_Pre_Master_Point - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) - { - currSlot = animSlots[ slotIdx ]; - - masterFunction_StandaloneWTasks( currSlot ); - } - MEAS__Capture_Post_Master_Point; - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master - flushRegisters(); - } - case MultiLang: - while(1) - { MEAS__Capture_Pre_Master_Point - for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) - { - currSlot = animSlots[ slotIdx ]; - - masterFunction_multiLang( currSlot ); - } - MEAS__Capture_Post_Master_Point; - masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master - flushRegisters(); - } + HOLISTIC__Record_Assigner_end; + return; } } - +*/ inline void -masterFunction_multiLang( AnimSlot *currSlot ) +masterFunction_MultiLang( AnimSlot *slot ) { //Scan the animation slots int32 magicNumber; SlaveVP *slave; - SlaveVP *assignedSlaveVP; - PRSemEnv *semanticEnv; + PRLangEnv *langEnv; PRReqst *req; RequestHandler requestHandler; + PRProcess *process; - //Check if newly-done slave in slot, which will need request handled - if( currSlot->workIsDone ) - { currSlot->workIsDone = FALSE; - currSlot->needsWorkAssigned = TRUE; - - 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 = currSlot->slaveAssignedToSlot; - req = slave->request; + //Check if newly-done slave in slot, which will need request handled + if( slot->workIsDone ) + { slot->workIsDone = FALSE; + slot->needsWorkAssigned = TRUE; - //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 ) - replaceWithNewSlotSlv( slave ); + HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot + MEAS__startReqHdlr; - //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( 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( slave ); break; - } - case SlvCreate: PRHandle_CreateSlave( slave ); break; - case SlvDissipate: PRHandle_Dissipate( slave ); break; - case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own semantic env - case Hardware: //for future expansion - case IO: //for future expansion - case OSCall: //for future expansion - PR_int__throw_exception("Not implemented"); break; - case Language: //normal sem request - magicNumber = req->langMagicNumber; - semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber ); - requestHandler = semanticEnv->requestHdlr; - (*requestHandler)( req->semReq, slave, semanticEnv ); + + //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. + 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; } + 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_Dissipate( req, slave ); break; + case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own language 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; - MEAS__endReqHdlr; - } //if have request to be handled - - if( currSlot->needsWorkAssigned ) - { - HOLISTIC__Record_Assigner_start; - - //Scan sem environs, looking for semEnv with ready work. - // call the Assigner for that sem Env, to get a slave for the slot - assignedSlaveVP = assignWork( semanticEnv, currSlot ); - - //if work found, put into slot, and adjust flags and state - if( assignedSlaveVP != NULL ) - { currSlot->slaveAssignedToSlot = assignedSlaveVP; - assignedSlaveVP->animSlotAssignedTo = currSlot; - currSlot->needsWorkAssigned = FALSE; - } - HOLISTIC__Record_Assigner_end; - }//if slot needs slave assigned + } //if have request to be handled + + if( slot->needsWorkAssigned ) + { + HOLISTIC__Record_Assigner_start; + + //Pick a process to get this slot + process = pickAProcess( slot ); + + //Scan lang environs, looking for langEnv with ready work. + // call the Assigner for that lang Env, to get a slave for the slot + assignWork( process, slot ); + + HOLISTIC__Record_Assigner_end; + }//if slot needs slave assigned } -//========================================================================== -/*When a task in a slot slave suspends, the slot slave has to be changed to - * a free task slave, then the slot slave replaced. The replacement can be - * 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. +/*When several processes exist, use some pattern for picking one to give + * the animation slot to. + *First, it has to be a process that has work available. + *For now, just do a round-robin */ -inline void -replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcess *process ) - { SlaveVP *newSlotSlv; - - When slot slave converted to a free task slave, insert the process pointer -- slot slaves are not assigned to any process; - when convert from slot slave to free task slave, check what should do about num (live slaves + live tasks) inside VSs's task stub, and properly update process's count of liveFreeTaskSlaves - - //get a new slave to be the slot slave - newSlotSlv = readPrivQ( process->freeTaskSlvRecycleQ ); - if( newSlotSlv == NULL ) - { newSlotSlv = PR_int__create_slaveVP( &idle_fn, NULL, process, 0); - //just made a new free task slave, so count it - process->numLiveFreeTaskSlvs += 1; +inline +PRProcess * +pickAProcess( AnimSlot *slot ) + { int32 idx; + PRProcess *process; + + for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++) + { + process = _PRTopEnv->processes[ idx ]; + if( process->numEnvsWithWork != 0 ) + { _PRTopEnv->currProcessIdx = idx; + return process; + } } - - //set slave values to make it the slot slave - newSlotSlv->metaTask = NULL; - newSlotSlv->typeOfVP = SlotTaskSlv; -// newSlotSlv->needsTaskAssigned = TRUE; - - //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; - - //put it into the slot slave matrix - int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; - int32 coreNum = requestingSlv->coreAnimatedBy; - process->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->metaTask->taskType = FreeTask; + for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++) + { + process = _PRTopEnv->processes[ idx ]; + if( process->numEnvsWithWork != 0 ) + { _PRTopEnv->currProcessIdx = idx; + return process; + } + } + //none found + return NULL; } - - /*This does: - * 1) searches the semantic environments for one with work ready + * 1) searches the language environments for one with work ready * if finds one, asks its assigner to return work * 2) checks what kind of work: new task, resuming task, resuming slave * if new task, gets the slot slave and assigns task to it and returns slave @@ -861,10 +638,10 @@ * 3) if no work found, then prune former task slaves waiting to be recycled. * If no work and no slaves to prune, check for shutdown conditions. * - * Semantic env keeps its own work in its own structures, and has its own + * language env keeps its own work in its own structures, and has its own * assigner. It chooses * However, include a switch that switches-in an override assigner, which - * sees all the work in all the semantic env's. This is most likely + * sees all the work in all the language env's. This is most likely * generated by static tools and included in the executable. That means it * has to be called via a registered pointer from here. The idea is that * the static tools know which languages are grouped together.. and the @@ -872,7 +649,8 @@ * all the languages in a unified way.. Don't really expect this to happen, * but am making it possible. */ -inline SlaveVP * +inline +SlaveVP * assignWork( PRProcess *process, AnimSlot *slot ) { SlaveVP *returnSlv; int32 coreNum, slotNum; @@ -881,147 +659,75 @@ coreNum = slot->coreSlotIsOn; if( process->overrideAssigner != NULL ) - { assignedMetaTask = (*process->overrideAssigner)( process, slot ); - if( assignedMetaTask != NULL ) - { - //have work, so reset Done flag (caused by work generated on other core) -// if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf -// process->coreIsDone[coreNum] = FALSE; //don't just write always - -// switch( assignedMetaTask->taskType ) -// { case GenericSlave: goto AssignSlave; -// case FreeTask: goto AssignSlave; -// case SlotTask: goto AssignNewTask; -// default: PR_int__throw_exception( "unknown task type ret by assigner" ); -// } - //If meta task has a slave attached, then goto assign slave, - // else it's a new task, so goto where assign it to a slot slave - if( assignedMetaTask->slaveAssignedTo != NULL ) - goto AssignSlave; - else - goto AssignNewTask; + { if( process->numEnvsWithWork != 0 ) + { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot + goto ReturnAfterAssigningWork; //quit for-loop, cause found work } - else //metaTask is NULL, so no work.. + else goto NoWork; } - //If here, then no override assigner, so search semantic envs for work - int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner; - semEnvs = process->semEnvs; - numEnvs = process->numSemEnvs; - for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash & array - { semEnv = semEnvs[envIdx]; - if( semEnv->hasWork ) - { assigner = semEnv->slaveAssigner; - assignedMetaTask = (*assigner)( semEnv, slot ); - - //have work, so reset Done flag (caused by work generated on other core) -// if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf -// process->coreIsDone[coreNum] = FALSE; //don't just write always - -// switch( assignedMetaTask->taskType ) -// { case GenericSlave: goto AssignSlave; -// case FreeTask: goto AssignSlave; -// case SlotTask: goto AssignNewTask; -// default: PR_int__throw_exception( "unknown task type ret by assigner" ); -// } - //If meta task has a slave attached, then goto assign slave, - // else it's a new task, so goto where assign it to a slot slave - if( assignedMetaTask->slaveAssignedTo != NULL ) - goto AssignSlave; - else - goto AssignNewTask; + //If here, then no override assigner, so search language envs for work + int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv; + langEnvsList = process->langEnvsList; + numEnvs = process->numLangEnvs; + for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array + { langEnv = langEnvsList[envIdx]; + if( langEnv->hasWork ) + { (*langEnv->slaveAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot + goto ReturnAfterAssigningWork; //quit for-loop, cause found work + //NOTE: bad search alg -- should start where left off, then wrap around } } - //If reach here, then have searched all semEnv's & none have work.. + //If reach here, then have searched all langEnv's & none have work.. - NoWork: - //No work, if reach here.. - { goto ReturnTheSlv; - } - - AssignSlave: //Have a metaTask attached to a slave, so get the slave & ret it - { returnSlv = assignedMetaTask->slaveAssignedTo; - returnSlv->coreAnimatedBy = coreNum; - - goto ReturnTheSlv; - } - - AssignNewTask: //Have a new metaTask that has no slave yet.. assign to slot slv + NoWork: //No work, if end up here.. { - //get the slot slave to assign the task to.. - slotNum = slot->slotIdx; - returnSlv = process->slotTaskSlvs[coreNum][slotNum]; - - //point slave to task's function - PR_int__reset_slaveVP_to_TopLvlFn( returnSlv, - assignedMetaTask->topLevelFn, assignedMetaTask->initData ); - returnSlv->metaTask = assignedMetaTask; - assignedMetaTask->slaveAssignedTo = returnSlv; -// returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type - - //have work, so reset Done flag, if was set -// if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf -// process->coreIsDone[coreNum] = FALSE; //don't just write always - - goto ReturnTheSlv; - } - - - ReturnTheSlv: //All paths goto here.. to provide single point for holistic.. - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - if( returnSlv == NULL ) - { returnSlv = process->idleSlv[coreNum][slotNum]; + returnSlv = process->idleSlv[coreNum][slotNum]; //things that would normally happen in resume(), but idle VPs // never go there returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID Unit newU; - newU.vp = returnSlv->slaveID; + newU.vp = returnSlv->slaveNum; newU.task = returnSlv->numTimesAssignedToASlot; addToListOfArrays(Unit,newU,process->unitList); if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit { Dependency newD; // to this one - 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 ,process->ctlDependenciesList); } + #endif + HOLISTIC__Record_Assigner_end; + return; } - else //have a slave will be assigned to the slot - { //assignSlv->numTimesAssigned++; - //get previous occupant of the slot - Unit prev_in_slot = - process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; - if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency - { Dependency newD; // is a hardware dependency - newD.from_vp = prev_in_slot.vp; - newD.from_task = prev_in_slot.task; - newD.to_vp = returnSlv->slaveID; - newD.to_task = returnSlv->numTimesAssignedToASlot; - addToListOfArrays(Dependency,newD,process->hwArcs); - } - prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous - prev_in_slot.task = returnSlv->numTimesAssignedToASlot; - process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = - prev_in_slot; + + ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic.. + { + HOLISTIC__Record_Assigner_end; + return; } - #endif - - return( returnSlv ); } -/*In creator, only PR related things happen, and things in the langlet whose + +/*This is first thing called when creating a slave.. it hands off to the + * langlet's creator, then adds updates of its own.. + * + *There's a question of things like lang data, meta tasks, and such.. + *In creator, only PR related things happen, and things for the langlet whose * creator construct was used. - *Other langlet still gets a chance to create semData -- but by registering a - * "createSemData" handler in the semEnv. When a construct of the langlet - * calls "PR__give_sem_data()", if there is no semData for that langlet, - * the PR will call the creator in the langlet's semEnv, place whatever it - * makes as the semData in that slave for that langlet, and return that semData + * + *Other langlets still get a chance to create langData -- but by registering a + * "createLangData" handler in the langEnv. When a construct of the langlet + * calls "PR__give_lang_data()", if there is no langData for that langlet, + * the PR will call the creator in the langlet's langEnv, place whatever it + * makes as the langData in that slave for that langlet, and return that langData * *So, as far as counting things, a langlet is only allowed to count creation * of slaves it creates itself.. may have to change this later.. add a way for @@ -1034,87 +740,92 @@ *PR itself needs to create the slave, then update numLiveSlaves in process, * copy processID from requestor to newly created */ -PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv ) - { SlaveVP *newSlv; - PRMetaTask metaTask; +inline +void +PRHandle_CreateSlave( PRReqst *req, SlaveVP *slave ) + { SlaveVP *newSlv; PRProcess *process; + PRLangEnv *protoLangEnv; - process = requestingSlv->processSlaveIsIn; - newSlv = PR_int__create_slaveVP(); + process = slave->processSlaveIsIn; + protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber ); + +// newSlv = PR_int__create_slave( req->topLevelFn, req->initData ); + + //create slv has diff prototype than standard reqst hdlr + newSlv = + (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv)); + newSlv->typeOfVP = GenericSlv; newSlv->processSlaveIsIn = process; + newSlv->ID = req->ID; process->numLiveGenericSlvs += 1; - metaTask = PR_int__create_slave_meta_task(); - metaTask->taskID = req->ID; -// metaTask->taskType = GenericSlave; - - (*req->handler)( req->semReq, newSlv, requestingSlv, semEnv ); } -/*The dissipate handler has to, sdate the number of slaves of the type, within +/*The dissipate handler has to, update the number of slaves of the type, within * the process, and call the langlet handler linked into the request, * and after that returns, then call the PR function that frees the slave state * (or recycles the slave). * *The PR function that frees the slave state has to also free all of the - * semData in the slave.. or else reset all of the semDatas.. by, say, marking - * them, then in PR__give_semData( magicNum ) call the langlet registered - * "resetSemData" Fn. + * langData in the slave.. or else reset all of the langDatas.. by, say, marking + * them, then in PR__give_langData( magicNum ) call the langlet registered + * "resetLangData" Fn. */ -PRHandle_Dissipate( SlaveVP *slave ) +inline +void +PRHandle_Dissipate( PRReqst *req, SlaveVP *slave ) { PRProcess *process; - void *semEnv; + PRLangEnv *protoLangEnv; process = slave->processSlaveIsIn; //do the language's dissipate handler - semEnv = PR_int__give_sem_env_for_slave( slave, slave->request->langMagicNumber ); - (*slave->request->handler)( slave->request->semReq, slave, semEnv ); + protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber ); + + if(req->handler != NULL) + (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) ); process->numLiveGenericSlvs -= 1; - PR_int__recycle_slave_multilang( requestingSlv ); + PR_int__recycle_slave__ML( slave ); //check End Of Process Condition if( process->numLiveTasks == 0 && process->numLiveGenericSlvs == 0 ) - PR_SS__shutdown_process( process ); + PR_SS__shutdown_process__ML( process ); } /*Create task is a special form, that has PR behavior in addition to plugin - * behavior. Master calls this first, and then calls the plugin's + * 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 PRMetaTask * -PRHandle_CreateTask( PRReqst *req, SlaveVP *requestingSlv ) +inline +void +PRHandle_CreateTask( PRReqst *req, SlaveVP *slave ) { PRMetaTask *metaTask; PRProcess *process; - PRLangMetaTask *langMetaTask; - PRSemEnv *semanticEnv; + PRLangEnv *protoLangEnv; + void *task; - process = requestingSlv->processSlaveIsIn; - - metaTask = PR_int__create_meta_task( req ); - metaTask->taskID = req->ID; //may be NULL + process = slave->processSlaveIsIn; + + protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( 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 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; - semanticEnv = PR_int__give_sem_env_for_slave( slave, - req->langMagicNumber ); - - //Do the langlet's create-task handler, which keeps the task - // inside the langlet's sem env, but returns the langMetaTask - // so PR can hook it to the PRMetaTask. - //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size - // of the lang's metaTask, and alloc's that plus the prolog and returns - // ptr to position just above the prolog) - langMetaTask = (*req->handler)(req->semReq, slave, semanticEnv); - metaTask->langMetaTask = langMetaTask; - langMetaTask->protoMetaTask = metaTask; - return; } @@ -1125,7 +836,7 @@ * 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 semData and meta task structs alloc'd for it). Then + * 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. @@ -1141,31 +852,31 @@ * *Note: slave may be either a slot slave or a free task slave. */ -inline void -PRHandle_EndTask( SlaveVP *requestingSlv ) - { void *semEnv; - PRReqst *req; - PRLangMetaTask *langMetaTask; +inline +void +PRHandle_EndTask( PRReqst *req, SlaveVP *requestingSlv ) + { void *langEnv; PRProcess *process; + void *langMetaTask; - req = requestingSlv->request; - semEnv = PR_int__give_sem_env_of_req( req, requestingSlv ); //magic num in req - langMetaTask = requestingSlv->metaTask->langMetaTask; + langEnv = PR_int__give_lang_env_of_req__ML( req, requestingSlv ); //magic num in req + langMetaTask = PR_int__give_lang_meta_task_from_slave__ML( requestingSlv, req->langMagicNumber); //Do the langlet's request handler - //Want to keep PR structs hidden from plugin, so extract semReq.. - (*req->handler)( langMetaTask, req->semReq, semEnv ); + //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_multilang( requestingSlv ); + PR_int__recycle_slave__ML( requestingSlv ); process->numLiveTasks -= 1; //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 ); + { //Tell the core controller to do wakeup of any waiting OS thread + PR_SS__shutdown_process__ML( process ); + } } diff -r 608833ae2c5d -r e5bd470b562b CoreController.c --- a/CoreController.c Sun Nov 04 18:39:28 2012 -0800 +++ b/CoreController.c Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2010 OpenSourceStewardshipFoundation + * Copyright 2010 OpenSourceResearchInstitute * * Licensed under BSD */ @@ -113,12 +113,12 @@ //make sure the controllers all start at same time, by making them wait pthread_mutex_lock( &suspendLock ); - while( !(_PRTopEnv->setupComplete) ) + while( !(_PRTopEnv->firstProcessReady) ) { pthread_cond_wait( &suspendCond, &suspendLock ); } pthread_mutex_unlock( &suspendLock ); - HOLISTIC__CoreCtrl_Setup; + HOLISTIC__CoreCtrl_Setup; DEBUG__printf1(TRUE, "started coreCtrlr", thisCoresIdx ); @@ -219,7 +219,7 @@ terminateCoreCtlr(SlaveVP *currSlv) { //first, free shutdown Slv that jumped here, then end the pthread - PR_int__dissipate_slaveVP( currSlv ); + PR_int__dissipate_slaveVP__SL( currSlv ); pthread_exit( NULL ); } diff -r 608833ae2c5d -r e5bd470b562b Defines/MEAS__macros_to_be_moved_to_langs.h --- a/Defines/MEAS__macros_to_be_moved_to_langs.h Sun Nov 04 18:39:28 2012 -0800 +++ b/Defines/MEAS__macros_to_be_moved_to_langs.h Mon Jan 14 15:31:23 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 diff -r 608833ae2c5d -r e5bd470b562b Defines/PR_defs.h --- a/Defines/PR_defs.h Sun Nov 04 18:39:28 2012 -0800 +++ b/Defines/PR_defs.h Mon Jan 14 15:31:23 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 diff -r 608833ae2c5d -r e5bd470b562b Defines/PR_defs__HW_constants.h --- a/Defines/PR_defs__HW_constants.h Sun Nov 04 18:39:28 2012 -0800 +++ b/Defines/PR_defs__HW_constants.h Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2012 OpenSourceStewardshipFoundation + * Copyright 2012 OpenSourceResearchInstitute * Licensed under BSD * * Author: seanhalle@yahoo.com @@ -20,9 +20,9 @@ // when work-stealing, can make bigger, at risk of losing cache affinity #define NUM_ANIM_SLOTS 1 - //number of PRSemEnv structs created inside a process -- can't start more + //number of PRLangEnv structs created inside a process -- can't start more // than this many langlets inside a single process -#define NUM_SEM_ENVS_IN_PROCESS 64 +#define NUM_IN_COLLECTION 64 //These are for backoff inside core-loop, which reduces lock contention #define NUM_REPS_W_NO_WORK_BEFORE_YIELD 10 diff -r 608833ae2c5d -r e5bd470b562b HW_Dependent_Primitives/PR__HW_measurement.h --- a/HW_Dependent_Primitives/PR__HW_measurement.h Sun Nov 04 18:39:28 2012 -0800 +++ b/HW_Dependent_Primitives/PR__HW_measurement.h Mon Jan 14 15:31:23 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 diff -r 608833ae2c5d -r e5bd470b562b HW_Dependent_Primitives/PR__MetaInfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HW_Dependent_Primitives/PR__MetaInfo.c Mon Jan 14 15:31:23 2013 -0800 @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../PR.h" + +void PR_SS__set_meta_info() + { + garbage__delete; + + _PRTopEnv->metaInfo = PR_int__malloc( sizeof(PRSysMetaInfo) ); + //Meta info gets set by calls from the language during its init, + // and info registered by calls from inside the application + _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->inputSet); + + } \ No newline at end of file diff -r 608833ae2c5d -r e5bd470b562b HW_Dependent_Primitives/PR__primitives.h --- a/HW_Dependent_Primitives/PR__primitives.h Sun Nov 04 18:39:28 2012 -0800 +++ b/HW_Dependent_Primitives/PR__primitives.h Mon Jan 14 15:31:23 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 diff -r 608833ae2c5d -r e5bd470b562b HW_Dependent_Primitives/PR__primitives_asm.s --- a/HW_Dependent_Primitives/PR__primitives_asm.s Sun Nov 04 18:39:28 2012 -0800 +++ b/HW_Dependent_Primitives/PR__primitives_asm.s Mon Jan 14 15:31:23 2013 -0800 @@ -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 + call PR_int__dissipate_slaveVP__SL movq %rbp , %rsp #goto the coreCtlrs stack pop %rbp #restore the old framepointer ret #return from core controller diff -r 608833ae2c5d -r e5bd470b562b PR.h --- a/PR.h Sun Nov 04 18:39:28 2012 -0800 +++ b/PR.h Mon Jan 14 15:31:23 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 @@ -30,25 +30,7 @@ //================================ Typedefs ================================= // -typedef unsigned long long TSCount; - -typedef struct _AnimSlot AnimSlot; -typedef struct _PRReqst PRReqst; -typedef struct _SlaveVP SlaveVP; -typedef struct _MasterVP MasterVP; -typedef struct _IntervalProbe IntervalProbe; -typedef struct _PRMetaTask PRMetaTask; - - -typedef SlaveVP *(*SlaveAssigner) ( void *, AnimSlot*); //semEnv, slot for HW info -typedef void (*RequestHandler) ( SlaveVP *, void * ); //prWReqst, semEnv -typedef void (*IndivReqHandler)( SlaveVP *, void * ); //prWReqst, semEnv -typedef void (*TopLevelFnPtr) ( void *, SlaveVP * ); //initData, animSlv -typedef void TopLevelFn ( void *, SlaveVP * ); //initData, animSlv -typedef void (*ResumeSlvFnPtr) ( SlaveVP *, void * ); - //=========== MEASUREMENT STUFF ========== - MEAS__Insert_Counter_Handler - //======================================== +#include "PR__structs.h" //============================ HW Dependent Fns ================================ @@ -56,338 +38,9 @@ #include "HW_Dependent_Primitives/PR__primitives.h" -//============= Request Related =========== -// - -enum PRReqstType //avoid starting enums at 0, for debug reasons - { - TaskCreate = 1, - TaskEnd, - SlvCreate, - SlvDissipate, - Language, - Service, //To invoke a PR provided equivalent of a language request (ex: probe) - Hardware, - IO, - OSCall - }; - -struct _PRReqst - { - enum PRReqstType reqType;//used for special forms that have PR behavior - void *semReq; - PRProcess *processReqIsIn; - int32 langMagicNumber; - TopLevelFn topLevelFn; - void *initData; - int32 *ID; - - //The request handling structure is a bit messy.. for special forms, - // such as create and dissipate, the language inserts pointer to handler - // fn directly into the request.. might change to this for all requests - IndivReqHandler handler; //pointer to handler fn for create, dissip, etc - - PRReqst *nextReqst; - }; -//PRReqst - -enum PRServReqType //These are equivalent to semantic 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, - openFile, - otherIO - }; - -typedef struct - { enum PRServReqType reqType; - SlaveVP *requestingSlv; - char *nameStr; //for create probe - char *msgStr; //for exception - void *exceptionData; - } -PRServReq; - - -//==================== Core data structures =================== - -typedef struct - { - //for future expansion - } -SlotPerfInfo; - -struct _AnimSlot - { - int workIsDone; - int needsWorkAssigned; - SlaveVP *slaveAssignedToSlot; - - int slotIdx; //needed by Holistic Model's data gathering - int coreSlotIsOn; - SlotPerfInfo *perfInfo; //used by assigner to pick best slave for core - }; -//AnimSlot - -enum VPtype - { SlotTaskSlv = 1,//Slave tied to an anim slot, only animates tasks - FreeTaskSlv, //When a suspended task ends, the slave becomes this - GenericSlv, //the VP is explicitly seen in the app code, or task suspends - Master, - Shutdown, - Idle - }; - -/*This structure embodies the state of a slaveVP. It is reused for masterVP - * and shutdownVPs. - */ -struct _SlaveVP - { //The offsets of these fields are hard-coded into assembly - void *stackPtr; //save the core's stack ptr when suspend - void *framePtr; //save core's frame ptr when suspend - void *resumeInstrPtr; //save core's program-counter when suspend - void *coreCtlrFramePtr; //restore before jmp back to core controller - void *coreCtlrStackPtr; //restore before jmp back to core controller - - //============ below this, no fields are used in asm ============= - - void *startOfStack; //used to free, and to point slave to Fn - PRProcess *processSlaveIsIn; - PRMetaTask *metaTask; - enum VPtype typeOfVP; //Slave vs Master vs Shutdown.. - int slaveID; //each slave given a globally unique ID - int coreAnimatedBy; - int numTimesAssignedToASlot; //Each assign is for one work-unit, so is an ID - //note, a scheduling decision is uniquely identified by the triple: - // -- used in record & replay - - //for comm -- between master and coreCtlr & btwn wrapper lib and plugin - AnimSlot *animSlotAssignedTo; - PRReqst *request; //wrapper lib puts in requests, plugin takes out - void *dataRetFromReq;//Return vals from plugin to Wrapper Lib - - //For language specific data that needs to be in the slave - void *semanticData; //Lang saves lang-specific things in slave here - - //Task related stuff -// bool needsTaskAssigned; - - //=========== MEASUREMENT STUFF ========== - MEAS__Insert_Meas_Fields_into_Slave; - float64 createPtInSecs; //time VP created, in seconds - //======================================== - }; -//SlaveVP - - -/* The one and only global variable, holds many odds and ends - */ -typedef struct - { //The offsets of these fields are hard-coded into assembly - void *coreCtlrReturnPt; //offset to this field used in asm - int8 falseSharePad1[256 - sizeof(void*)]; - int32 masterLock; //offset to this field used in asm - int8 falseSharePad2[256 - sizeof(int32)]; - //============ below this, no fields are used in asm ============= - - //Basic PR infrastructure - SlaveVP **masterVPs; - AnimSlot ***allAnimSlots; - - PRProcess **processes; - -//move to processEnv //Slave creation -- global count of slaves existing, across langs and processes - int32 numSlavesCreated; //used to give unique ID to processor - int32 numTasksCreated; //to give unique ID to a task - - //Initialization related - int32 setupComplete; //use while starting up coreCtlr - - //Memory management related - MallocArrays *freeLists; - int32 amtOfOutstandingMem;//total currently allocated - - //Random number seeds -- random nums used in various places - uint32_t seed1; - uint32_t seed2; - - These_Prob_belong_in_PRPRocess; -// SlaveVP *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; -// int32 numLiveFreeTaskSlvs; -// int32 numLiveThreadSlvs; -// bool32 *coreIsDone; -// int32 numCoresDone; - -// SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS]; -// int shutdownInitiated; - - //=========== MEASUREMENT STUFF ============= - IntervalProbe **intervalProbes; - PrivDynArrayInfo *dynIntervalProbesInfo; - HashTable *probeNameHashTbl; - int32 masterCreateProbeID; - float64 createPtInSecs; //real-clock time PR initialized - Histogram **measHists; - PrivDynArrayInfo *measHistsInfo; - MEAS__Insert_Susp_Meas_Fields_into_MasterEnv; - MEAS__Insert_Master_Meas_Fields_into_MasterEnv; - MEAS__Insert_Master_Lock_Meas_Fields_into_MasterEnv; - MEAS__Insert_Malloc_Meas_Fields_into_MasterEnv; - MEAS__Insert_Plugin_Meas_Fields_into_MasterEnv; - MEAS__Insert_System_Meas_Fields_into_MasterEnv; - MEAS__Insert_Counter_Meas_Fields_into_MasterEnv; - //========================================== - } -MasterEnv; - -//===================== -typedef struct - { int32 langMagicNumber; //indexes into hash array of semEnvs in PRProcess - PRSemEnv *chainedSemEnv; //chains to semEnvs with same hash - void *langSemEnv; - - SlaveAssigner slaveAssigner; - RequestHandler requestHdlr; - - RequestHandler createTaskHdlr; - RequestHandler endTaskHdlr; - RequestHandler createSlaveHdlr; - RequestHandler dissipateSlaveHdlr; - RequestHandler semDataCreator; - RequestHandler semDataInitializer; - - - //Track slaves created, separately for each langlet? (in each process) -// int32 numSlavesCreated; //gives ordering to processor creation -// int32 numSlavesAlive; //used to detect fail-safe shutdown - - //when multi-lang, master polls sem env's to find one with work in it.. - // in single-lang case, flag ignored, master always asks lang for work - int32 hasWork; - } -PRSemEnv; - -//The semantic env of every langlet must start with these two fields, so that -// PR can cast the void * to this struct, in order to access these two fields -typedef struct - { int32 langMagicNumber; - PRSemEnv *protoSemEnv; - } -PRLangSemEnv; - -//can cast any langlet's sem env to one of these, so PR can access values -typedef struct - { int32 langMagicNumber; - PRSemEnv *protoSemEnv; - } -PRServSemEnv; - -enum PRTaskType - { GenericSlave = 1, - SlotTask, - FreeTask - }; - -struct _PRMetaTask - { - PRTaskType taskType; -// RequestHandler reqHandler; //Lang-specific hdlr for create, end, etc - int32 *taskID; //is standard PR ID - SlaveVP *slaveAssignedTo; //no valid until task animated - TopLevelFn topLevelFn; //This is the Fn executes as the task - void *initData; //The data taken by the function - void *langMetaTask; - - //NOTE: info needed for "wait" functionality is inside lang's metaTask - }; -//PRMetaTask - -/*The language's meta task is cast to this struct, inside PR, then the - * back pointer to protoMetaTask is set. Keeps existence of PRMetaTask hidden - * from plugin -- so can change later. - */ -typedef struct - { int32 langMagicNumber; - PRMetaTask *protoMetaTask; - } -PRLangMetaTask; - -typedef struct - { - void (*freeFn)(void *); - } -PRSemDataTemplate; - -typedef struct - { - void (*recycler)(void *); - void *langSemData; - } -PRSemData; - -typedef struct - { PRSemDataTemplate **semDatas; - PRSemDataTemplate **semDatasIter; - int32 numSemDatas; - } -PRSemDataHolder; -//===================== Top Process level Data Strucs ====================== - -/*This structure holds all the information PR needs to manage a program. PR - * stores information about what percent of CPU time the program is getting, - * - */ -typedef struct - { - PRSemEnv semEnvs[NUM_SEM_ENVS_IN_PROCESS]; //used as a hash table - PRSemEnv semEnvList[NUM_SEM_ENVS_IN_PROCESS]; //lines up the semEnvs, so can iterate through - int32 numSemEnvs; //must be less than num sem envs.. used to iterate through - - int32 numLiveGenericSlvs; - int32 numLiveFreeTaskSlvs; - int32 numLiveTasks; -// bool32 coreIsDone[NUM_CORES][CACHE_LINE_SZ]; //Fixes false sharing - - PrivQueueStruc *freeTaskSlvRecycleQ; - SlaveVP slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; - void *resultToReturn; - - SlaveVP *seedSlv; - - SlaveAssigner overrideAssigner; - - //These are used to coord with OS thread waiting for process to end - bool32 executionIsComplete; - pthread_mutex_t doneLock; - pthread_cond_t doneCond; - } -PRProcess; - - -//========================= Extra Stuff Data Strucs ======================= -typedef struct - { - - } -PRExcp; //exception - -//======================= OS Thread related =============================== - -void * coreController( void *paramsIn ); //standard PThreads fn prototype -void * coreCtlr_Seq( void *paramsIn ); //standard PThreads fn prototype -void animationMaster( void *initData, SlaveVP *masterVP ); - - -typedef struct - { - void *endThdPt; - unsigned int coreNum; - } -ThdParams; - //============================= Global Vars ================================ -volatile MasterEnv *_PRTopEnv __align_to_cacheline__; +volatile TopEnv *_PRTopEnv __align_to_cacheline__; //these are global, but only used for startup and shutdown pthread_t coreCtlrThdHandles[ NUM_CORES ]; //pthread's virt-procr state @@ -403,7 +56,7 @@ * WL Wrapper Library -- wrapper lib code should only use these * PI Plugin -- plugin code should only use these * SS Startup and Shutdown -- designates these relate to startup & shutdown - * int internal to PR -- should not be used in wrapper lib or plugin + * int32internal to PR -- should not be used in wrapper lib or plugin * PROS means "OS functions for applications to use" * * PR_int__ functions touch internal PR data structs and are only safe @@ -413,184 +66,32 @@ * * PR_WL__ functions are all safe for use outside the master lock. * - * PROS are only safe for applications to use -- they're like a second + * PR_OS are only safe for applications to use -- they're like a second * language mixed in -- but they can't be used inside plugin code, and * aren't meant for use in wrapper libraries, because they are themselves * wrapper-library calls! */ -//========== Startup and shutdown ========== -void -PR__start(); -SlaveVP* -PR_SS__create_shutdown_slave(); +//============== include internally used fn prototypes ================ -void -PR_SS__shutdown(); +//include fn prototypes used internally in the proto-runtime implementation +#include "PR__int.h" -void -PR_SS__cleanup_at_end_of_shutdown(); +//include fn prototypes used by plugin +#include "PR__PI.h" -void -PR_SS__register_langlets_semEnv( PRSemEnv *semEnv, SlaveVP *seedVP, int32 VSs_MAGIC_NUMBER ); +//include fn prototype used by wrapper library +#include "PR__WL.h" +//================================= +#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__) -//============== =============== -inline SlaveVP * -PR_int__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam ); -#define PR_PI__create_slaveVP PR_int__create_slaveVP -#define PR_WL__create_slaveVP PR_int__create_slaveVP - -inline -SlaveVP * -PR_int__create_slot_slave(); - -inline -SlaveVP * -PR_int__create_slaveVP_helper( SlaveVP *newSlv, TopLevelFnPtr fnPtr, - void *dataParam, void *stackLocs ); - -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); - -inline -void -PR_int__point_slaveVP_to_OneParamFn( SlaveVP *slaveVP, void *fnPtr, - void *param); - -inline -void -PR_int__point_slaveVP_to_TwoParamFn( SlaveVP *slaveVP, void *fnPtr, - void *param1, void *param2); - -inline -void -PR_int__dissipate_slaveVP( SlaveVP *slaveToDissipate ); -#define PR_PI__dissipate_slaveVP PR_int__dissipate_slaveVP -//WL: dissipate a SlaveVP by sending a request - -inline -void -PR_int__dissipate_slaveVP_multilang( SlaveVP *slaveToDissipate ); - -inline -void -PR_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); -#define PR_PI__throw_exception PR_int__throw_exception -void -PR_WL__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); -#define PR_App__throw_exception PR_WL__throw_exception - -inline -void * -PR_int__give_sem_env_for_slave( SlaveVP *slave, int32 magicNumber ); -#define PR_PI__give_sem_env_for PR_int__give_sem_env_for_slave -#define PR_SS__give_sem_env_for_slave PR_int__give_sem_env_for_slave -//No WL version -- not safe! if use env in WL, be sure data rd & wr is stable -inline -PRSemEnv * -PR_int__give_proto_sem_env_for_slave( SlaveVP *slave, int32 magicNumber ); -#define PR_PI__give_proto_sem_env_for PR_int__give_proto_sem_env_for_slave -#define PR_SS__give_proto_sem_env_for_slave PR_int__give_proto_sem_env_for_slave -//No WL version -- not safe! if use env in WL, be sure data rd & wr is stable -inline -void * -PR_int__give_sem_env_from_process( PRProcess *process, int32 magicNumer ); -#define PR_PI__give_sem_env_from_process PR_int__give_sem_env_from_process -#define PR_SS__give_sem_env_from_process PR_int__give_sem_env_from_process -//#define PR_WL__give_sem_env_from_process PR_int__give_sem_env_from_process -//No WL version -- not safe! if use env in WL, be sure data rd & wr is stable - -inline -void * -PR_int__give_sem_data( SlaveVP *slave, int32 magicNumer ); -#define PR_PI__give_sem_data PR_int__give_sem_data -#define PR_SS__give_sem_data PR_int__give_sem_data -#define PR_WL__give_sem_data PR_int__give_sem_data - - -#define PR_int__give_lang_meta_task( slave, magicNumber )\ - slave->metaTask->langMetaTask; -#define PR_PI__give_lang_meta_task PR_int__give_lang_meta_task -#define PR_SS__give_lang_meta_task PR_int__give_lang_meta_task -#define PR_WL__give_lang_meta_task PR_int__give_lang_meta_task - -inline -SlaveVP * -PR_PI__give_slave_assigned_to( PRLangMetaTask *langMetaTask ); - -void -idle_fn(void* data, SlaveVP *animatingSlv); - -inline void -PR_int__get_master_lock(); - -#define PR_int__release_master_lock() _PRTopEnv->masterLock = UNLOCKED - -inline uint32_t -PR_int__randomNumber(); - -//============== Request Related =============== - -void -PR_WL__suspend_slaveVP_and_send_req( SlaveVP *callingSlv ); - -inline void -PR_WL__add_sem_request_in_mallocd_PRReqst( void *semReqData, SlaveVP *callingSlv ); - -inline void -PR_WL__send_sem_request( void *semReq, SlaveVP *callingSlv, int32 magicNum ); - -void -PR_WL__send_create_slaveVP_req( void *semReqData, SlaveVP *reqstingSlv ); - -void inline -PR_WL__send_dissipate_req( SlaveVP *prToDissipate ); - -inline void -PR_WL__send_service_request( void *semReqData, 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_PI__take_sem_reqst_from( PRReqst *req ); -#define PR_PI__take_sem_reqst_from( req ) req->semReqData - -void inline -PR_int__handle_PRServiceReq( PRReqst *req, SlaveVP *requestingSlv, void *semEnv, - ResumeSlvFnPtr resumeSlvFnPtr ); - -//======================== MEASUREMENT ====================== -uint64 -PR_WL__give_num_plugin_cycles(); -uint32 -PR_WL__give_num_plugin_animations(); - - -//========================= Utilities ======================= -inline char * -PR_int__strDup( char *str ); - - -//========================= PR request handlers ======================== -void inline -handleMakeProbe( PRServReq *semReq, void *semEnv, ResumeSlvFnPtr resumeFn ); - -void inline -handleThrowException( PRServReq *semReq, void *semEnv, ResumeSlvFnPtr resumeFn ); -//======================================================================= - -//========================= Probes ======================= -#include "Services_Offered_by_PR/Measurement_and_Stats/probes.h" +//========================= Services ======================= +//#include "Services_Offered_by_PR/Measurement_and_Stats/probes.h" +//#include "Services_Offered_by_PR/Services_Language/PRServ.h" +//#include "Services_Offered_by_PR/Services_Language/libPRServ.h" //================================================ #endif /* _PR_H */ diff -r 608833ae2c5d -r e5bd470b562b PR__PI.c --- a/PR__PI.c Sun Nov 04 18:39:28 2012 -0800 +++ b/PR__PI.c Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2010 OpenSourceStewardshipFoundation + * Copyright 2010 OpenSourceResearchInstitute * * Licensed under BSD */ @@ -44,9 +44,9 @@ *Turn function into macro that just accesses the request field * inline void * -PR_PI__take_sem_reqst_from( PRReqst *req ) +PR_PI__take_lang_reqst_from( PRReqst *req ) { - return req->semReqData; + return req->langReqData; } */ diff -r 608833ae2c5d -r e5bd470b562b PR__PI.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PR__PI.h Mon Jan 14 15:31:23 2013 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _PR__PI_H +#define _PR__PI_H +#define _GNU_SOURCE + + +#include "PR_primitive_data_types.h" + +//========================= Function Prototypes =========================== +/* MEANING OF WL PI SS int PROS + * These indicate which places the function is safe to use. They stand for: + * + * WL Wrapper Library -- wrapper lib code should only use these + * PI Plugin -- plugin code should only use these + * SS Startup and Shutdown -- designates these relate to startup & shutdown + * int32internal to PR -- should not be used in wrapper lib or plugin + * PROS means "OS functions for applications to use" + * + * PR_int__ functions touch internal PR data structs and are only safe + * to be used inside the master lock. However, occasionally, they appear + * in wrapper-lib or plugin code. In those cases, very careful analysis + * has been done to be sure no concurrency issues could arise. + * + * PR_WL__ functions are all safe for use outside the master lock. + * + * PROS are only safe for applications to use -- they're like a second + * language mixed in -- but they can't be used inside plugin code, and + * aren't meant for use in wrapper libraries, because they are themselves + * wrapper-library calls! + */ + +inline +SlaveVP * +PR_PI__give_slave_lang_meta_task_assigned_to( void *langMetaTask ); + + +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 + +//================================================ +#endif /* _PR__PI_H */ + diff -r 608833ae2c5d -r e5bd470b562b PR__SS.c --- a/PR__SS.c Sun Nov 04 18:39:28 2012 -0800 +++ b/PR__SS.c Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2010 OpenSourceStewardshipFoundation + * Copyright 2010 OpenSourceResearchInstitute * * Licensed under BSD */ @@ -32,7 +32,7 @@ create_anim_slots( int32 coreSlotsAreOn ); void -create_masterEnv(); +create_topEnv(); void create_the_coreCtlr_OS_threads(); @@ -70,251 +70,307 @@ * the requestHandler and slaveAssigner plug-in functions */ -/*This allocates PR data structures, populates the master PRProc, - * and master environment, and returns the master environment to the semantic - * layer. +//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() { - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - create_masterEnv(); - printf( "\n\n Running in SEQUENTIAL mode \n\n" ); - #else - create_masterEnv(); - DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(MasterEnv,masterLock) ); - create_the_coreCtlr_OS_threads(); - #endif + 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 } -/*A process is represented by a structure that holds all the process-specific +/*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 semantic environs of any langlets started + *-] The hash-array containing the language environs of any langlets started * inside the process. - *-] Flags used to detect the end of activity in the process *-] Counter of num live slaves and num live tasks in the process * - *PR automatically generates the seedVP when it creates the process, and - * inserts the processID of the newly created process into it. */ PRProcess * -PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ) +PR__create_process__SL( TopLevelFnPtr seed_Fn, void *seedData ) { SlaveVP *seedSlv; PRProcess *process; - PRMetaTask *metaTask; - PRSemEnv *semEnvs; - int32 idx; + PRLangEnv **langEnvs, **langEnvsList; + + _PRTopEnv->mode = SingleLang; + process = malloc( sizeof(PRProcess) ); - process->numSemEnvs = 0; - semEnvs = process->semEnvs; - for( idx = 0; idx < NUM_SEM_ENVS_IN_PROCESS; idx++ ) - { semEnvs[idx].langSemEnv = NULL; - semEnvs[idx].chainedSemEnv = NULL; + _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__ML( 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 } - - //A Process starts with one slave, the seed slave - seedSlv = PR_int__create_slaveVP( seed_Fn, seedData ); - - seedSlv->processSlaveIsIn = process; - - //seed slave is a generic slave, so make a generic slave meta task for it - metaTask = PR_int__create_generic_slave_meta_task( seedData ); - seedSlv->metaTask = metaTask; - - process->numLiveGenericSlvs = 1; //count the seed - process->numLiveTasks = 0; - - PRServSemEnv * - servicesSemEnv = PR_SS__malloc( sizeof(PRServSemEnv) ); - PR_SS__register_langlets_semEnv( servicesSemEnv, seedSlv, PRSERV_MAGIC_NUMBER ); - - //resume seedVP into PR's built-in services language's semantic env - PRServ__resume_slaveVP( seedSlv, servicesSemEnv ); + 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 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__ML( TopLevelFnPtr seed_Fn, void *seedData ) + { SlaveVP *seedSlv; + PRProcess *process; + PRLangEnv **langEnvs, **langEnvsList; + + _PRTopEnv->mode = MultiLang; + + + 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__ML( 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 ); -/*This gets the process struct out of the seedVP, then gets the semEnv-holding - * struct out of that, then inserts the semantic env into that struct, using - * the magic number as the key to the sem env placement. The master will - * use the magic number from a request to retrieve the semantic env appropriate - * for the construct that made the request. + 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__register_langlets_semEnv( void *_semEnv, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *protoSemEnv; - PRProcess *process; - PRServSemEnv *semEnv = (PRServSemEnv *)_semEnv; +PR_SS__shutdown_process__ML( PRProcess *process ) + { int32 i, processIdx; + PRProcess **processes; + + //remove process from PR's list of processes.. + processes = _PRTopEnv->processes; + for( i = 0; i < _PRTopEnv->numProcesses; i++ ) + { if( processes[i] == process ) + { processIdx = i; + break; + } + } + for( i = processIdx +1; i < _PRTopEnv->numProcesses; i++ ) + { processes[i-1] = process[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 *langEnv; + for( i = 0; i < process->numLangEnvs; i++ ) + { langEnv = PR_int__give_proto_lang_env(process->langEnvsList[i]); + //The lang shutdowns should free any slaves or tasks in the langEnv + (*langEnv->shutdownHdlr)(&(langEnv[1])); + PR_int__free( langEnv ); + } + 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 ); + //BUG: process struct can be freed and re-allocated before waiter sees + // executionIsComplete - process = seedVP->processSlaveIsIn; - - protoSemEnv = PR_int__create_proto_sem_env_in_process( process, magicNum ); - protoSemEnv->langSemEnv = semEnv; - protoSemEnv->langMagicNumber = magicNum; - protoSemEnv->hasWork = FALSE; - - semEnv->protoSemEnv = protoSemEnv; + //if last process, cause resume of "PR__wait_for_all_activity_to_end" + if( _PRTopEnv->numProcesses == 1 ) + { implement_me(); //have to ensure that PRServ has no activity -- do later + pthread_mutex_lock( _PRTopEnv->activityDoneLock ); + _PRTopEnv->allActivityIsDone = TRUE; + pthread_mutex_unlock( _PRTopEnv->activityDoneLock ); + pthread_cond_broadcast( _PRTopEnv->activityDoneCond ); + } + + //lastly, free the PRProcess struct itself + PR_int__free(process); } -/*These store the pointer to handler into the semantic env -- semantic env - * found by using magic num to look it up in the process that the seedVP - * is inside of. +/*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__register_create_task_handler( RequestHandler createTaskHandler, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->createTaskHdlr = createTaskHandler; - } -void -PR_SS__register_end_task_handler( RequestHandler endTaskHandler, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->endTaskHdlr = endTaskHandler; - } -void -PR_SS__register_create_slave_handler( RequestHandler createSlvHandler, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->createSlaveHdlr = createSlvHandler; - } -void -PR_SS__register_dissipate_slave_handler( RequestHandler dissipateHandler, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->dissipateSlaveHdlr = dissipateHandler; - } -void -PR_SS__register_request_handler( RequestHandler reqHandler, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->requestHdlr = reqHandler; - } -void -PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->slaveAssigner = assigner; - } -void -PR_SS__register_sem_data_creator( SemDataCreator semDataCreator, - SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->semDataCreator = semDataCreator; - } -void -PR_SS__register_sem_data_initializer( SemDataInitializer semDataInitializer, - SlaveVP *seedVP, int32 magicNum ) - { PRSemEnv *semEnv; - - semEnv = PR_SS__give_proto_sem_env_for_slave( seedVP, magicNum ); - semEnv->semDataInitializer = semDataInitializer; +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 ); + } } - - - -/*TODO: finish implementing - *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() - { - //-------------------------- - fprintf(output, "#\n# >> Build information <<\n"); - fprintf(output, "# GCC VERSION: %d.%d.%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__); - fprintf(output, "# Build Date: %s %s\n", __DATE__, __TIME__); - - fprintf(output, "#\n# >> Hardware information <<\n"); - fprintf(output, "# Hardware Architecture: "); - #ifdef __x86_64 - fprintf(output, "x86_64"); - #endif //__x86_64 - #ifdef __i386 - fprintf(output, "x86"); - #endif //__i386 - fprintf(output, "\n"); - fprintf(output, "# Number of Cores: %d\n", NUM_CORES); - //-------------------------- - - //PR Plugins - fprintf(output, "#\n# >> PR Plugins <<\n"); - fprintf(output, "# Language : "); - fprintf(output, _LANG_NAME_); - fprintf(output, "\n"); - //Meta info gets set by calls from the language during its init, - // and info registered by calls from inside the application - fprintf(output, "# Assigner: %s\n", _PRTopEnv->metaInfo->assignerInfo); - - //-------------------------- - //Application - fprintf(output, "#\n# >> Application <<\n"); - fprintf(output, "# Name: %s\n", _PRTopEnv->metaInfo->appInfo); - fprintf(output, "# Data Set:\n%s\n",_PRTopEnv->metaInfo->inputSet); - - //-------------------------- +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_SS__shutdown_process( PRProcess *process ) - { - removes from queue of processes, and calls shutdown on each langlet started in it (which frees any langlet-alloc'd data in semEnv & semEnv itself).. then frees the process struct (which frees the proto-semEnv's in array).. then writes a done flag (in TopEnv?) and signals the condition var that any OS threads might be waiting on (the wait-for-process-to-end call); +PR__wait_for_process_to_end() + { + pthread_mutex_lock( _PRTopEnv->activityDoneLock ); + while( !(_PRTopEnv->allActivityIsDone) ) + { + pthread_cond_wait( _PRTopEnv->activityDoneCond, + _PRTopEnv->activityDoneLock ); + } + pthread_mutex_unlock( _PRTopEnv->activityDoneLock ); } -/*A pointer to the startup-function for the language is given as the last - * argument to the call. Use this to initialize a program in the language. - * This creates a data structure that encapsulates the bookkeeping info - * PR uses to track and schedule a program run. - */ -/*PRProcess * -PR__spawn_program_on_data_in_Lang( TopLevelFnPtr seed_fn, void *data ) - { PRProcess *newProcess; - newProcess = malloc( sizeof(PRProcess) ); - - newProcess->doneLock = PTHREAD_MUTEX_INITIALIZER; - newProcess->doneCond = PTHREAD_COND_INITIALIZER; - newProcess->executionIsComplete = FALSE; - newProcess->numSlavesLive = 0; - - newProcess->dataForSeed = data; - newProcess->seedFnPtr = prog_seed_fn; - - //The language's spawn-process function fills in the plugin function-ptrs in - // the PRProcess struct, gives the struct to PR, which then makes and - // queues the seed SlaveVP, which starts processors made from the code being - // animated. - - (*langInitFnPtr)( newProcess ); - - return newProcess; - } -*/ - - -/*When all SlaveVPs owned by the program-run associated to the process have - * dissipated, then return from this call. There is no language to cleanup, - * and PR does not shutdown.. but the process bookkeeping structure, - * which is used by PR to track and schedule the program, is freed. - *The PRProcess structure is kept until this call collects the results from it, - * then freed. If the process is not done yet when PR gets this - * call, then this call waits.. the challenge here is that this call comes from - * a live OS thread that's outside PR.. so, inside here, it waits on a - * condition.. then it's a PR thread that signals this to wake up.. +/*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 @@ -322,9 +378,8 @@ * 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_App__give_results_when_done_for( PRProcess *process ) +PR__give_results_from_process_when_ready( PRProcess *process ) { void *result; pthread_mutex_lock( process->doneLock ); @@ -333,109 +388,273 @@ pthread_cond_wait( process->doneCond, process->doneLock ); } + result = process->resultToReturn; pthread_mutex_unlock( process->doneLock ); - - result = process->resultToReturn; - - PR_int__cleanup_process_after_done( process ); - free( process ); //was malloc'd above, so free it here - + return result; } + + +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_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_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->slaveAssigner = assigner; + } +void +PR_SS__register_shutdown_handler( RequestHandler 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_data_initializer( LangDataInitializer langDataInitializer, + SlaveVP *seedVP, int32 magicNum ) + { PRLangEnv *langEnv; + + langEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum ); + langEnv->langDataInitializer = langDataInitializer; + } */ + + +/* + *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[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 -create_masterEnv() - { MasterEnv *masterEnv; +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() + { TopEnv *masterEnv; PRQueueStruc **readyToAnimateQs; - int coreIdx; + int32 coreIdx; SlaveVP **masterVPs; AnimSlot ***allAnimSlots; //ptr to array of ptrs + //Make the top env, which holds everything else + _PRTopEnv = malloc( sizeof(TopEnv) ); - //Make the master env, which holds everything else - _PRTopEnv = malloc( sizeof(MasterEnv) ); - - //Very first thing put into the master env is the free-list, seeded + //Very first thing put into the top env is the free-list, seeded // with a massive initial chunk of memory. //After this, all other mallocs are PR__malloc. - _PRTopEnv->freeLists = PR_ext__create_free_list(); + _PRTopEnv->freeLists = PR_ext__create_free_list(); + _PRTopEnv->amtOfOutstandingMem = 0; + + //===================== Only PR__malloc after this ===================== + // + //=================== Both single and multi lang vars ================== + // + // + _PRTopEnv->metaInfo = PR_int__malloc( sizeof(PRSysMetaInfo) ); + memset( _PRTopEnv->metaInfo, 0, sizeof(PRSysMetaInfo) ); + + masterVPs = PR_int__malloc( NUM_CORES * sizeof(SlaveVP *) ); + _PRTopEnv->masterVPs = masterVPs; - //===================== Only PR__malloc after this ==================== - masterEnv = (MasterEnv*)_PRTopEnv; - - //Make a readyToAnimateQ for each core controller - readyToAnimateQs = PR_int__malloc( NUM_CORES * sizeof(PRQueueStruc *) ); - masterVPs = PR_int__malloc( NUM_CORES * sizeof(SlaveVP *) ); + allAnimSlots = PR_int__malloc( NUM_CORES * sizeof(AnimSlot *) ); + _PRTopEnv->allAnimSlots = allAnimSlots; - //One array for each core, several in array, core's masterVP scheds all - allAnimSlots = PR_int__malloc( NUM_CORES * sizeof(AnimSlot *) ); - - _PRTopEnv->numSlavesAlive = 0; //used to detect shut-down condition - -//======================================== - - Copied__fixThis; - - semEnv->freeExtraTaskSlvQ = makePRQ(); - semEnv->numLiveExtraTaskSlvs = 0; //must be last - semEnv->numLiveThreadSlvs = 1; //must be last, counts the seed - - semEnv->shutdownInitiated = FALSE; -// semEnv->coreIsDone = PR_int__malloc( NUM_CORES * sizeof( bool32 ) ); - + //Make the master VPs + for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) + { + readyToAnimateQs[ coreIdx ] = makePRQ(); + + //Q: should give masterVP core-specific info as its init data? + masterVPs[ coreIdx ] = PR_int__create_slave( (TopLevelFnPtr)&animationMaster, (void*)_PRTopEnv ); + masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx; + masterVPs[ coreIdx ]->typeOfVP = Master; + allAnimSlots[ coreIdx ] = create_anim_slots( coreIdx ); //makes for one core + } + //For each animation slot, there is an idle slave, and an initial // slave assigned as the current-task-slave. Create them here. int32 coreNum, slotNum; SlaveVP *idleSlv, *slotTaskSlv; + for( coreNum = 0; coreNum < NUM_CORES; coreNum++ ) - { //semEnv->coreIsDone[coreNum] = FALSE; //use during shutdown + { //langEnv->coreIsDone[coreNum] = FALSE; //use during shutdown for( slotNum = 0; slotNum < NUM_ANIM_SLOTS; ++slotNum ) - { idleSlv = PR__create_slave_helper( &idle_fn, NULL, semEnv, 0); + { idleSlv = PR_int__create_slaveVP( &idle_fn, NULL ); idleSlv->coreAnimatedBy = coreNum; idleSlv->animSlotAssignedTo = _PRTopEnv->allAnimSlots[coreNum][slotNum]; _PRTopEnv->idleSlv[coreNum][slotNum] = idleSlv; + slotTaskSlv = PR_int__create_slot_slave( ); slotTaskSlv->coreAnimatedBy = coreNum; slotTaskSlv->animSlotAssignedTo = _PRTopEnv->allAnimSlots[coreNum][slotNum]; -// slotTaskSlv->needsTaskAssigned = TRUE; - slotTaskSlv->slaveType = SlotTaskSlv; + slotTaskSlv->typeOfVP = SlotTaskSlv; _PRTopEnv->slotTaskSlvs[coreNum][slotNum] = slotTaskSlv; } } - //create the recycle queue where free task slaves are put after their task ends - semEnv->freeTaskSlvRecycleQ = makePRQ(); + _PRTopEnv->slaveRecycleQ = makePRQ(); - - semEnv->numLiveFreeTaskSlvs = 0; - semEnv->numLiveGenericSlvs = 0; //none existent yet.. "create process" creates the seeds -//================================================================== - - _PRTopEnv->numSlavesCreated = 0; //used by create slave to set slave ID - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) - { - readyToAnimateQs[ coreIdx ] = makePRQ(); - - //Q: should give masterVP core-specific info as its init data? - masterVPs[ coreIdx ] = PR_int__create_slaveVP( (TopLevelFnPtr)&animationMaster, (void*)masterEnv ); - masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx; - masterVPs[ coreIdx ]->typeOfVP = Master; - allAnimSlots[ coreIdx ] = create_anim_slots( coreIdx ); //makes for one core - } - _PRTopEnv->masterVPs = masterVPs; _PRTopEnv->masterLock = UNLOCKED; _PRTopEnv->seed1 = rand()%1000; // init random number generator _PRTopEnv->seed2 = rand()%1000; // init random number generator - _PRTopEnv->allAnimSlots = allAnimSlots; - _PRTopEnv->measHistsInfo = NULL; + + _PRTopEnv->measHistsInfo = NULL; + + _PRTopEnv->numSlavesCreated = 0; //used by create slave to set slave ID + + //=================== single lang only vars ================== + // + // + _PRTopEnv->numSlavesCreated = 0; //used to give unique ID to processor + _PRTopEnv->numTasksCreated = 0; //to give unique ID to a task + _PRTopEnv->numSlavesAlive = 0; + + _PRTopEnv->shutdownInitiated = FALSE; + _PRTopEnv->coreIsDone = PR_int__malloc( NUM_CORES * sizeof( bool32 ) ); + memset( _PRTopEnv->coreIsDone, 0, NUM_CORES * sizeof( bool32 ) ); + + //=================== multi lang only vars ================== + // + // + readyToAnimateQs = PR_int__malloc( NUM_CORES * sizeof(PRQueueStruc *) ); + + _PRTopEnv->processes = PR_int__malloc( NUM_IN_COLLECTION * sizeof(PRProcess *) ); + _PRTopEnv->numProcesses = 0; + _PRTopEnv->currProcessIdx = 0; + _PRTopEnv->firstProcessReady = FALSE; //use while starting up coreCtlr + + //initialize flags for waiting for activity within PR to complete + pthread_mutex_init( _PRTopEnv->activityDoneLock, NULL ); + pthread_cond_init( _PRTopEnv->activityDoneCond, NULL ); + _PRTopEnv->allActivityIsDone = FALSE; //============================= MEASUREMENT STUFF ======================== @@ -484,6 +703,13 @@ } +/*This is called during PR startup.. It simple creates the OS threads, with the + * core controller code as the top level function. + *However, there's nothing for these threads to do until a process is created, + * so, the core controller has a cond-var and flag in the top env they all + * "wait" on. The process creation call includes a singleton that releases + * all the core controller threads when the first process is created. + */ void create_the_coreCtlr_OS_threads() { @@ -494,7 +720,7 @@ //Need the threads to be created suspended, and wait for a signal // before proceeding -- gives time after creating to initialize other // stuff before the coreCtlrs set off. - _PRTopEnv->setupComplete = 0; + _PRTopEnv->firstProcessReady = 0; //initialize the cond used to make the new threads wait and sync up //must do this before *creating* the threads.. @@ -516,94 +742,50 @@ } -/*This is what causes the PR system to initialize.. then waits for it to - * exit. +//========================== 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. * - *Wrapper lib layer calls this when it wants the system to start running.. + *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_SS__start_the_work_then_wait_until_done() - { -#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. - // - //Instead of un-suspending threads, just call the one and only - // core ctlr (sequential version), in the main thread. - coreCtlr_Seq( NULL ); - flushRegisters(); -#else - int coreIdx; - //Start the core controllers running +PR__shutdown() + { int32 coreIdx; - //tell the core controller threads that setup is complete - //get lock, to lock out any threads still starting up -- they'll see - // that setupComplete is true before entering while loop, and so never - // wait on the condition - pthread_mutex_lock( &suspendLock ); - _PRTopEnv->setupComplete = 1; - pthread_mutex_unlock( &suspendLock ); - pthread_cond_broadcast( &suspendCond ); + PR_SS__shutdown_OS_threads(); - - //wait for all to complete + //wait for the OS threads to exit for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) { pthread_join( coreCtlrThdHandles[coreIdx], NULL ); } - - //NOTE: do not clean up PR env here -- semantic layer has to have - // a chance to clean up its environment first, then do a call to free - // the Master env and rest of PR locations -#endif - } -*/ -SlaveVP* PR_SS__create_shutdown_slave() - { - SlaveVP* shutdownVP; - - shutdownVP = PR_int__create_slaveVP( &endOSThreadFn, NULL ); - shutdownVP->typeOfVP = Shutdown; - - return shutdownVP; + //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(); } -//TODO: look at architecting cleanest separation between request handler -// and animation master, for dissipate, create, shutdown, and other non-semantic -// requests. Issue is chain: one removes requests from AppSlv, one dispatches -// on type of request, and one handles each type.. but some types require -// action from both request handler and animation master -- maybe just give the -// request handler calls like: PR__handle_X_request_type - -/*This is called by the semantic layer's request handler when it decides its - * time to shut down the PR system. Calling this causes the core controller OS - * threads to exit, which unblocks the entry-point function that started up - * PR, and allows it to grab the result and return to the original single- - * threaded application. +/*Calling this causes the core controller OS threads to exit, * - *The _PRTopEnv is needed by this shut down function, so the create-seed- - * and-wait function has to free a bunch of stuff after it detects the - * threads have all died: the masterEnv, the thread-related locations, - * masterVP any AppSlvs that might still be allocated and sitting in the - * semantic environment, or have been orphaned in the _PRWorkQ. + *The _PRTopEnv is used inside this shut down function, so it wait until + * the OS thread shutdown is done before freeing it. + * + *In here,create one core-loop shut-down slave for each core controller + * and put them all directly into the animation slots. * - *NOTE: the semantic plug-in is expected to use PR__malloc to get all the - * locations it needs, and give ownership to masterVP. Then, they will be - * automatically freed. - * - *In here,create one core-loop shut-down processor for each core controller and put - * them all directly into the readyToAnimateQ. - *Note, this function can ONLY be called after the semantic environment no - * longer cares if AppSlvs get animated after the point this is called. In - * other words, this can be used as an abort, or else it should only be - * called when all AppSlvs have finished dissipate requests -- only at that - * point is it sure that all results have completed. + *Note, this function should ONLY be called after all processes have ended, + * because it doesn't pay attention to whether unfinished work exists.. */ void -PR_SS__shutdown() +PR_SS__shutdown_OS_threads() { int32 coreIdx; SlaveVP *shutDownSlv; AnimSlot **animSlots; @@ -623,6 +805,48 @@ } +SlaveVP* PR_SS__create_shutdown_slave() + { + SlaveVP* shutdownVP; + + shutdownVP = PR_int__create_slave( &endOSThreadFn, NULL ); + shutdownVP->typeOfVP = Shutdown; + + return shutdownVP; + } + + + +void +PR_SS__print_out_measurements() + { + if( _PRTopEnv->measHistsInfo != NULL ) + { forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&printHist ); + forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&saveHistToFile); + forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&freeHist ); + } + + MEAS__Print_Hists_for_Susp_Meas; + MEAS__Print_Hists_for_Master_Meas; + MEAS__Print_Hists_for_Master_Lock_Meas; + MEAS__Print_Hists_for_Malloc_Meas; + 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 + */ +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 ); + } + + /*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 @@ -646,58 +870,6 @@ #endif } - -/*This is called from the startup & shutdown - */ -void -PR_SS__cleanup_at_end_of_shutdown() - { - //Before getting rid of everything, print out any measurements made - if( _PRTopEnv->measHistsInfo != NULL ) - { forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&printHist ); - forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&saveHistToFile); - forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&freeHist ); - } - - MEAS__Print_Hists_for_Susp_Meas; - MEAS__Print_Hists_for_Master_Meas; - MEAS__Print_Hists_for_Master_Lock_Meas; - MEAS__Print_Hists_for_Malloc_Meas; - MEAS__Print_Hists_for_Plugin_Meas; - - - //All the environment data has been allocated with PR__malloc, so just - // free its internal big-chunk and all inside it disappear. -/* - readyToAnimateQs = _PRTopEnv->readyToAnimateQs; - masterVPs = _PRTopEnv->masterVPs; - allAnimSlots = _PRTopEnv->allAnimSlots; - - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) - { - freePRQ( readyToAnimateQs[ coreIdx ] ); - //master Slvs were created external to PR, so use external free - PR_int__dissipate_slaveVP( masterVPs[ coreIdx ] ); - - freeAnimSlots( allAnimSlots[ coreIdx ] ); - } - - PR_int__free( _PRTopEnv->readyToAnimateQs ); - PR_int__free( _PRTopEnv->masterVPs ); - PR_int__free( _PRTopEnv->allAnimSlots ); - - //============================= MEASUREMENT STUFF ======================== - #ifdef PROBES__TURN_ON_STATS_PROBES - freeDynArrayDeep( _PRTopEnv->dynIntervalProbesInfo, &PR_WL__free_probe); - #endif - //======================================================================== -*/ - //These are the only two that use system free - PR_ext__free_free_list( _PRTopEnv->freeLists ); - free( (void *)_PRTopEnv ); - } - - //================================ diff -r 608833ae2c5d -r e5bd470b562b PR__WL.c --- a/PR__WL.c Sun Nov 04 18:39:28 2012 -0800 +++ b/PR__WL.c Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2010 OpenSourceStewardshipFoundation + * Copyright 2010 OpenSourceResearchInstitute * * Licensed under BSD */ @@ -25,17 +25,27 @@ -inline int32 * -PR__give_task_ID( SlaveVP *animSlv, int32 magicNumber ) +inline +int32 * +PR__give_ID_from_slave( SlaveVP *animSlv, int32 magicNumber ) { - return animSlv->metaTask->taskID; + return animSlv->ID; + } + +inline +int32 * +PR__give_ID_from_task( void *_task ) + { PRMetaTask task; + task = ((PRMetaTask *)_task)[-1]; + return task->ID; } SlaveVP * -PR__give_slave_of_task_ID( int32 *taskID, SlaveVP *animSlv ) +PR__give_owner_of_ID( int32 *taskID, SlaveVP *animSlv ) { - metaTask = lookup( taskID ); - return metaTask->slaveAssignedTo; + implement_me(); + //metaTask = lookup( taskID ); + //return metaTask->slaveAssignedTo; } /*For this implementation of PR, it may not make much sense to have the @@ -52,15 +62,15 @@ * to the plugin. */ void -PR_WL__send_create_slaveVP_req( void *semReq, int32 *slvID, SlaveVP *reqstingSlv, - int32 magicNum ) +PR_WL__send_create_slaveVP_req( void *langReq, CreateHandler handler, + int32 *slvID, SlaveVP *reqstingSlv, int32 magicNum ) { PRReqst req; req.reqType = SlvCreate; req.ID = slvID; req.langMagicNumber = magicNum; - req.semReq = semReq; -// req.nextReqst = reqstingSlv->request; + req.langReq = langReq; + req.createHdlr = handler; reqstingSlv->request = &req; PR_WL__suspend_slaveVP_and_send_req( reqstingSlv ); @@ -71,7 +81,7 @@ *This adds a request to dissipate, then suspends the processor so that the * request handler will receive the request. The request handler is what * does the work of freeing memory and removing the processor from the - * semantic environment's data structures. + * language environment's data structures. *The request handler also is what figures out when to shutdown the PR * system -- which causes all the core controller threads to die, and returns from * the call that started up PR to perform the work. @@ -89,10 +99,13 @@ * pears -- making that suspend the last thing in the Slv's trace. */ void -PR_WL__send_dissipate_req( SlaveVP *slaveToDissipate ) +PR_WL__send_end_slave_req( RequestHandler handler, SlaveVP *slaveToDissipate, + int32 magicNum ) { PRReqst req; req.reqType = SlvDissipate; + req.langMagicNumber = magicNum; + req.handler = handler; // req.nextReqst = slaveToDissipate->request; slaveToDissipate->request = &req; @@ -101,16 +114,16 @@ inline void -PR_WL__send_create_task_req( TopLevelFn fn, void *initData, void *semReq, - int32 *taskID, RequestHandler handler, SlaveVP *animSlv, int32 magicNumber) +PR_WL__send_create_task_req( TopLevelFn fn, void *initData, void *langReq, + int32 *taskID, CreateHandler handler, SlaveVP *animSlv, int32 magicNumber) { PRReqst req; req.reqType = TaskCreate; req.topLevelFn = fn; req.initData = initData; req.ID = taskID; - req.semReq = semReq; - req.handler = handler; + req.langReq = langReq; + req.createHdlr = handler; req.langMagicNumber = magicNumber; animSlv->request = &req; @@ -119,12 +132,12 @@ inline void -PR_WL__send_end_task_request( void *semReq, RequestHandler handler, +PR_WL__send_end_task_request( void *langReq, RequestHandler handler, SlaveVP *animSlv, int32 magicNum ) { PRReqst req; req.reqType = TaskEnd; - req.semReq = semReq; + req.langReq = langReq; req.handler = handler; req.langMagicNumber = magicNum; animSlv->request = &req; @@ -137,20 +150,20 @@ * has to free any extra requests tacked on before a send, using this. * * This inserts the semantic-layer's request data into standard PR carrier - * request data-struct that is mallocd. The sem request doesn't need to + * request data-struct that is mallocd. The lang request doesn't need to * be malloc'd if this is called inside the same call chain before the * send of the last request is called. * *The request handler has to call PR_int__free_PRReq for any of these */ inline void -PR_WL__add_sem_request_in_mallocd_PRReqst( void *semReqData, +PR_WL__add_lang_request_in_mallocd_PRReqst( void *langReqData, SlaveVP *callingSlv ) { PRReqst *req; - +//WARNING: not update.. may be buggy req = PR_int__malloc( sizeof(PRReqst) ); req->reqType = Language; - req->semReq = semReqData; + req->langReq = langReqData; req->nextReqst = callingSlv->request; callingSlv->request = req; } @@ -170,13 +183,14 @@ *Then it does suspend, to cause request to be sent. */ inline void -PR_WL__send_sem_request( void *semReqData, SlaveVP *callingSlv, int32 magicNum ) +PR_WL__send_lang_request( void *langReqData, RequestHandler handler, + SlaveVP *callingSlv, int32 magicNum ) { PRReqst req; req.reqType = Language; req.langMagicNumber = magicNum; - req. - req.semReq = semReqData; + req.langReq = langReqData; + req.handler = handler; req.nextReqst = callingSlv->request; callingSlv->request = &req; @@ -188,12 +202,12 @@ * */ inline void -PR_WL__send_service_request( void *semReqData, SlaveVP *callingSlv ) +PR_WL__send_service_request( void *langReqData, SlaveVP *callingSlv ) { PRReqst req; - req.reqType = PRLang; - req.langMagicNumber = PRLang_MAGIC_NUMBER; - req.semReq = semReqData; + req.reqType = Service; + req.langMagicNumber = PRServ_MAGIC_NUMBER; + req.langReq = langReqData; req.nextReqst = callingSlv->request; //grab any other preceeding callingSlv->request = &req; @@ -207,15 +221,15 @@ void PR_WL__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ) { PRReqst req; - PRServReq semReq; + PRServReq langReq; - req.reqType = PRSemantic; - req.semReq = &semReq; + req.reqType = Language; + req.langReq = &langReq; req.nextReqst = reqstSlv->request; //gab any other preceeding reqstSlv->request = &req; - semReq.msgStr = msgStr; - semReq.exceptionData = excpData; + langReq.msgStr = msgStr; + langReq.exceptionData = excpData; PR_WL__suspend_slaveVP_and_send_req( reqstSlv ); } diff -r 608833ae2c5d -r e5bd470b562b PR__WL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PR__WL.h Mon Jan 14 15:31:23 2013 -0800 @@ -0,0 +1,122 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _PR__WL_H +#define _PR__WL_H +#define _GNU_SOURCE + +#include "PR_primitive_data_types.h" +#include "PR__structs.h" +//========================= Function Prototypes =========================== +/* MEANING OF WL PI SS int PROS + * These indicate which places the function is safe to use. They stand for: + * + * WL Wrapper Library -- wrapper lib code should only use these + * PI Plugin -- plugin code should only use these + * SS Startup and Shutdown -- designates these relate to startup & shutdown + * int32internal to PR -- should not be used in wrapper lib or plugin + * PROS means "OS functions for applications to use" + * + * PR_int__ functions touch internal PR data structs and are only safe + * to be used inside the master lock. However, occasionally, they appear + * in wrapper-lib or plugin code. In those cases, very careful analysis + * has been done to be sure no concurrency issues could arise. + * + * PR_WL__ functions are all safe for use outside the master lock. + * + * PROS are only safe for applications to use -- they're like a second + * language mixed in -- but they can't be used inside plugin code, and + * aren't meant for use in wrapper libraries, because they are themselves + * wrapper-library calls! + */ +//========== Startup and shutdown ========== +void +PR__start(); + +SlaveVP* +PR_SS__create_shutdown_slave(); + +void +PR_SS__shutdown(); + +void +PR_SS__cleanup_at_end_of_shutdown(); + +void +PR_SS__register_langlets_langEnv( PRLangEnv *langEnv, SlaveVP *seedVP, int32 VSs_MAGIC_NUMBER ); + +//============== include internally used fn prototypes ================ +#include "PR__int.h" + +//============== =============== + +inline +SlaveVP * +PR_PI__give_slave_lang_meta_task_assigned_to( void *langMetaTask ); + +//============== Request Related =============== + +void +PR_WL__suspend_slaveVP_and_send_req( SlaveVP *callingSlv ); + +inline void +PR_WL__add_lang_request_in_mallocd_PRReqst( void *langReqData, + SlaveVP *callingSlv ); + +inline void +PR_WL__send_lang_request( void *langReq, SlaveVP *callingSlv, int32 magicNum ); + +void +PR_WL__send_create_slaveVP_req( void *langReq, CreateHandler handler, + int32 *slvID, SlaveVP *reqstingSlv, int32 magicNum ); + +void inline +PR_WL__send_end_slave_req( SlaveVP *prToDissipate, int32 magicNum ); + +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_PI__take_lang_reqst_from( PRReqst *req ); +#define PR_PI__take_lang_reqst_from( req ) req->langReqData + +//======================== MEASUREMENT ====================== +uint64 +PR_WL__give_num_plugin_cycles(); +uint32 +PR_WL__give_num_plugin_animations(); + + +//========================= Utilities ======================= +void +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 ======================= +//#include "Services_Offered_by_PR/Measurement_and_Stats/probes.h" +//#include "Services_Offered_by_PR/Services_Language/PRServ.h" +//#include "Services_Offered_by_PR/Services_Language/libPRServ.h" + +//================================================ +#endif /* _PR_H */ + diff -r 608833ae2c5d -r e5bd470b562b PR__int.c --- a/PR__int.c Sun Nov 04 18:39:28 2012 -0800 +++ b/PR__int.c Mon Jan 14 15:31:23 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2010 OpenSourceStewardshipFoundation + * Copyright 2010 OpenSourceResearchInstitute * * Licensed under BSD */ @@ -25,48 +25,26 @@ //=========================================================================== // //=========================================================================== - -inline SlaveVP * -PR_int__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam, PRProcess *process ) +inline +SlaveVP * +PR_int__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam ) { SlaveVP *newSlv; void *stackLocs; - - PR_int__create_slaveVP_helper( fnPtr, dataParam ); - - process->numLiveGenericSlvs += 1; - -// newSlv->needsTaskAssigned = TRUE; - newSlv->metaTask = NULL; - newSlv->typeOfVP = GenericSlave; - return newSlv; - } - - -inline SlaveVP * -PR_int__create_slaveVP_helper( TopLevelFnPtr fnPtr, void *dataParam ) - { SlaveVP *newSlv; - void *stackLocs; - newSlv = PR_int__malloc( sizeof(SlaveVP) ); stackLocs = PR_int__malloc( VIRT_PROCR_STACK_SIZE ); if( stackLocs == 0 ) { perror("PR_int__malloc stack"); exit(1); } newSlv->startOfStack = stackLocs; - newSlv->slaveID = _PRTopEnv->numSlavesCreated++; + newSlv->slaveNum = _PRTopEnv->numSlavesCreated++; newSlv->request = NULL; newSlv->animSlotAssignedTo = NULL; newSlv->numTimesAssignedToASlot = 0; - #ifdef MODE__MULTI_LANG - PRSemDataHolder * - semDataHolder = PR_int__malloc( sizeof(PRSemDataHolder) ); - newSlv->semanticData = semDataHolder; - #else - newSlv->semanticData = NULL; - #endif + newSlv->langData = NULL; + newSlv->metaTask = NULL; PR_int__reset_slaveVP_to_TopLvlFn( newSlv, fnPtr, dataParam ); @@ -80,13 +58,138 @@ #endif //======================================================================== + newSlv->typeOfVP = GenericSlave; + return newSlv; } +inline SlaveVP * -PR_int__create_slot_slave() - { - fixme; +PR_int__create_slaveVP__ML( TopLevelFnPtr fnPtr, void *dataParam, PRProcess *process ) + { SlaveVP *newSlv; + + newSlv = PR_int__create_slaveVP( fnPtr, dataParam ); + + int32 * + langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); + langDatas[0] = NUM_IN_COLLECTION; //size held in prolog + newSlv->langData = &(langDatas[1]); //skip over the size + + int32 * + metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); + metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog + newSlv->metaTask = &(metaTasks[1]); + + process->numLiveGenericSlvs += 1; + } + + +/* + */ +/* +inline +SlaveVP * +PR_int__create_seed_slave__ML( TopLevelFnPtr fnPtr, void *dataParam, PRProcess *process ) + { SlaveVP *newSlv; + + newSlv = PR_int__create_slaveVP( fnPtr, dataParam ); + + int32 * + langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); + langDatas[0] = NUM_IN_COLLECTION; //size held in prolog + newSlv->langData = &(langDatas[1]); //skip over the size + + int32 * + metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); + metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog + newSlv->metaTask = &(metaTasks[1]); //make slave point to array + + newSlv->typeOfVP = SeedSlv; + process->numLiveGenericSlvs = 1; + } +*/ + + +/*Called when a new slot slave is needed.. takes from recycle pool, and + * sets the slave up to be a slot slave -- no lang data array, no meta task + * array. + */ +SlaveVP * +PR_int__get_recycled_slot_slave( ) + { SlaveVP *retSlv; + + //take slave from recycle Q + retSlv = readPrivQ( _PRTopEnv->slaveRecycleQ ); + + if( retSlv != NULL ) + { + //set slave up with slot-slave's initial values. + retSlv->typeOfVP = SlotTaskSlv; + retSlv->slaveNum = _PRTopEnv->numSlavesCreated++; + retSlv->numTimesAssignedToASlot = 0; + retSlv->request = NULL; + } + else //if none to recycle, create a new one + { retSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL ); + retSlv->typeOfVP = SlotTaskSlv; + } + + return retSlv; + } + +/*A slot slave has no array for lang data nor meta tasks -- it only ever has + * one meta task.. + */ +SlaveVP * +PR_int__create_slot_slave( ) + { SlaveVP *retSlv; + + retSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL ); + retSlv->typeOfVP = SlotTaskSlv; + + return retSlv; + } + +//========================================================================== +/*When a task in a slot slave suspends, the slot slave has to be changed to + * a free task slave, then the slot slave replaced. The replacement can be + * 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. + */ +inline void +PR_int__replace_with_new_slot_slv( SlaveVP *requestingSlv, PRProcess *process ) + { SlaveVP *newSlotSlv; + + //get a new slave to be the slot slave + newSlotSlv = PR_int__get_recycled_slot_slave( process ); + + //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; + + //put it into the slot slave matrix + int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; + int32 coreNum = requestingSlv->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; + + + int32 * + langDatas = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRLangData *) ); + langDatas[0] = NUM_IN_COLLECTION; //size held in prolog + newSlotSlv->langData = &(langDatas[1]); //skip over the size + + int32 * + metaTasks = PR_int__malloc( sizeof(int32) + NUM_IN_COLLECTION * sizeof(PRMetaTask *) ); + metaTasks[0] = NUM_IN_COLLECTION; //size held in prolog + newSlotSlv->metaTask = &(metaTasks[1]); } void idle_fn(void* data, SlaveVP *animatingSlv) @@ -97,47 +200,6 @@ } -PRMetaTask * -PR_int__create_generic_slave_meta_task( void *initData ) - { PRMetaTask *newStub; - - newStub = PR_PI__malloc( sizeof(PRMetaTask) ); - newStub->slaveAssignedTo = NULL; //set later - newStub->taskType = IS_A_GENERIC_SLV; - newStub->taskID = NULL; - - return newStub; - } - -/*This calls recycle handler registered for each langlet's sem data and meta - * task. It also recycles the slave struct. - * - *This assumes that each slave has an array of - */ -void -PR_int__recycle_slave_multilang( SlaveVP *slave ) - { int32 semDataIdx, numSemDatas; - PRSemDataHolder *semDataHolder; - PRSemData *protoSemData, **semDatas; - - semDataHolder = (PRSemDataHolder *)slave->semanticData; - semDatas = semDataHolder->semDatasIter; - - for( semDataIdx = 0; semDataIdx < numSemDatas; semDataIdx++ ) - { protoSemData = semDatas[ semDataIdx ]; - //instead of looking up the semEnv, just put ptr to recycler in protoSemData - //To get by without, must iter through hash table.. - (*protoSemData->recycler)(protoSemData->langSemData); - } - for( metaTaskIdx = 0; metaTaskIdx < numMetaTasks; metaTaskIdx++ ) - { protoMetaTask = metaTasks[ metaTaskIdx ]; - //instead of looking up the semEnv, just put ptr to recycler in protoSemData - (*protoMetaTask->recycler)(protoMetaTask->langMetaTask); - } - - writePrivQ( slave, slave->processSlaveIsIn->freeTaskSlvRecycleQ ); - } - /* This is for OS requests and PR infrastructure requests, such as to create * a probe -- a probe is inside the heart of PR-core, it's not part of any @@ -145,26 +207,27 @@ * in the application.. so it crosses abstractions.. so, need some special * pattern here for handling such requests. * Doing this just like it were a second language sharing PR-core. - * - * This is called from the language's request handler when it sees a request - * of type PRSemReq - * - * TODO: Later change this, to give probes their own separate plugin & have - * PR-core steer the request to appropriate plugin - * Do the same for OS calls -- look later at it.. */ void inline -PR_int__handle_PRServiceReq( PRReqst *req, SlaveVP *requestingSlv, void *semEnv, - ResumeSlvFnPtr resumeFn ) - { PRServReq *semReq; +PR_int__handle_PRServiceReq( SlaveVP *requestingSlv ) + { PRReqst *req; + PRServReq *langReq; + void *langEnv; + int32 magicNumber; + + + req = requestingSlv->request; + + magicNumber = req->langMagicNumber; + langEnv = PR_PI__give_lang_env_for( slave, magicNumber ); - semReq = PR_PI__take_sem_reqst_from(req); - if( semReq == NULL ) return; - switch( semReq->reqType ) //sem handlers are all in other file + 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( semReq, semEnv, resumeFn); + case make_probe: handleMakeProbe( langReq, langEnv ); break; - case throw_excp: handleThrowException( semReq, semEnv, resumeFn); + case throw_excp: handleThrowException( langReq, langEnv ); break; } } @@ -189,7 +252,7 @@ //return ownership of the Slv and anim slot to Master virt pr animatingSlv->animSlotAssignedTo->workIsDone = TRUE; - HOLISTIC__Record_HwResponderInvocation_start; + HOLISTIC__Record_HwResponderInvocation_start; MEAS__Capture_Pre_Susp_Point; //This assembly function is a PR primitive that first saves the // stack and frame pointer, plus an addr inside this assembly code. @@ -226,9 +289,9 @@ * of dis-owning it. */ void -PR_int__dissipate_slaveVP( SlaveVP *animatingSlv ) +PR_int__dissipate_slaveVP__SL( SlaveVP *animatingSlv ) { - DEBUG__printf2(dbgRqstHdlr, "PR int dissipate slaveID: %d, alive: %d",animatingSlv->slaveID, _PRTopEnv->numSlavesAlive-1); + DEBUG__printf2(dbgRqstHdlr, "PR int dissipate slaveNum: %d, alive: %d",animatingSlv->slaveNum, _PRTopEnv->numSlavesAlive-1); //dis-own all locations owned by this processor, causing to be freed // any locations that it is (was) sole owner of _PRTopEnv->numSlavesAlive -= 1; @@ -247,116 +310,466 @@ PR_int__free( animatingSlv ); } -/*In multi-lang mode, there are multiple semData in the slave.. + +/*In multi-lang mode, there are multiple langData in the slave.. * *At some point want to recycle rather than free.. * - *For now, iterate through semData, call registered free-er on each, then + *For now, iterate through langData, call registered free-er on each, then * free the basic slave */ void -PR_int__dissipate_slaveVP_multilang( SlaveVP *slave ) - { PRSemDataHolder *semDataHolder; - PRSemDataTemplate *semData; - int32 idx; +PR_int__free_slaveVP__ML( SlaveVP *slave ) + { + PR_int__apply_Fn_to_all_in_collection( &recycleLangDataAsElem, + (PRCollElem**) slave->langData ); + PR_int__apply_Fn_to_all_in_collection( &recycleMetaTaskAsElem, + (PRCollElem**) slave->metaTask ); - semDataHolder = (PRSemDataHolder *)slave->semanticData; - for(idx = 0; idx < semDataHolder->numSemDatas; idx++) - { - semData = semDataHolder->semDatas[idx]; - (*(semData->freeFn))(semData); //this Fn is lang-spec - } - + PR_int__free( &(((int32*)(slave->langData))[-1]) ); + PR_int__free( &(((int32*)(slave->metaTask))[-1]) ); PR_int__free( slave->startOfStack ); PR_int__free( slave ); } -inline -void * -PR_int__give_sem_env_of_req( PRReqst *req, SlaveVP *requestingSlv ) - { - return PR_int__give_sem_env_for_process( requestingSlv->processSlaveIsIn, - req->langMagicNumber ); +/*This calls recycle handler registered for each langlet's lang data and meta + * task. It also recycles the slave struct. + * + *This assumes that each slave has an array of + */ +void +PR_int__recycle_slave__ML( SlaveVP *slave ) + { + PR_int__apply_Fn_to_all_in_collection( &recycleLangDataAsElem, + (PRCollElem**) slave->langData ); + PR_int__apply_Fn_to_all_in_collection( &recycleMetaTaskAsElem, + (PRCollElem**) slave->metaTask ); + + writePrivQ( slave, _PRTopEnv->slaveRecycleQ ); } -/*Anticipating multi-tasking - */ -inline +void +recycleLangDataAsElem( void *elem ) + { PRLangData *langData; + + langData = (PRLangData *)elem; //recycler receives the prolog, and must call + //a PR Fn to convert prolog to lang-specific version. + + //apply the recycle fn that's stored in the lang data prolog + (*(langData->recycler))(langData); //lang registered the recycler + } + +void +recycleMetaTaskAsElem( void *elem ) + { PRMetaTask *metaTask; + + metaTask = (PRMetaTask *)elem; //recycler receives the prolog, and must call + //a PR Fn to convert prolog to lang-specific version. + + //apply the recycle fn that's stored in the lang data prolog + (*(metaTask->recycler))(metaTask); //lang registered the recycler + } + + + +//====================================== +inline void * -PR_int__give_sem_env_for_slave( SlaveVP *slave, int32 magicNum ) - { - return PR_int__give_sem_env_for_process( slave->processSlaveIsIn, magicNum ); +PR_int__give_lang_env( PRLangEnv *protoLangEnv ) + { + return (void *) &(protoLangEnv[1]); } -inline -PRSemEnv * -PR_int__give_proto_sem_env_for_slave( SlaveVP *slave, int32 magicNum ) - { - return PR_int__give_proto_sem_env_for_process( slave->processSlaveIsIn, magicNum ); +inline +PRLangEnv * +PR_int__give_proto_lang_env( void *langEnv ) + { + return (PRLangEnv *) &(((PRLangEnv *)langEnv)[-1]); } inline void * -PR_int__give_sem_env_for_process( PRProcess *process, int32 magicNum ) - { PRSemEnv *protoSemEnv; - - protoSemEnv = lookup_proto_sem_env_in_array( process->semEnvs, magicNum ); - return protoSemEnv->langSemEnv; - } -inline -PRSemEnv * -PR_int__give_proto_sem_env_for_process( PRProcess *process, int32 magicNum ) - { - return lookup_proto_sem_env_in_array( process->semEnvs, magicNum ); +PR_int__create_lang_env_in_process( int32 size, 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 ); + + //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; + retEnv->idxInProcess = idxInProcess; + process->numLangEnvs += 1; + + return &(retEnv[1]); //skip over prolog } inline -PRSemEnv * -lookup_proto_sem_env_in_array( PRSemEnv *semEnvs, int32 magicNum ) - { PRSemEnv *retEnv; - int32 idx; +void * +PR_int__free_lang_env( void *langEnv ) + { PRLangEnv *protoLangEnv = PR_int__give_proto_lang_env( langEnv ); + PRCollElem **langEnvs; + PRLangEnv **langEnvsList; + + //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 ); + int32 count, idx; + idx = protoLangEnv->idxInProcess; + count = (process->numLangEnvs - idx - 1) * sizeof(PRLangEnv *); + memmove( langEnvsList[idx], langEnvsList[idx+1], count); + + PR_int__free( protoLangEnv ); + } + +inline +void * +PR_int__give_lang_env_of_req__ML( PRReqst *req, SlaveVP *requestingSlv ) + { + return PR_int__give_lang_env_from_process( requestingSlv->processSlaveIsIn, + req->langMagicNumber ); + } + +inline +void * +PR_int__give_lang_env_for_slave__ML( SlaveVP *slave, int32 magicNum ) + { + return PR_int__give_lang_env_from_process( slave->processSlaveIsIn, magicNum ); + } +inline +PRLangEnv * +PR_int__give_proto_lang_env_for_slave__ML( SlaveVP *slave, int32 magicNum ) + { + return PR_int__give_proto_lang_env_for_process( slave->processSlaveIsIn, magicNum ); + } + +inline +void * +PR_int__give_lang_env_from_process( PRProcess *process, int32 magicNum ) + { PRLangEnv *retLangEnv; + PRCollElem **langEnvs; + + langEnvs = (PRCollElem **)process->langEnvs; + retLangEnv = PR_int__lookup_elem_in_collection( magicNum, langEnvs ); + if( retLangEnv != NULL ) + return &(retLangEnv[1]); //skip over prolog + else + return NULL; + } +inline +PRLangEnv * +PR_int__give_proto_lang_env_for_process( PRProcess *process, int32 magicNum ) + { PRLangEnv *retLangEnv; + PRCollElem **langEnvs; + + langEnvs = (PRCollElem **)process->langEnvs; + retLangEnv = PR_int__lookup_elem_in_collection( magicNum, langEnvs ); + return retLangEnv; //return prolog + } + +inline +void +PR_int__set_work_in_lang_env( void *_langEnv ) + { PRLangEnv *protoLangEnv = &(((PRLangEnv *)_langEnv)[-1]); //go to the prolog + if( protoLangEnv->hasWork != TRUE ) + { protoLangEnv->hasWork = TRUE; + protoLangEnv->processEnvIsIn->numEnvsWithWork += 1; + } + } +inline +void +PR_int__clear_work_in_lang_env( void *_langEnv ) + { PRLangEnv *prototLangEnv = &(((PRLangEnv *)_langEnv)[-1]); //back up addr to the prolog + + if( prototLangEnv->hasWork != FALSE ) + { prototLangEnv->hasWork = FALSE; + prototLangEnv->processEnvIsIn->numEnvsWithWork -= 1; + } + } + +/*This is to be called by langlet's assigner. + */ +inline +void +PR_int__put_slave_into_slot( SlaveVP *slave, AnimSlot *slot ) + { + slave->coreAnimatedBy = slot->coreSlotIsOn; + //if work found, put into slot, and adjust flags and state + slot->slaveAssignedToSlot = slave; + slave->animSlotAssignedTo = slot; + slot->needsWorkAssigned = FALSE; + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + //have a slave to be assigned to the slot + //assignSlv->numTimesAssigned++; + //get previous occupant of the slot + PRProcess *process = slave->processSlaveIsIn; + int32 coreNum = slot->coreSlotIsOn; + int32 slotNum = slot->slotIdx; + Unit prev_in_slot = + process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; + if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency + { Dependency newD; // is a hardware dependency + newD.from_vp = prev_in_slot.vp; + newD.from_task = prev_in_slot.task; + newD.to_vp = slave->slaveNum; + newD.to_task = slave->numTimesAssignedToASlot; + addToListOfArrays(Dependency,newD,process->hwArcs); + } + prev_in_slot.vp = slave->slaveNum; //make new slave the new previous + prev_in_slot.task = slave->numTimesAssignedToASlot; + process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = + prev_in_slot; + + #endif + } + + +/*This is to be called by langlet's assigner + */ +inline +void +PR_int__put_task_into_slot( PRMetaTask *task, PRProcess *process, AnimSlot *slot ) + { int32 slotNum, coreNum; + SlaveVP *slotSlv; - idx = magicNum & 63; //mask off, leaving lowest 6 bits - retEnv = &(semEnvs[idx]); //is array of structs, so take addr - while( retEnv->langMagicNumber != magicNum ) //assume magicNums unique - { retEnv = retEnv->chainedSemEnv; - if( retEnv == NULL ) goto NotFound; + //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__ML( task, slotSlv ); + PR_int__put_slave_into_slot( slotSlv, slot ); + } + +//========================== +inline +PRMetaTask * +PR_int__give_prolog_of_task( void *task ) + { + return (PRMetaTask *) &(((PRMetaTask *)task)[-1]); + } + +inline +void * +PR_int__give_lang_meta_task_of_prolog( PRMetaTask *metaTask) + { + return (void *)&(metaTask[1]); + } + + +inline +void * +PR_int__create_lang_meta_task__ML( int32 size, int32 magicNum ) + { PRMetaTask *retMetaTask; + + //make the new meta task + retMetaTask = PR_int__malloc( sizeof(PRMetaTask) + size ); + retMetaTask->chainedMetaTask = NULL; + retMetaTask->langMagicNumber = magicNum; + retMetaTask->slaveAssignedTo = NULL; + retMetaTask->taskType = SlotTask; + retMetaTask->ID = NULL; + + return &(retMetaTask[1]); //skip over prolog + } + +/*allocates space for a new lang-meta-task, and inserts it into the slave, + * under the given magic number. + */ +inline +void * +PR_int__create_lang_meta_task_in_slave__ML( int32 size, SlaveVP *slave, int32 magicNum ) + { PRMetaTask *retMetaTask; + PRCollElem **metaTasks; + + //make the new meta task + retMetaTask = PR_int__malloc( sizeof(PRMetaTask) + size ); + retMetaTask->chainedMetaTask = NULL; + retMetaTask->langMagicNumber = magicNum; + retMetaTask->slaveAssignedTo = slave; + retMetaTask->taskType = GenericSlave; + retMetaTask->ID = NULL; + + //multilang has a "collection" of meta tasks inside the slave + metaTasks = (PRCollElem **)slave->metaTask; + PR_int__insert_elem_into_collection( (PRCollElem *)retMetaTask, + metaTasks, magicNum ); + + return &(retMetaTask[1]); //skip over prolog + } + +inline +void +PR_int__insert_meta_task_into_slave__ML( PRMetaTask *task, SlaveVP *slave ) + { + task->slaveAssignedTo = slave; + PR_int__insert_elem_into_collection( (PRCollElem *)task, + (PRCollElem **)slave->metaTask, task->langMagicNumber ); + } +inline +void +PR_int__insert_lang_meta_task_into_slave__ML( void *langMetaTask, SlaveVP *slave ) + { PRMetaTask *metaTask = &(((PRMetaTask*)langMetaTask)[-1]); + metaTask->slaveAssignedTo = slave; + PR_int__insert_elem_into_collection( (PRCollElem *)metaTask, + (PRCollElem **)slave->metaTask, metaTask->langMagicNumber ); + } + +inline +void * +PR_int__give_lang_meta_task_from_slave__ML( SlaveVP *slave, int32 magicNum ) + { PRMetaTask *retMetaTask; + PRCollElem **metaTasks; + + metaTasks = (PRCollElem **)slave->metaTask; + retMetaTask = PR_int__lookup_elem_in_collection( magicNum, metaTasks ); + if( retMetaTask != NULL ) + return &(retMetaTask[1]); //skip over prolog + else + return NULL; + } + +inline +SlaveVP * +PR_PI__give_slave_lang_meta_task_assigned_to( void *langMetaTask ) + { PRMetaTask *metaTask = &(((PRMetaTask*)langMetaTask)[-1]); + return metaTask->slaveAssignedTo; + } + +//=============================================== +/*Allocates space for a new lang-lang-data, and inserts it into the slave, + * under the given magic number. Also returns it. + */ +inline +void * +PR_int__create_lang_data_in_slave__ML( int32 size, SlaveVP *slave, int32 magicNum ) + { PRLangData *retLangData; + PRCollElem **langDatas; + + //make the new lang Data + retLangData = PR_int__malloc( sizeof(PRLangData) + size ); + retLangData->chainedLangData = NULL; + retLangData->langMagicNumber = magicNum; + + //multilang has a "collection" of lang datas inside the slave + langDatas = (PRCollElem **)slave->langData; + PR_int__insert_elem_into_collection( (PRCollElem *)retLangData, langDatas, magicNum ); + + return &(retLangData[1]); //skip over prolog + } + +inline +void * +PR_int__give_lang_data_from_slave__ML( SlaveVP *slave, int32 magicNum ) + { PRLangData *retLangData; + PRCollElem **langDatas; + + langDatas = (PRCollElem **)slave->langData; + retLangData = PR_int__lookup_elem_in_collection( magicNum, langDatas ); + if( retLangData != NULL ) + return &(retLangData[1]); //skip over prolog + else + return NULL; + } + + +//=============================================== +inline +void +PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash ) + { int32 idx, numIdxsInColl; + PRCollElem *test; + + numIdxsInColl = ((int32 *)coll)[-1]; //prolog holds number of idexes in array + + //figure out where to link in + idx = hash & (numIdxsInColl - 1); //mask off, leaving lowest bits + test = coll[idx]; + elem->chained = NULL; //elem goes at end of any chain, so just being sure here + if( test == NULL ) //spot empty, so add there + { //add to the array + coll[idx] = elem; } - return retEnv; + else //collision -- look for last in chain, then add there + { while( test->chained != NULL ) + { test = test->chained; + } + //add new to the end of chain + test->chained = elem; + } + } + +inline +void * +PR_int__lookup_elem_in_collection( int32 hash, PRCollElem **coll ) + { int32 idx, numIdxsInColl; + PRCollElem *test; + + numIdxsInColl = ((int32 *)coll)[-1]; //prolog holds number of indexes in array + + idx = hash & (numIdxsInColl - 1); //mask off, leaving lowest bits + test = coll[idx]; + if( test == NULL ) goto NotFound; + while( test->hash != hash ) + { test = test->chained; + if( test == NULL ) goto NotFound; + } + return test; NotFound: return NULL; } inline -PRSemEnv * -PR_int__create_proto_sem_env_in_process( PRProcess process, int32 magicNum ) - { PRSemEnv *semEnvs; - PRSemEnv *retEnv, *newEnv; - int32 idx; - - semEnvs = process->semEnvs; - - idx = magicNum & 63; //mask upper bits off, leaving lowest 6 bits - retEnv = &(semEnvs[idx]); //is array of structs, so take addr - if( retEnv->langSemEnv == NULL ) - { //if env that's in array is empty, do nothing, drop down to return sequence +void +PR_int__remove_elem_from_collection( int32 hash, PRCollElem **coll ) + { int32 idx, numIdxsInColl; + PRCollElem *test, *prev; + + numIdxsInColl = ((int32 *)coll)[-1]; //num indexes in prolog -- power of 2 + + idx = hash & (numIdxsInColl - 1); //mask off, leaving lowest bits (power of 2) + test = coll[idx]; + if( test == NULL ) return; //not found, nothing to remove + prev = NULL; + while( test->hash != hash ) + { prev = test; + test = test->chained; + if( test == NULL ) return; //not found, nothing to remove } - else //look for last environment in chain - { while( retEnv->chainedSemEnv != NULL ) - { retEnv = retEnv->chainedSemEnv; - } - //add a new proto sem env to the end of chain - newEnv = PR_int__malloc( sizeof(PRSemEnv) ); - newEnv->chainedSemEnv = NULL; - retEnv->chainedSemEnv = newEnv; - retEnv = newEnv; + if( prev == NULL) + { coll[idx] = coll[idx]->chained; + return; } - - process->semEnvList[process->numSemEnvs] = retEnv; - process->numSemEnvs += 1; - return retEnv; + else + { prev->chained = test->chained; + return; + } } +inline +void +PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem *coll ) + { int32 idx, numIdxsInColl; + PRCollElem *test; + + numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs + for( idx = 0; idx < ; idx++ ) + { test = coll[idx]; + while( test != NULL ) + { (*Fn)((void *)test); + test = test->chained; + } + } + } + +//========================================== /*Later, improve this -- for now, just exits the application after printing * the error message. @@ -370,7 +783,8 @@ } -inline char * +inline +char * PR_int__strDup( char *str ) { char *retStr; diff -r 608833ae2c5d -r e5bd470b562b PR__int.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PR__int.h Mon Jan 14 15:31:23 2013 -0800 @@ -0,0 +1,245 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _PR_INT_H +#define _PR_INT_H +#define _GNU_SOURCE + + +/* 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 + */ + + +inline SlaveVP * +PR_int__create_slave( TopLevelFnPtr fnPtr, void *dataParam ); +#define PR_PI__create_slaveVP PR_int__create_slave +#define PR_WL__create_slaveVP PR_int__create_slave + +inline +SlaveVP * +PR_int__create_slaveVP_helper( SlaveVP *newSlv, TopLevelFnPtr fnPtr, + void *dataParam, void *stackLocs ); + +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); + +inline +void +PR_int__point_slaveVP_to_OneParamFn( SlaveVP *slaveVP, void *fnPtr, + void *param); + +inline +void +PR_int__point_slaveVP_to_TwoParamFn( SlaveVP *slaveVP, void *fnPtr, + void *param1, void *param2); + +//=========================================================================== +// +//=========================================================================== +inline +SlaveVP * +PR_int__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam ); + +inline +SlaveVP * +PR_int__create_slaveVP__ML( TopLevelFnPtr fnPtr, void *dataParam, PRProcess *process ); + +SlaveVP * +PR_int__get_recycled_slot_slave( ); + +SlaveVP * +PR_int__create_slot_slave( ); + +inline +void +PR_int__replace_with_new_slot_slv( SlaveVP *slave ); + +void +idle_fn(void* data, SlaveVP *animatingSlv); + +inline +void +PR_int__put_task_into_slot( PRMetaTask *task, PRProcess *process, AnimSlot *slot ); + +inline +void +PR_int__put_slave_into_slot( SlaveVP *slave, AnimSlot *slot ); + +void inline +PR_int__handle_PRServiceReq( 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__ML( SlaveVP *slave ); + +void +PR_int__recycle_slave__ML( SlaveVP *slave ); + +void +recycleLangDataAsElem( void *elem ); + +void +recycleMetaTaskAsElem( void *elem ); + +inline +void * +PR_int__give_lang_env( PRLangEnv *protoLangEnv ); + +inline +PRLangEnv * +PR_int__give_proto_lang_env( void *langEnv ); + +inline +void * +PR_int__create_lang_env_in_process( int32 size, PRProcess process, int32 magicNum ); + +inline +void * +PR_int__free_lang_env( void *langEnv ); + +inline +void * +PR_int__give_lang_env_of_req__ML( PRReqst *req, SlaveVP *requestingSlv ); + +inline +void * +PR_int__give_lang_env_for_slave__ML( SlaveVP *slave, int32 magicNum ); +#define PR_PI__give_lang_env_for PR_int__give_lang_env_for_slave__ML +#define PR_SS__give_lang_env_for_slave PR_int__give_lang_env_for_slave__ML +//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 +//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 ); + +inline +void +PR_int__set_work_in_lang_env( void *_langEnv ); + +inline +void +PR_int__clear_work_in_lang_env( void *_langEnv ); + +inline +PRMetaTask * +PR_int__give_prolog_of_task( void *task ); + +inline +void * +PR_int__give_lang_meta_task_of_prolog( PRMetaTask *metaTask); + +inline +void * +PR_int__create_lang_meta_task__ML( int32 size, int32 magicNum ); + +inline +void * +PR_int__create_lang_meta_task_in_slave__ML( int32 size, SlaveVP *slave, int32 magicNum ); + +inline +void +PR_int__insert_meta_task_into_slave__ML( PRMetaTask *task, SlaveVP *slave ); + +inline +void +PR_int__insert_lang_meta_task_into_slave__ML( void *langMetaTask, SlaveVP *slave ); + +inline +void * +PR_int__give_lang_meta_task_from_slave__ML( 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__ML +#define PR_SS__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave__ML +#define PR_WL__give_lang_meta_task_from_slave__ML PR_int__give_lang_meta_task_from_slave__ML + +inline +SlaveVP * +PR_PI__give_slave_lang_meta_task_assigned_to( void *langMetaTask ); + +inline +void * +PR_int__create_lang_data_in_slave__ML( int32 size, SlaveVP *slave, int32 magicNum ); + +inline +void * +PR_int__give_lang_data_from_slave__ML( SlaveVP *slave, int32 magicNumer ); +#define PR_PI__give_lang_data PR_int__give_lang_data_from_slave__ML +#define PR_SS__give_lang_data PR_int__give_lang_data_from_slave__ML +#define PR_WL__give_lang_data PR_int__give_lang_data_from_slave__ML + +inline +void +PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash ); + +inline +void * +PR_int__lookup_elem_in_collection( int32 hash, PRCollElem **coll ); + +inline +void +PR_int__remove_elem_from_collection( int32 hash, PRCollElem **coll ); + +inline +void +PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem *coll ); + +void +PR_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData ); +#define PR_PI__throw_exception PR_int__throw_exception + +inline 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 + +inline uint32_t +PR_int__randomNumber(); + +inline void +PR_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock ); + +#endif /* _PR_INT_H */ + diff -r 608833ae2c5d -r e5bd470b562b PR__structs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PR__structs.h Mon Jan 14 15:31:23 2013 -0800 @@ -0,0 +1,418 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _PR__structs_H +#define _PR__structs_H +#define _GNU_SOURCE + +#include "PR_primitive_data_types.h" + +#include +#include + + +//================================ Typedefs ================================= +// +typedef unsigned long long TSCount; + +typedef struct _AnimSlot AnimSlot; +typedef struct _PRReqst PRReqst; +typedef struct _SlaveVP SlaveVP; +typedef struct _MasterVP MasterVP; +typedef struct _IntervalProbe IntervalProbe; +typedef struct _PRLangEnv PRLangEnv; //a prolog +typedef struct _PRMetaTask PRMetaTask; //a prolog +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 void (*RequestHandler) ( void *, SlaveVP *, void * ); //req, slv, langEnv +typedef void *(*CreateHandler) ( void *, SlaveVP *, void * ); //req, slv, langEnv +typedef void (*TopLevelFnPtr) ( void *, SlaveVP * ); //initData, animSlv +typedef void TopLevelFn ( void *, SlaveVP * ); //initData, animSlv +typedef void (*ResumeSlvFnPtr) ( SlaveVP *, void * ); + //=========== MEASUREMENT STUFF ========== + MEAS__Insert_Counter_Handler + //======================================== + +//============================ HW Dependent Fns ================================ + +#include "HW_Dependent_Primitives/PR__HW_measurement.h" +#include "HW_Dependent_Primitives/PR__primitives.h" + + +typedef struct + { //These are set by the plugin during startup and the application + char *assignerInfo; + char *appInfo; + char *inputInfo; + } +PRSysMetaInfo; + +//===================== Process Data Struct ====================== + +/*This structure holds all the information PR needs to manage a program. PR + * stores information about what percent of CPU time the program is getting, + * + */ +typedef struct + { + int32 numEnvsWithWork; + void *resultToReturn; + + PRLangEnv *langEnvs[NUM_IN_COLLECTION]; //used as a hash table + PRLangEnv *langEnvsList[NUM_IN_COLLECTION]; //for fast linear scan of envs + int32 numLangEnvs; //for fast linear scan of envs + + SlaveVP *seedSlv; + + int32 numLiveGenericSlvs; + int32 numLiveTasks; + + SlaveAssigner overrideAssigner; + + + + //These are used to coord with an OS thread waiting for process to end + bool32 executionIsComplete; + pthread_mutex_t doneLock; + pthread_cond_t doneCond; + + //=========== MEASUREMENT STUFF ============= + IntervalProbe **intervalProbes; + PrivDynArrayInfo *dynIntervalProbesInfo; + HashTable *probeNameHashTbl; + int32 masterCreateProbeID; + float64 createPtInSecs; //real-clock time PR initialized + Histogram **measHists; + PrivDynArrayInfo *measHistsInfo; + MEAS__Insert_Susp_Meas_Fields_into_MasterEnv; + MEAS__Insert_Master_Meas_Fields_into_MasterEnv; + MEAS__Insert_Master_Lock_Meas_Fields_into_MasterEnv; + MEAS__Insert_Malloc_Meas_Fields_into_MasterEnv; + MEAS__Insert_Plugin_Meas_Fields_into_MasterEnv; + MEAS__Insert_System_Meas_Fields_into_MasterEnv; + MEAS__Insert_Counter_Meas_Fields_into_MasterEnv; + //========================================== + } +PRProcess; + + +//============= Request Related =========== +// + +enum PRReqstType //avoid starting enums at 0, for debug reasons + { + TaskCreate = 1, + TaskEnd, + SlvCreate, + SlvDissipate, + Language, + Service, //To invoke a PR provided equivalent of a language request (ex: probe) + Hardware, + IO, + OSCall + }; + +struct _PRReqst + { + enum PRReqstType reqType;//used for special forms that have PR behavior + void *langReq; + PRProcess *processReqIsIn; + int32 langMagicNumber; + TopLevelFnPtr topLevelFn; + void *initData; + int32 *ID; + + //The request handling structure is a bit messy.. for special forms, + // such as create and dissipate, the language inserts pointer to handler + // fn directly into the request.. might change to this for all requests + RequestHandler handler; //pointer to handler fn + CreateHandler createHdlr; //special because returns something + + PRReqst *nextReqst; + }; +//PRReqst + +enum PRServReqType //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, + openFile, + otherIO + }; + +typedef struct + { enum PRServReqType reqType; + SlaveVP *requestingSlv; + char *nameStr; //for create probe + char *msgStr; //for exception + void *exceptionData; + } +PRServReq; + + +//==================== Core data structures =================== + +typedef struct + { + //for future expansion + } +SlotPerfInfo; + +struct _AnimSlot + { + int32 workIsDone; + int32 needsWorkAssigned; + SlaveVP *slaveAssignedToSlot; + + int32 slotIdx; //needed by Holistic Model's data gathering + int32 coreSlotIsOn; + SlotPerfInfo *perfInfo; //used by assigner to pick best slave for core + }; +//AnimSlot + +enum VPtype + { SlotTaskSlv = 1,//Slave tied to an anim slot, only animates tasks + 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 + }; + +/*This structure embodies the state of a slaveVP. It is reused for masterVP + * and shutdownVPs. + */ +struct _SlaveVP + { //The offsets of these fields are hard-coded into assembly + void *stackPtr; //save the core's stack ptr when suspend + void *framePtr; //save core's frame ptr when suspend + void *resumeInstrPtr; //save core's program-counter when suspend + void *coreCtlrFramePtr; //restore before jmp back to core controller + void *coreCtlrStackPtr; //restore before jmp back to core controller + + //============ below this, no fields are used in asm ============= + + void *startOfStack; //used to free, and to point slave to Fn + PRProcess *processSlaveIsIn; + enum VPtype typeOfVP; //Slave vs Master vs Shutdown.. + int32 slaveNum; //each slave given it's seq in creation + int32 *ID; //App defines meaning of each int in array + int32 coreAnimatedBy; + int32 numTimesAssignedToASlot; //Each assign is for one work-unit, so is an ID + //note, a scheduling decision is uniquely identified by the triple: + // -- used in record & replay + + //for comm -- between master and coreCtlr & btwn wrapper lib and plugin + AnimSlot *animSlotAssignedTo; + PRReqst *request; //wrapper lib puts in requests, plugin takes out + void *dataRetFromReq;//Return vals from plugin to Wrapper Lib + + //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 *langData; //Lang saves lang-specific things in slave here + void *metaTask; + + //=========== MEASUREMENT STUFF ========== + MEAS__Insert_Meas_Fields_into_Slave; + float64 createPtInSecs; //time VP created, in seconds + //======================================== + +// int8 cacheLinePad[512 - sizeof(contents)]; //for false sharing + }; +//SlaveVP + + +enum PRMode + { SingleLang = 1, + StandaloneWTasks, + MultiLang + }; + +/* The one and only global variable, holds many odds and ends + */ +typedef struct + { //The offsets of these fields are hard-coded into assembly + void *coreCtlrReturnPt; //offset to this field used in asm + int8 falseSharePad1[256 - sizeof(void*)]; + int32 masterLock; //offset to this field used in asm + int8 falseSharePad2[256 - sizeof(int32)]; + //============ below this, no fields are used in asm ============= + + //Basic PR infrastructure + enum PRMode mode; + SlaveVP **masterVPs; + AnimSlot ***allAnimSlots; + PrivQueueStruc *slaveRecycleQ; + SlaveVP *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; + SlaveVP *idleSlv[NUM_CORES][NUM_ANIM_SLOTS]; + + //Memory management related + MallocArrays *freeLists; + int32 amtOfOutstandingMem;//total currently allocated + + //Random number seeds -- random nums used in various places + uint32_t seed1; + uint32_t seed2; + + PRSysMetaInfo *metaInfo; //info about this PR system -- vers, build, etc + + //============== This only used by multi-lang mode ============ + PRProcess **processes; + int32 numProcesses; + int32 currProcessIdx; //used to choose which process gets slot + int32 firstProcessReady; //use while starting up coreCtlr + RequestHandler free_lang_data; //lang data persists after langlet stops + //so need freer when end slaves + + //initialize flags for waiting for activity within PR to complete + bool32 allActivityIsDone; + pthread_mutex_t activityDoneLock; + pthread_cond_t activityDoneCond; + + + //============== Below this is only used by single-lang mode ============== + void *protoLangEnv; + //Slave creation -- global count of slaves existing, across langs and processes + int32 numSlavesCreated; //used to give unique ID to processor + int32 numTasksCreated; //to give unique ID to a task + int32 numSlavesAlive; + + bool32 *coreIsDone; + int32 numCoresDone; + int32 shutdownInitiated; + + + //=========== MEASUREMENT STUFF ============= + IntervalProbe **intervalProbes; + PrivDynArrayInfo *dynIntervalProbesInfo; + HashTable *probeNameHashTbl; + int32 masterCreateProbeID; + float64 createPtInSecs; //real-clock time PR initialized + Histogram **measHists; + PrivDynArrayInfo *measHistsInfo; + MEAS__Insert_Susp_Meas_Fields_into_MasterEnv; + MEAS__Insert_Master_Meas_Fields_into_MasterEnv; + MEAS__Insert_Master_Lock_Meas_Fields_into_MasterEnv; + MEAS__Insert_Malloc_Meas_Fields_into_MasterEnv; + MEAS__Insert_Plugin_Meas_Fields_into_MasterEnv; + MEAS__Insert_System_Meas_Fields_into_MasterEnv; + MEAS__Insert_Counter_Meas_Fields_into_MasterEnv; + //========================================== + } +TopEnv; + + +//===================== These are prologs ==================== +//===A prolog is data immediately before pointer returned by a create function. +//= +struct _PRLangEnv + { //============== First two must match PRCollElem ============== + int32 langMagicNumber; //indexes into hash array of langEnvs in PRProcess + PRLangEnv *chainedLangEnv; //chains to langEnvs with same hash + //============================================================= + + SlaveAssigner slaveAssigner; + RequestHandler requestHdlr; + RequestHandler shutdownHdlr; //called when lang ended or process shutdown + +/* + CreateTaskHdlr createTaskHdlr; + RequestHandler endTaskHdlr; + CreateSlvHdlr createSlaveHdlr; + RequestHandler dissipateSlaveHdlr; + */ + RequestHandler langDataCreator; + 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 + int32 hasWork; + PRProcess *processEnvIsIn; + + int32 idxInProcess; //index into array of langEnvs in the process + }; +//PRLangEnv -- this is the prolog of every lang's lang env + +enum PRTaskType + { GenericSlave = 1, + SlotTask, + FreeTask + }; + +struct _PRMetaTask + { //============== First two must match PRCollElem ============== + int32 langMagicNumber; + PRMetaTask *chainedMetaTask; + //============================================================= + enum PRTaskType taskType; + int32 *ID; //is standard PR ID + SlaveVP *slaveAssignedTo; //no valid until task animated + TopLevelFnPtr topLevelFn; //This is the Fn executes as the task + void *initData; //The data taken by the function + void (*recycler)(void *); + + //NOTE: info needed for "wait" functionality is inside lang's metaTask + }; +//PRMetaTask -- prolog of every lang's meta task + +struct _PRLangData + { //============== First two must match PRCollElem ============== + int32 langMagicNumber; + PRLangData *chainedLangData; + //============================================================= + void (*recycler)(void *); + void *langLangData; + }; +//PRLangData -- this is the prolog of each lang's lang data + +struct _PRCollElem + { + int32 hash; + PRCollElem *chained; + }; +//PRCollElem -- this is generic form of all the prologs + + + +//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 + { + + } +PRExcp; //exception + +//======================= OS Thread related =============================== + +void * coreController( void *paramsIn ); //standard PThreads fn prototype +void * coreCtlr_Seq( void *paramsIn ); //standard PThreads fn prototype +void animationMaster( void *initData, SlaveVP *masterVP ); + + +typedef struct + { + void *endThdPt; + unsigned int coreNum; + } +ThdParams; + +#endif /* _PR__structs_H */ + diff -r 608833ae2c5d -r e5bd470b562b PR_primitive_data_types.h --- a/PR_primitive_data_types.h Sun Nov 04 18:39:28 2012 -0800 +++ b/PR_primitive_data_types.h Mon Jan 14 15:31:23 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 diff -r 608833ae2c5d -r e5bd470b562b Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h --- a/Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h Sun Nov 04 18:39:28 2012 -0800 +++ b/Services_Offered_by_PR/Measurement_and_Stats/MEAS__macros.h Mon Jan 14 15:31:23 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 @@ -368,7 +368,7 @@ #define HOLISTIC__Insert_Master_Global_Vars \ int vpid,task; \ - CounterHandler counterHandler = masterEnv->counterHandler; + CounterHandler counterHandler = _PRTopEnv->counterHandler; #define HOLISTIC__Record_last_work lastVPBeforeMaster = currVP; @@ -376,7 +376,7 @@ uint64 cycles,instrs,cachem; \ saveCyclesAndInstrs(thisCoresIdx,cycles, instrs,cachem); \ if(lastVPBeforeMaster){ \ - (*counterHandler)(AppResponderInvocation_start,lastVPBeforeMaster->slaveID,lastVPBeforeMaster->numTimesAssignedToASlot,lastVPBeforeMaster,cycles,instrs,cachem); \ + (*counterHandler)(AppResponderInvocation_start,lastVPBeforeMaster->slaveNum,lastVPBeforeMaster->numTimesAssignedToASlot,lastVPBeforeMaster,cycles,instrs,cachem); \ lastVPBeforeMaster = NULL; \ } else { \ _PRTopEnv->start_master_lock[thisCoresIdx][0] = cycles; \ @@ -395,7 +395,7 @@ * would be erroneously counted as invocation time. */ #define HOLISTIC__Record_AppResponder_start \ - vpid = currSlot->slaveAssignedToSlot->slaveID; \ + vpid = currSlot->slaveAssignedToSlot->slaveNum; \ task = currSlot->slaveAssignedToSlot->numTimesAssignedToASlot; \ uint64 cycles, instrs, cachem; \ saveCyclesAndInstrs(thisCoresIdx,cycles, instrs,cachem); \ @@ -429,30 +429,30 @@ uint64 cycles,instrs,cachem; \ saveCyclesAndInstrs(thisCoresIdx,cycles,instrs,cachem); \ if(empty){ \ - (*counterHandler)(AssignerInvocation_start,assignedSlaveVP->slaveID,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,masterEnv->start_master_lock[thisCoresIdx][0],masterEnv->start_master_lock[thisCoresIdx][1],masterEnv->start_master_lock[thisCoresIdx][2]); \ + (*counterHandler)(AssignerInvocation_start,assignedSlaveVP->slaveNum,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,_PRTopEnv->start_master_lock[thisCoresIdx][0],_PRTopEnv->start_master_lock[thisCoresIdx][1],masterEnv->start_master_lock[thisCoresIdx][2]); \ } \ - (*counterHandler)(Timestamp_start,assignedSlaveVP->slaveID,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,tsc,0,0); \ - (*counterHandler)(Assigner_start,assignedSlaveVP->slaveID,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,tmp_cycles,tmp_instrs,tmp_cachem); \ - (*counterHandler)(Assigner_end,assignedSlaveVP->slaveID,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,cycles,instrs,tmp_cachem); + (*counterHandler)(Timestamp_start,assignedSlaveVP->slaveNum,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,tsc,0,0); \ + (*counterHandler)(Assigner_start,assignedSlaveVP->slaveNum,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,tmp_cycles,tmp_instrs,tmp_cachem); \ + (*counterHandler)(Assigner_end,assignedSlaveVP->slaveNum,assignedSlaveVP->numTimesAssignedToASlot,assignedSlaveVP,cycles,instrs,tmp_cachem); #define HOLISTIC__Record_Work_start \ if(currVP){ \ uint64 cycles,instrs,cachem; \ saveCyclesAndInstrs(thisCoresIdx,cycles, instrs,cachem); \ - (*counterHandler)(Work_start,currVP->slaveID,currVP->numTimesAssignedToASlot,currVP,cycles,instrs,cachem); \ + (*counterHandler)(Work_start,currVP->slaveNum,currVP->numTimesAssignedToASlot,currVP,cycles,instrs,cachem); \ } #define HOLISTIC__Record_Work_end \ if(currVP){ \ uint64 cycles,instrs,cachem; \ saveCyclesAndInstrs(thisCoresIdx,cycles, instrs,cachem); \ - (*counterHandler)(Work_end,currVP->slaveID,currVP->numTimesAssignedToASlot,currVP,cycles,instrs,cachem); \ + (*counterHandler)(Work_end,currVP->slaveNum,currVP->numTimesAssignedToASlot,currVP,cycles,instrs,cachem); \ } #define HOLISTIC__Record_HwResponderInvocation_start \ uint64 cycles,instrs,cachem; \ saveCyclesAndInstrs(animatingSlv->coreAnimatedBy,cycles, instrs,cachem); \ - (*(_PRTopEnv->counterHandler))(HwResponderInvocation_start,animatingSlv->slaveID,animatingSlv->numTimesAssignedToASlot,animatingSlv,cycles,instrs,cachem); + (*(_PRTopEnv->counterHandler))(HwResponderInvocation_start,animatingSlv->slaveNum,animatingSlv->numTimesAssignedToASlot,animatingSlv,cycles,instrs,cachem); #define getReturnAddressBeforeLibraryCall(vp_ptr, res_ptr) do{ \ diff -r 608833ae2c5d -r e5bd470b562b Services_Offered_by_PR/Memory_Handling/vmalloc.c --- a/Services_Offered_by_PR/Memory_Handling/vmalloc.c Sun Nov 04 18:39:28 2012 -0800 +++ b/Services_Offered_by_PR/Memory_Handling/vmalloc.c Mon Jan 14 15:31:23 2013 -0800 @@ -366,8 +366,7 @@ PR_ext__create_free_list() { //Initialize containers for small chunks and fill with zeros - _PRTopEnv->freeLists = (MallocArrays*)malloc( sizeof(MallocArrays) ); - MallocArrays *freeLists = _PRTopEnv->freeLists; + MallocArrays *freeLists = (MallocArrays*)malloc( sizeof(MallocArrays) ); freeLists->smallChunks = (MallocProlog**)malloc(SMALL_CHUNK_COUNT*sizeof(MallocProlog*));