# HG changeset patch # User Sean Halle # Date 1350553470 25200 # Node ID a60399b62614793bda94bccb529e47615066b5a8 # Parent 5bc52d3eae7d76dcb2da2887cfedcace0cdeecfc Update.. in middle of changes.. diff -r 5bc52d3eae7d -r a60399b62614 Measurement/VSs_Counter_Recording.c --- a/Measurement/VSs_Counter_Recording.c Mon Sep 03 03:26:12 2012 -0700 +++ b/Measurement/VSs_Counter_Recording.c Thu Oct 18 02:44:30 2012 -0700 @@ -4,18 +4,20 @@ */ #include "VSs_Counter_Recording.h" -#include "VMS_impl/VMS.h" +#include "PR_impl/PR.h" #include "VSs_impl/VSs.h" #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS -void VSs__init_counter_data_structs(){ - VSsSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv; - int i; - for(i=0;icounterList[i] = makeListOfArrays(sizeof(CounterEvent), 128); +void VSs__init_counter_data_structs( SlaveVP *slave ) + { + VSsSemEnv *semanticEnv = + (VSsSemEnv *)PR_SS__give_sem_env_for( slave, VSs_MAGIC_NUMBER ); + int i; + for(i=0;icounterList[i] = makeListOfArrays(sizeof(CounterEvent), 128); } -} + } void addToListOfArraysCounterEvent(CounterEvent value, ListOfArrays* list){ int offset_in_fragment = list->next_free_index % list->num_entries_per_fragment; @@ -36,7 +38,7 @@ return; } - VSsSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv; + VSsSemEnv *semanticEnv = _PRMasterEnv->semanticEnv; CounterEvent e; e.event_type = evt_type; diff -r 5bc52d3eae7d -r a60399b62614 Measurement/VSs_Counter_Recording.h --- a/Measurement/VSs_Counter_Recording.h Mon Sep 03 03:26:12 2012 -0700 +++ b/Measurement/VSs_Counter_Recording.h Thu Oct 18 02:44:30 2012 -0700 @@ -8,7 +8,7 @@ #ifndef VSs_COUNTER_RECORDING_H #define VSs_COUNTER_RECORDING_H -#include "VMS_impl/VMS.h" +#include "PR_impl/PR.h" typedef struct { int event_type; diff -r 5bc52d3eae7d -r a60399b62614 Measurement/VSs_Measurement.h --- a/Measurement/VSs_Measurement.h Mon Sep 03 03:26:12 2012 -0700 +++ b/Measurement/VSs_Measurement.h Thu Oct 18 02:44:30 2012 -0700 @@ -26,8 +26,8 @@ #define ReceiveOfTypeHistIdx 4 #define MEAS__Make_Meas_Hists_for_Language \ - _VMSMasterEnv->measHistsInfo = \ - makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \ + _PRMasterEnv->measHistsInfo = \ + makePrivDynArrayOfSize( (void***)&(_PRMasterEnv->measHists), 200); \ makeAMeasHist( SendFromToHistIdx, "SendFromTo", 50, 0, 100 ) \ makeAMeasHist( SendOfTypeHistIdx, "SendOfType", 50, 0, 100 ) \ makeAMeasHist( ReceiveFromToHistIdx,"ReceiveFromTo", 50, 0, 100 ) \ @@ -40,7 +40,7 @@ #define Meas_endSendFromTo \ saveLowTimeStampCountInto( endStamp ); \ addIntervalToHist( startStamp, endStamp, \ - _VMSMasterEnv->measHists[ SendFromToHistIdx ] ); + _PRMasterEnv->measHists[ SendFromToHistIdx ] ); #define Meas_startSendOfType \ int32 startStamp, endStamp; \ @@ -49,7 +49,7 @@ #define Meas_endSendOfType \ saveLowTimeStampCountInto( endStamp ); \ addIntervalToHist( startStamp, endStamp, \ - _VMSMasterEnv->measHists[ SendOfTypeHistIdx ] ); + _PRMasterEnv->measHists[ SendOfTypeHistIdx ] ); #define Meas_startReceiveFromTo \ int32 startStamp, endStamp; \ @@ -58,7 +58,7 @@ #define Meas_endReceiveFromTo \ saveLowTimeStampCountInto( endStamp ); \ addIntervalToHist( startStamp, endStamp, \ - _VMSMasterEnv->measHists[ ReceiveFromToHistIdx ] ); + _PRMasterEnv->measHists[ ReceiveFromToHistIdx ] ); #define Meas_startReceiveOfType \ int32 startStamp, endStamp; \ @@ -67,7 +67,7 @@ #define Meas_endReceiveOfType \ saveLowTimeStampCountInto( endStamp ); \ addIntervalToHist( startStamp, endStamp, \ - _VMSMasterEnv->measHists[ReceiveOfTypeHistIdx ] ); + _PRMasterEnv->measHists[ReceiveOfTypeHistIdx ] ); #else //===================== turned off ========================== diff -r 5bc52d3eae7d -r a60399b62614 Measurement/dependency.c --- a/Measurement/dependency.c Mon Sep 03 03:26:12 2012 -0700 +++ b/Measurement/dependency.c Thu Oct 18 02:44:30 2012 -0700 @@ -1,8 +1,8 @@ #include "dependency.h" -#include "VMS_impl/VMS.h" +#include "PR_impl/PR.h" Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task){ - Dependency* newDep = (Dependency*) VMS_int__malloc(sizeof(Dependency)); + Dependency* newDep = (Dependency*) PR_int__malloc(sizeof(Dependency)); if (newDep!=NULL){ newDep->from_vp = from_vp; newDep->from_task = from_task; @@ -13,7 +13,7 @@ } NtoN* new_NtoN(int id){ - NtoN* newn = (NtoN*) VMS_int__malloc(sizeof(NtoN)); + NtoN* newn = (NtoN*) PR_int__malloc(sizeof(NtoN)); newn->id = id; newn->senders = makeListOfArrays(sizeof(Unit), 64); newn->receivers = makeListOfArrays(sizeof(Unit), 64); diff -r 5bc52d3eae7d -r a60399b62614 VSs.c --- a/VSs.c Mon Sep 03 03:26:12 2012 -0700 +++ b/VSs.c Thu Oct 18 02:44:30 2012 -0700 @@ -16,11 +16,6 @@ //========================================================================== -void -VSs__init(); - -void -VSs__init_Helper(); //========================================================================== @@ -31,8 +26,8 @@ /*These are the library functions *called in the application* * *There's a pattern for the outside sequential code to interact with the - * VMS_HW code. - *The VMS_HW system is inside a boundary.. every VSs system is in its + * PR_HW code. + *The PR_HW system is inside a boundary.. every VSs system is in its * own directory that contains the functions for each of the processor types. * One of the processor types is the "seed" processor that starts the * cascade of creating all the processors that do the work. @@ -58,60 +53,6 @@ //=========================================================================== -/*This is the "border crossing" function -- the thing that crosses from the - * outside world, into the VMS_HW world. It initializes and starts up the - * VMS system, then creates one processor from the specified function and - * puts it into the readyQ. From that point, that one function is resp. - * for creating all the other processors, that then create others, and so - * forth. - *When all the processors, including the seed, have dissipated, then this - * function returns. The results will have been written by side-effect via - * pointers read from, or written into initData. - * - *NOTE: no Threads should exist in the outside program that might touch - * any of the data reachable from initData passed in to here - */ -void -VSs__create_seed_slave_and_do_work( TopLevelFnPtr fnPtr, void *initData ) - { VSsSemEnv *semEnv; - SlaveVP *seedSlv; - VSsSemData *semData; - VSsTaskStub *threadTaskStub, *parentTaskStub; - - VSs__init(); //normal multi-thd - - semEnv = _VMSMasterEnv->semanticEnv; - - //VSs starts with one processor, which is put into initial environ, - // and which then calls create() to create more, thereby expanding work - seedSlv = VSs__create_slave_helper( fnPtr, initData, - semEnv, semEnv->nextCoreToGetNewSlv++ ); - - //seed slave is a thread slave, so make a thread's task stub for it - // and then make another to stand for the seed's parent task. Make - // the parent be already ended, and have one child (the seed). This - // will make the dissipate handler do the right thing when the seed - // is dissipated. - threadTaskStub = create_thread_task_stub( initData ); - parentTaskStub = create_thread_task_stub( NULL ); - parentTaskStub->isEnded = TRUE; - parentTaskStub->numLiveChildThreads = 1; //so dissipate works for seed - threadTaskStub->parentTaskStub = parentTaskStub; - - semData = (VSsSemData *)seedSlv->semanticData; - //seedVP is a thread, so has a permanent task - semData->needsTaskAssigned = FALSE; - semData->taskStub = threadTaskStub; - semData->slaveType = ThreadSlv; - - resume_slaveVP( seedSlv, semEnv ); //returns right away, just queues Slv - - VMS_SS__start_the_work_then_wait_until_done(); //normal multi-thd - - VSs__cleanup_after_shutdown(); - } - - int32 VSs__giveMinWorkUnitCycles( float32 percentOverhead ) { @@ -134,9 +75,12 @@ * saves jump point, and second jumps back several times to get reliable time */ void -VSs__start_primitive() - { saveLowTimeStampCountInto( ((VSsSemEnv *)(_VMSMasterEnv->semanticEnv))-> - primitiveStartTime ); +VSs__begin_primitive() + { VSsSemData *semData; + + semData = (VSsSemData *)PR_WL__give_sem_data( animSlv, VSs_MAGIC_NUMBER); + + saveLowTimeStampCountInto( semData->primitiveStartTime ); } /*Just quick and dirty for now -- make reliable later @@ -145,262 +89,21 @@ * also to throw out any "weird" values due to OS interrupt or TSC rollover */ int32 -VSs__end_primitive_and_give_cycles() +VSs__end_primitive_and_give_cycles( SlaveVP animSlv ) { int32 endTime, startTime; + VSsSemData *semData; + //TODO: fix by repeating time-measurement saveLowTimeStampCountInto( endTime ); - startTime =((VSsSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime; + semData = (VSsSemData *)PR_WL__give_sem_data( animSlv, VSs_MAGIC_NUMBER); + startTime = semData->primitiveStartTime; return (endTime - startTime); } + //=========================================================================== -/*Initializes all the data-structures for a VSs system -- but doesn't - * start it running yet! - * - *This runs in the main thread -- before VMS starts up - * - *This sets up the semantic layer over the VMS system - * - *First, calls VMS_Setup, then creates own environment, making it ready - * for creating the seed processor and then starting the work. - */ -void -VSs__init() - { - VMS_SS__init(); - //masterEnv, a global var, now is partially set up by init_VMS - // after this, have VMS_int__malloc and VMS_int__free available - VSs__init_Helper(); - } - - -void idle_fn(void* data, SlaveVP *animatingSlv){ - while(1){ - VMS_int__suspend_slaveVP_and_send_req(animatingSlv); - } -} - -void -VSs__init_Helper() - { VSsSemEnv *semanticEnv; - int32 i, coreNum, slotNum; - VSsSemData *semData; - - //Hook up the semantic layer's plug-ins to the Master virt procr - _VMSMasterEnv->requestHandler = &VSs__Request_Handler; - _VMSMasterEnv->slaveAssigner = &VSs__assign_slaveVP_to_slot; - - //create the semantic layer's environment (all its data) and add to - // the master environment - semanticEnv = VMS_int__malloc( sizeof( VSsSemEnv ) ); - _VMSMasterEnv->semanticEnv = semanticEnv; - - #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS - _VMSMasterEnv->counterHandler = &VSs__counter_handler; - VSs__init_counter_data_structs(); - #endif - - semanticEnv->shutdownInitiated = FALSE; - semanticEnv->coreIsDone = VMS_int__malloc( NUM_CORES * sizeof( bool32 ) ); - //For each animation slot, there is an idle slave, and an initial - // slave assigned as the current-task-slave. Create them here. - SlaveVP *idleSlv, *slotTaskSlv; - for( coreNum = 0; coreNum < NUM_CORES; coreNum++ ) - { semanticEnv->coreIsDone[coreNum] = FALSE; //use during shutdown - - for( slotNum = 0; slotNum < NUM_ANIM_SLOTS; ++slotNum ) - { idleSlv = VSs__create_slave_helper( &idle_fn, NULL, semanticEnv, 0); - idleSlv->coreAnimatedBy = coreNum; - idleSlv->animSlotAssignedTo = - _VMSMasterEnv->allAnimSlots[coreNum][slotNum]; - semanticEnv->idleSlv[coreNum][slotNum] = idleSlv; - - slotTaskSlv = VSs__create_slave_helper( &idle_fn, NULL, semanticEnv, 0); - slotTaskSlv->coreAnimatedBy = coreNum; - slotTaskSlv->animSlotAssignedTo = - _VMSMasterEnv->allAnimSlots[coreNum][slotNum]; - - semData = slotTaskSlv->semanticData; - semData->needsTaskAssigned = TRUE; - semData->slaveType = SlotTaskSlv; - semanticEnv->slotTaskSlvs[coreNum][slotNum] = slotTaskSlv; - } - } - - //create the ready queues, hash tables used for matching and so forth - semanticEnv->slavesReadyToResumeQ = makeVMSQ(); - semanticEnv->freeExtraTaskSlvQ = makeVMSQ(); - semanticEnv->taskReadyQ = makeVMSQ(); - - semanticEnv->argPtrHashTbl = makeHashTable32( 16, &VMS_int__free ); - semanticEnv->commHashTbl = makeHashTable32( 16, &VMS_int__free ); - - semanticEnv->nextCoreToGetNewSlv = 0; - - - //TODO: bug -- turn these arrays into dyn arrays to eliminate limit - //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); - //semanticEnv->transactionStrucs = makeDynArrayInfo( ); - for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) - { - semanticEnv->fnSingletons[i].endInstrAddr = NULL; - semanticEnv->fnSingletons[i].hasBeenStarted = FALSE; - semanticEnv->fnSingletons[i].hasFinished = FALSE; - semanticEnv->fnSingletons[i].waitQ = makeVMSQ(); - semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSQ(); - } - - semanticEnv->numLiveExtraTaskSlvs = 0; //must be last - semanticEnv->numLiveThreadSlvs = 1; //must be last, counts the seed - - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - semanticEnv->unitList = makeListOfArrays(sizeof(Unit),128); - semanticEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); - semanticEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); - semanticEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); - semanticEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semanticEnv->ntonGroups),8); - - semanticEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); - memset(semanticEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); - #endif - } - - -/*Frees any memory allocated by VSs__init() then calls VMS_int__shutdown - */ -void -VSs__cleanup_after_shutdown() - { VSsSemEnv *semanticEnv; - - semanticEnv = _VMSMasterEnv->semanticEnv; - - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - //UCC - FILE* output; - int n; - char filename[255]; - for(n=0;n<255;n++) - { - sprintf(filename, "./counters/UCC.%d",n); - output = fopen(filename,"r"); - if(output) - { - fclose(output); - }else{ - break; - } - } - if(n<255){ - printf("Saving UCC to File: %s ...\n", filename); - output = fopen(filename,"w+"); - if(output!=NULL){ - set_dependency_file(output); - //fprintf(output,"digraph Dependencies {\n"); - //set_dot_file(output); - //FIXME: first line still depends on counters being enabled, replace w/ unit struct! - //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); - forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file); - forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); - forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file); - //fprintf(output,"}\n"); - fflush(output); - - } else - printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); - } else { - printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); - } - //Loop Graph - for(n=0;n<255;n++) - { - sprintf(filename, "./counters/LoopGraph.%d",n); - output = fopen(filename,"r"); - if(output) - { - fclose(output); - }else{ - break; - } - } - if(n<255){ - printf("Saving LoopGraph to File: %s ...\n", filename); - output = fopen(filename,"w+"); - if(output!=NULL){ - set_dependency_file(output); - //fprintf(output,"digraph Dependencies {\n"); - //set_dot_file(output); - //FIXME: first line still depends on counters being enabled, replace w/ unit struct! - //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); - forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file ); - forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file ); - forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file ); - //fprintf(output,"}\n"); - fflush(output); - - } else - printf("Opening LoopGraph file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); - } else { - printf("Could not open LoopGraph file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); - } - - - freeListOfArrays(semanticEnv->unitList); - freeListOfArrays(semanticEnv->commDependenciesList); - freeListOfArrays(semanticEnv->ctlDependenciesList); - freeListOfArrays(semanticEnv->dynDependenciesList); - - #endif -#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS - for(n=0;n<255;n++) - { - sprintf(filename, "./counters/Counters.%d.csv",n); - output = fopen(filename,"r"); - if(output) - { - fclose(output); - }else{ - break; - } - } - if(n<255){ - printf("Saving Counter measurements to File: %s ...\n", filename); - output = fopen(filename,"w+"); - if(output!=NULL){ - set_counter_file(output); - int i; - for(i=0;icounterList[i], &print_counter_events_to_file ); - fflush(output); - } - - } else - printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); - } else { - printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); - } - -#endif -/* It's all allocated inside VMS's big chunk -- that's about to be freed, so - * nothing to do here - - - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) - { - VMS_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); - VMS_int__free( semanticEnv->readyVPQs[coreIdx] ); - } - VMS_int__free( semanticEnv->readyVPQs ); - - freeHashTable( semanticEnv->commHashTbl ); - VMS_int__free( _VMSMasterEnv->semanticEnv ); - */ - VMS_SS__cleanup_at_end_of_shutdown(); - } //=========================================================================== @@ -408,18 +111,33 @@ SlaveVP * VSs__create_thread( TopLevelFnPtr fnPtr, void *initData, SlaveVP *creatingThd ) + { + return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID, + ANY_CORE, creatingThd ); + } + +SlaveVP * +VSs__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID, + SlaveVP *creatingThd ) + { + return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, thdID, + ANY_CORE, creatingThd ); + } + + +SlaveVP * +VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, + int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ) { VSsSemReq reqData; //the semantic request data is on the stack and disappears when this // call returns -- it's guaranteed to remain in the VP's stack for as // long as the VP is suspended. - reqData.reqType = 0; //know type because in a VMS create req - reqData.fnPtr = fnPtr; - reqData.initData = initData; - reqData.callingSlv = creatingThd; - - VMS_WL__send_create_slaveVP_req( &reqData, creatingThd ); - + reqData.reqType = create_slave; //know type because in a PR create req + reqData.coreToAssignOnto = coreToAssignOnto; + + PR_WL__send_create_slaveVP_req( &reqData, fnPtr, initData, thdID, + creatingThd, VSs_MAGIC_NUMBER ); return creatingThd->dataRetFromReq; } @@ -432,9 +150,8 @@ */ void VSs__end_thread( SlaveVP *thdToEnd ) - { VSsSemData *semData; - - VMS_WL__send_dissipate_req( thdToEnd ); + { + PR_WL__send_dissipate_req( thdToEnd, VSs_MAGIC_NUMBER ); } @@ -454,34 +171,25 @@ reqData.taskType = taskType; reqData.args = args; reqData.callingSlv = animSlv; - - reqData.taskID = NULL; - - VMS_WL__send_sem_request( &reqData, animSlv ); - } - -inline int32 * -VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv ) - { int32 *taskID; - taskID = VMS_WL__malloc( sizeof(int32) + numInts * sizeof(int32) ); - taskID[0] = numInts; - return taskID; + //Create task is a special form, so have to pass as parameters, the + // top-level-fn of task and the data for that fn, plus lang's req, + // animating slave, and lang's magic number + PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID, animSlv, VSs_MAGIC_NUMBER ); } void VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, SlaveVP *animSlv) { VSsSemReq reqData; - + reqData.reqType = submit_task; reqData.taskType = taskType; reqData.args = args; - reqData.taskID = taskID; reqData.callingSlv = animSlv; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID, animSlv, VSs_MAGIC_NUMBER ); } @@ -490,8 +198,8 @@ * assigner here.. only one slave, no slave ReadyQ, and so on.. *Can either make the assigner take the next task out of the taskQ, or can * leave all as it is, and make task-end take the next task. - *Note: this fits the case in the new VMS for no-context tasks, so will use - * the built-in taskQ of new VMS, and should be local and much faster. + *Note: this fits the case in the new PR for no-context tasks, so will use + * the built-in taskQ of new PR, and should be local and much faster. * *The task-stub is saved in the animSlv, so the request handler will get it * from there, along with the task-type which has arg types, and so on.. @@ -500,7 +208,7 @@ * instead, can make a single slave per core, and coreCtrlr looks up the * slave from having the core number. * - *But, to stay compatible with all the other VMS languages, leave it in.. + *But, to stay compatible with all the other PR languages, leave it in.. */ void VSs__end_task( SlaveVP *animSlv ) @@ -509,20 +217,23 @@ reqData.reqType = end_task; reqData.callingSlv = animSlv; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_end_task_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); } +/*Waits for all tasks that are direct children to end, then resumes calling + * task or thread + */ void VSs__taskwait(SlaveVP *animSlv) -{ + { VSsSemReq reqData; reqData.reqType = taskwait; reqData.callingSlv = animSlv; - VMS_WL__send_sem_request( &reqData, animSlv ); -} + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); + } @@ -532,7 +243,7 @@ inline int32 * VSs__give_self_taskID( SlaveVP *animSlv ) { - return ((VSsSemData*)animSlv->semanticData)->taskStub->taskID; + return PR__give_task_ID( animSlv, VSs_MAGIC_NUMBER ); } //================================ send =================================== @@ -551,7 +262,7 @@ reqData.nextReqInHashEntry = NULL; - VMS_WL__send_sem_request( &reqData, senderSlv ); + PR_WL__send_sem_request( &reqData, senderSlv, VSs_MAGIC_NUMBER ); //When come back from suspend, no longer own data reachable from msg } @@ -569,7 +280,7 @@ reqData.nextReqInHashEntry = NULL; - VMS_WL__send_sem_request( &reqData, senderSlv ); + PR_WL__send_sem_request( &reqData, senderSlv, VSs_MAGIC_NUMBER ); } @@ -594,7 +305,7 @@ reqData.nextReqInHashEntry = NULL; - VMS_WL__send_sem_request( &reqData, receiverSlv ); + PR_WL__send_sem_request( &reqData, receiverSlv, VSs_MAGIC_NUMBER ); return receiverSlv->dataRetFromReq; } @@ -619,7 +330,7 @@ reqData.nextReqInHashEntry = NULL; DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); - VMS_WL__send_sem_request( &reqData, receiverSlv ); + PR_WL__send_sem_request( &reqData, receiverSlv, VSs_MAGIC_NUMBER ); return receiverSlv->dataRetFromReq; } @@ -655,10 +366,10 @@ reqData.reqType = singleton_fn_start; reqData.singletonID = singletonID; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton { - VSsSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); + VSsSemEnv *semEnv = PR_WL__give_sem_env_for( animSlv, VSs_MAGIC_NUMBER ); asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); } } @@ -678,7 +389,7 @@ reqData.reqType = singleton_data_start; reqData.singletonPtrAddr = singletonAddr; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr { //Assembly code changes the return addr on the stack to the one // saved into the singleton by the end-singleton-fn @@ -703,13 +414,13 @@ //don't need this addr until after at least one singleton has reached // this function - VSsSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); + VSsSemEnv *semEnv = PR_WL__give_sem_env_for( animSlv, VSs_MAGIC_NUMBER ); asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); reqData.reqType = singleton_fn_end; reqData.singletonID = singletonID; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); EndSingletonInstrAddr: return; @@ -726,15 +437,12 @@ // data singleton -- that data-singleton can only be given to exactly // one instance in the code of this function. However, can use this // function in different places for different data-singletons. -// (*(singletonAddr))->endInstrAddr = &&EndDataSingletonInstrAddr; - - asm_save_ret_to_singleton(*singletonPtrAddr); reqData.reqType = singleton_data_end; reqData.singletonPtrAddr = singletonPtrAddr; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); } /*This executes the function in the masterVP, so it executes in isolation @@ -758,7 +466,7 @@ reqData.fnToExecInMaster = ptrToFnToExecInMaster; reqData.dataForFn = data; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); } @@ -781,11 +489,11 @@ VSsSemReq reqData; // - reqData.callingSlv = animSlv; + reqData.callingSlv = animSlv; reqData.reqType = trans_start; reqData.transID = transactionID; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); } /*This suspends to the master, then uses transactionID as index into an @@ -807,30 +515,12 @@ reqData.reqType = trans_end; reqData.transID = transactionID; - VMS_WL__send_sem_request( &reqData, animSlv ); + PR_WL__send_sem_request( &reqData, animSlv, VSs_MAGIC_NUMBER ); } //======================== Internal ================================== /* */ -SlaveVP * -VSs__create_slave_with( TopLevelFnPtr fnPtr, void *initData, - SlaveVP *creatingSlv ) - { VSsSemReq reqData; - - //the semantic request data is on the stack and disappears when this - // call returns -- it's guaranteed to remain in the VP's stack for as - // long as the VP is suspended. - reqData.reqType = 0; //know type because in a VMS create req - reqData.coreToAssignOnto = -1; //means round-robin assign - reqData.fnPtr = fnPtr; - reqData.initData = initData; - reqData.callingSlv = creatingSlv; - - VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv ); - - return creatingSlv->dataRetFromReq; - } SlaveVP * VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, @@ -846,7 +536,7 @@ reqData.initData = initData; reqData.callingSlv = creatingSlv; - VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv ); + PR_WL__send_create_slaveVP_req( &reqData, creatingSlv, VSs_MAGIC_NUMBER ); return creatingSlv->dataRetFromReq; } diff -r 5bc52d3eae7d -r a60399b62614 VSs.h --- a/VSs.h Mon Sep 03 03:26:12 2012 -0700 +++ b/VSs.h Thu Oct 18 02:44:30 2012 -0700 @@ -11,24 +11,28 @@ #include "Queue_impl/PrivateQueue.h" #include "Hash_impl/PrivateHash.h" -#include "VMS_impl/VMS.h" +#include "PR_impl/PR.h" #include "Measurement/dependency.h" //=========================================================================== + //uniquely identifies VSs -- should be a jenkins char-hash of "VSs" to int32 +#define VSs_MAGIC_NUMBER 0000000001 + #define NUM_STRUCS_IN_SEM_ENV 1000 //This is hardware dependent -- it's the number of cycles of scheduling // overhead -- if a work unit is fewer than this, it is better being // combined sequentially with other work - //This value depends on both VMS overhead and VSs's plugin. At some point + //This value depends on both PR overhead and VSs's plugin. At some point // it will be derived by perf-counter measurements during init of VSs #define MIN_WORK_UNIT_CYCLES 20000 //=========================================================================== /*This header defines everything specific to the VSs semantic plug-in */ -typedef struct _VSsSemReq VSsSemReq; +typedef struct _VSsSemReq VSsSemReq; +typedef struct _VSsTaskStub VSsTaskStub; typedef void (*VSsTaskFnPtr ) ( void *, SlaveVP *); typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master //=========================================================================== @@ -45,6 +49,10 @@ #define IS_ENDED NULL #define SEED_SLV NULL +#define NO_ID NULL +#define ANY_CORE -1 + +//=========================================================================== typedef struct { VSsTaskFnPtr fn; @@ -65,22 +73,24 @@ } VSsPointerEntry; -typedef struct +/*This is placed into semData, used for dependencies and wait construct*/ +struct _VSsTaskStub { - void **args; //ctld args must come first, as ptrs - VSsTaskType *taskType; - int32 *taskID; - int32 numBlockingProp; - SlaveVP *slaveAssignedTo; //only valid before end task (thread) - VSsPointerEntry **ptrEntries; - void* parentTaskStub; + int32 langMagicNumber; //magic num must be 1st field of langMetaTask + PRMetaTask *protoMetaTask; //back-link must always be 2nd field + void **args; //ctld args must be the first ones (as ptrs) + VSsPointerEntry **ptrEntries; + int32 numBlockingProp; + + VSsTaskType *taskType; //has VSs lang related info + + VSsTaskStub *parentTaskStub; //for liveness, for the wait construct int32 numLiveChildTasks; int32 numLiveChildThreads; bool32 isWaitingForChildTasksToEnd; bool32 isWaitingForChildThreadsToEnd; bool32 isEnded; - } -VSsTaskStub; + }; typedef struct @@ -144,7 +154,7 @@ SlaveVP *callingSlv; VSsTaskType *taskType; void *args; - VSsTaskStub *taskStub; +// VSsTaskStub *taskStub; //not needed -- get via PR accessor from slv SlaveVP *senderSlv; SlaveVP *receiverSlv; @@ -153,12 +163,13 @@ int32 msgType; void *msg; VSsSemReq *nextReqInHashEntry; - int32 *taskID; +//In PRReq: int32 *taskID; TopLevelFnPtr fnPtr; void *initData; int32 coreToAssignOnto; +//These, below, should move to util language.. int32 sizeToMalloc; void *ptrToFree; @@ -174,15 +185,15 @@ typedef struct - { + { PRSemEnv *protoSemEnv; PrivQueueStruc *slavesReadyToResumeQ; //Shared (slaves not pinned) - PrivQueueStruc *freeExtraTaskSlvQ; //Shared + PrivQueueStruc *freeTaskSlvRecycleQ; //Shared PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) - SlaveVP *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; +// SlaveVP *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; HashTable *argPtrHashTbl; HashTable *commHashTbl; - int32 numLiveExtraTaskSlvs; - int32 numLiveThreadSlvs; +// int32 numLiveFreeTaskSlvs; +// int32 numLiveThreadSlvs; int32 nextCoreToGetNewSlv; int32 primitiveStartTime; @@ -190,8 +201,11 @@ VSsSingleton fnSingletons[NUM_STRUCS_IN_SEM_ENV]; VSsTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; - bool32 *coreIsDone; - int32 numCoresDone; +// bool32 *coreIsDone; +// int32 numCoresDone; + +// SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS]; +// int shutdownInitiated; #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC ListOfArrays* unitList; @@ -207,8 +221,6 @@ #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS ListOfArrays* counterList[NUM_CORES]; #endif - SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS]; - int shutdownInitiated; } VSsSemEnv; @@ -221,19 +233,20 @@ }; //TransListElem +/* PR now handles what this used to be used for enum VSsSlvType - { ExtraTaskSlv = 1, + { FreeTaskSlv = 1, SlotTaskSlv, ThreadSlv }; +*/ typedef struct { - int32 highestTransEntered; - TransListElem *lastTransEntered; - bool32 needsTaskAssigned; - VSsTaskStub *taskStub; - enum VSsSlvType slaveType; + int32 highestTransEntered; + TransListElem *lastTransEntered; + int32 primitiveStartTime; +// VSsTaskStub *taskStub; //get from slave via PR accessor } VSsSemData; @@ -246,7 +259,7 @@ VSs__giveMinWorkUnitCycles( float32 percentOverhead ); void -VSs__start_primitive(); +VSs__begin_primitive(); int32 VSs__end_primitive_and_give_cycles(); @@ -260,7 +273,7 @@ //======================= void -VSs__init(); +VSs__start( SlaveVP *seedSlv ); void VSs__cleanup_after_shutdown(); @@ -276,9 +289,9 @@ //======================= -#define VSs__malloc( numBytes, callingSlave ) VMS_App__malloc( numBytes, callingSlave) +#define VSs__malloc( numBytes, callingSlave ) PR_App__malloc( numBytes, callingSlave) -#define VSs__free(ptrToFree, callingSlave ) VMS_App__free( ptrToFree, callingSlave ) +#define VSs__free(ptrToFree, callingSlave ) PR_App__free( ptrToFree, callingSlave ) //======================= @@ -351,8 +364,8 @@ VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData, VSsSemEnv *semEnv, int32 coreToAssignOnto ); -VSsTaskStub * -create_thread_task_stub( void *initData ); +PRMetaTask * +PR_int__create_generic_slave_meta_task( void *initData ); SlaveVP * @@ -363,9 +376,6 @@ VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, SlaveVP *creatingSlv, int32 coreToAssignOnto); -void -idle_fn(void* data, SlaveVP *animatingSlv); - //===================== Measurement of Lang Overheads ===================== #include "Measurement/VSs_Measurement.h" diff -r 5bc52d3eae7d -r a60399b62614 VSs_PluginFns.c --- a/VSs_PluginFns.c Mon Sep 03 03:26:12 2012 -0700 +++ b/VSs_PluginFns.c Thu Oct 18 02:44:30 2012 -0700 @@ -16,13 +16,13 @@ resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv ); inline void -handleSemReq( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); +handleSemReq( PRReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); inline void handleDissipate( SlaveVP *requestingSlv, VSsSemEnv *semEnv ); inline void -handleCreate( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); +handleCreate( PRReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); //============================== Assigner ================================== // @@ -30,6 +30,9 @@ * VPs, and by tasks being able to suspend. *It can't use an explicit slave to animate a task because of stack * pollution. So, it has to keep the two kinds separate. + * + *Q: one assigner for both tasks and slaves, or separate? + * *Simplest way for the assigner logic is with a Q for extra empty task * slaves, and another Q for slaves of both types that are ready to resume. * @@ -52,10 +55,8 @@ VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot ) { SlaveVP *returnSlv; VSsSemEnv *semEnv; - VSsSemData *semData; int32 coreNum, slotNum; - VSsTaskStub *newTaskStub; - SlaveVP *extraSlv; + PRMetaTask *returnMetaTask = NULL, *newTaskStub; coreNum = slot->coreSlotIsOn; slotNum = slot->slotIdx; @@ -66,173 +67,79 @@ returnSlv = readPrivQ( semEnv->slavesReadyToResumeQ ); if( returnSlv != NULL ) //Yes, have a slave, so return it. { returnSlv->coreAnimatedBy = coreNum; - - //have work, so reset Done flag (when work generated on other core) - if( semEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf - semEnv->coreIsDone[coreNum] = FALSE; //don't just write always - goto ReturnTheSlv; + returnMetaTask = returnSlv->metaTask; + goto ReturnTheMetaTask; } - //If none, speculate will have a task, so get the slot slave - //TODO: false sharing ? (think not bad cause mostly read..) - returnSlv = semEnv->slotTaskSlvs[coreNum][slotNum]; - - semData = (VSsSemData *)returnSlv->semanticData; - - //There is always a curr task slave, and it always needs a task - // (task slaves that are resuming are in resumeQ) newTaskStub = readPrivQ( semEnv->taskReadyQ ); if( newTaskStub != NULL ) - { //point slave to task's function, and mark slave as having task - VMS_int__reset_slaveVP_to_TopLvlFn( returnSlv, - newTaskStub->taskType->fn, newTaskStub->args ); - semData->taskStub = newTaskStub; - newTaskStub->slaveAssignedTo = returnSlv; - semData->needsTaskAssigned = FALSE; - - //have work, so reset Done flag, if was set - if( semEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf - semEnv->coreIsDone[coreNum] = FALSE; //don't just write always - goto ReturnTheSlv; + { returnMetaTask = newTaskStub->protoMetaTask; + goto ReturnTheMetaTask; } - else - { //no task, so try to clean up unused extra task slaves - extraSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); - if( extraSlv != NULL ) - { //have two slaves need tasks, so delete one - //This both bounds the num extras, and delivers shutdown cond - handleDissipate( extraSlv, semEnv ); - //then return NULL - returnSlv = NULL; - goto ReturnTheSlv; - } - else - { //candidate for shutdown.. if all extras dissipated, and no tasks - // and no ready to resume slaves, then no way to generate - // more tasks (on this core -- other core might have task still) - if( semEnv->numLiveExtraTaskSlvs == 0 && - semEnv->numLiveThreadSlvs == 0 ) - { //This core sees no way to generate more tasks, so say it - if( semEnv->coreIsDone[coreNum] == FALSE ) - { semEnv->numCoresDone += 1; - semEnv->coreIsDone[coreNum] = TRUE; - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - semEnv->shutdownInitiated = TRUE; - - #else - if( semEnv->numCoresDone == NUM_CORES ) - { //means no cores have work, and none can generate more - semEnv->shutdownInitiated = TRUE; - } - #endif - } - } - //return NULL.. no task and none to resume - returnSlv = NULL; - //except if shutdown has been initiated by this or other core - if(semEnv->shutdownInitiated) - { returnSlv = VMS_SS__create_shutdown_slave(); - } - goto ReturnTheSlv; //don't need, but completes pattern - } //if( extraSlv != NULL ) - } //if( newTaskStub == NULL ) - //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL -ReturnTheSlv: //Nina, doing gotos to here should help with holistic.. +ReturnTheMetaTask: //doing gotos to here should help with holistic.. #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - if( returnSlv == NULL ) - { returnSlv = semEnv->idleSlv[coreNum][slotNum]; + //This no longer works -- should be moved into PR in master + //This assumes the task has already been assigned to a slave, which happens + // inside Master.. + if( returnMetaTask == NULL ) + { returnSlv = semEnv->process->idleSlv[coreNum][slotNum]; //things that would normally happen in resume(), but these VPs // never go there - returnSlv->assignCount++; //Somewhere here! - Unit newu; - newu.vp = returnSlv->slaveID; - newu.task = returnSlv->assignCount; - addToListOfArrays(Unit,newu,semEnv->unitList); + returnSlv->numTimesAssignedToASlot++; + Unit newU; + newU.vp = returnSlv->slaveID; + newU.task = returnSlv->numTimesAssignedToASlot; + addToListOfArrays(Unit,newU,semEnv->unitList); - if (returnSlv->assignCount > 1) - { Dependency newd; - newd.from_vp = returnSlv->slaveID; - newd.from_task = returnSlv->assignCount - 1; - newd.to_vp = returnSlv->slaveID; - newd.to_task = returnSlv->assignCount; - addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList); + if (returnSlv->numTimesAssignedToASlot > 1) + { Dependency newD; + newD.from_vp = returnSlv->slaveID; + newD.from_task = returnSlv->numTimesAssignedToASlot - 1; + newD.to_vp = returnSlv->slaveID; + newD.to_task = returnSlv->numTimesAssignedToASlot; + addToListOfArrays(Dependency, newD, semEnv->ctlDependenciesList); } + returnMetaTask = returnSlv->metaTask; } - #endif - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - if( returnSlv != NULL ) + else //returnSlv != NULL { //assignSlv->numTimesAssigned++; Unit prev_in_slot = semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; if(prev_in_slot.vp != 0) - { Dependency newd; - newd.from_vp = prev_in_slot.vp; - newd.from_task = prev_in_slot.task; - newd.to_vp = returnSlv->slaveID; - newd.to_task = returnSlv->assignCount; - addToListOfArrays(Dependency,newd,semEnv->hwArcs); + { Dependency newD; + 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,semEnv->hwArcs); } prev_in_slot.vp = returnSlv->slaveID; - prev_in_slot.task = returnSlv->assignCount; + prev_in_slot.task = returnSlv->numTimesAssignedToASlot; semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = prev_in_slot; } #endif - return( returnSlv ); + return( returnMetaTask ); } //=========================== Request Handler ============================ // /* - * (BTW not inline because invoked indirectly via a pointer) + * (Not inline because invoked indirectly via a pointer) */ + void -VSs__Request_Handler( SlaveVP *requestingSlv, void *_semEnv ) - { VSsSemEnv *semEnv; - VMSReqst *req; - - semEnv = (VSsSemEnv *)_semEnv; - - req = VMS_PI__take_next_request_out_of( requestingSlv ); - - while( req != NULL ) - { - switch( req->reqType ) - { case semantic: handleSemReq( req, requestingSlv, semEnv); - break; - case createReq: handleCreate( req, requestingSlv, semEnv); - break; - case dissipate: handleDissipate( requestingSlv, semEnv); - break; - case VMSSemantic: VMS_PI__handle_VMSSemReq(req, requestingSlv, semEnv, - (ResumeSlvFnPtr) &resume_slaveVP); - break; - default: - break; - } - - req = VMS_PI__take_next_request_out_of( requestingSlv ); - } //while( req != NULL ) - - } - - -inline void -handleSemReq( VMSReqst *req, SlaveVP *reqSlv, VSsSemEnv *semEnv ) +handleSemReq( PRReqst *req, SlaveVP *reqSlv, VSsSemEnv *semEnv ) { VSsSemReq *semReq; - semReq = VMS_PI__take_sem_reqst_from(req); + semReq = PR_PI__take_sem_reqst_from(req); if( semReq == NULL ) return; switch( semReq->reqType ) //sem handlers are all in other file { - case submit_task: handleSubmitTask( semReq, semEnv); - break; - case end_task: handleEndTask( semReq, semEnv); - break; case send_type_to: handleSendTypeTo( semReq, semEnv); break; case send_from_to: handleSendFromTo( semReq, semEnv); @@ -268,209 +175,6 @@ -//=========================== VMS Request Handlers ============================== -/*SlaveVP dissipate -- this is NOT task-end!, only call this to get rid of - * extra task slaves, and to end explicitly created threads - */ -inline void -handleDissipate( SlaveVP *requestingSlv, VSsSemEnv *semEnv ) - { VSsSemData *semData; - VSsTaskStub *parentTaskStub, *ownTaskStub; - - DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d", - requestingSlv->slaveID) - semData = (VSsSemData *)requestingSlv->semanticData; - - if( semData->slaveType == ExtraTaskSlv ) - { semEnv->numLiveExtraTaskSlvs -= 1; //for detecting shutdown condition - //Has no task assigned, so no parents and no children, so free self - goto FreeSlaveStateAndReturn; - } - - if( semData->slaveType == SlotTaskSlv ) - { //should never call dissipate on a slot assigned slave - VMS_PI__throw_exception( "dissipate a slot-assigned slave", requestingSlv, NULL ); - } - - //if make it to here, then is a thread slave ending - semEnv->numLiveThreadSlvs -= 1; //for detecting shutdown condition - - ownTaskStub = semData->taskStub; - parentTaskStub = ownTaskStub->parentTaskStub; - parentTaskStub->numLiveChildThreads -= 1; //not freed, even if ended - - //if all children ended, then free this task's stub - // else, keep stub around, and last child will free it (below) - if( ownTaskStub->numLiveChildTasks == 0 && - ownTaskStub->numLiveChildThreads == 0 ) - free_task_stub( ownTaskStub ); - else - ownTaskStub->isEnded = TRUE; //for children to see when they end - - //Now, check on parents waiting on child threads to end - if( parentTaskStub->isWaitingForChildThreadsToEnd && - parentTaskStub->numLiveChildThreads == 0 ) - { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE; - if( parentTaskStub->isWaitingForChildTasksToEnd ) - return; //still waiting on tasks (should be impossible) - else //parent free to resume - resume_slaveVP( parentTaskStub->slaveAssignedTo, semEnv ); - } - - //check if this is last child of ended parent (note, not possible to - // have more than one level of ancestor waiting to be freed) - if( parentTaskStub->isEnded ) - { if( parentTaskStub->numLiveChildTasks == 0 && - parentTaskStub->numLiveChildThreads == 0 ) - free_task_stub( parentTaskStub ); //just stub, semData already freed - } - - //Free the semData and requesting slave's base state for all cases - FreeSlaveStateAndReturn: - VMS_PI__free( semData ); - VMS_PI__dissipate_slaveVP( requestingSlv ); - return; - //Note, this is not a location to check for shutdown because doesn't - // say anything about work availability here.. check for shutdown in - // places try to get work for the core (in the assigner) - } - - - -/*Re-use this in the entry-point fn - */ -inline SlaveVP * -VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData, - VSsSemEnv *semEnv, int32 coreToAssignOnto ) - { SlaveVP *newSlv; - VSsSemData *semData; - - //This is running in master, so use internal version - newSlv = VMS_PI__create_slaveVP( fnPtr, initData ); - - //task slaves differ from thread slaves by the settings in the taskStub - //so, don't create task stub here, only create semData, which is same - // for all kinds of slaves - semData = VMS_PI__malloc( sizeof(VSsSemData) ); - semData->highestTransEntered = -1; - semData->lastTransEntered = NULL; - semData->needsTaskAssigned = TRUE; - semData->taskStub = NULL; - - newSlv->semanticData = semData; - - //=================== Assign new processor to a core ===================== - #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE - newSlv->coreAnimatedBy = 0; - - #else - //Assigning slaves to cores is part of SSR code.. - if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES ) - { //out-of-range, so round-robin assignment - newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv; - - if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 ) - semEnv->nextCoreToGetNewSlv = 0; - else - semEnv->nextCoreToGetNewSlv += 1; - } - else //core num in-range, so use it - { newSlv->coreAnimatedBy = coreToAssignOnto; - } - #endif - //======================================================================== - - return newSlv; - } - -VSsTaskStub * -create_thread_task_stub( void *initData ) - { VSsTaskStub *newStub; - - newStub = VMS_PI__malloc( sizeof(VSsTaskStub) ); - newStub->numBlockingProp = 0; - newStub->slaveAssignedTo = NULL; //set later - newStub->taskType = IS_A_THREAD; - newStub->ptrEntries = NULL; - newStub->args = initData; - newStub->numLiveChildTasks = 0; - newStub->numLiveChildThreads = 0; - newStub->parentTaskStub = NULL; - newStub->isWaitingForChildTasksToEnd = FALSE; - newStub->isWaitingForChildThreadsToEnd = FALSE; - newStub->taskID = NULL; - - return newStub; - } - -/*Application invokes this when it explicitly creates a thread via the - * "VSs__create_thread()" command. - * - *The request handlers create new task slaves directly, not via this hdlr. - * - *Make everything in VSs be a task. An explicitly created VP is just a - * suspendable task, and the seedVP is also a suspendable task. - *So, here, create a task Stub. - * Then, see if there are any extra slaveVPs hanging around, and if not, - * call the helper to make a new one. - * Then, put the task stub into the slave's semantic Data. - *When the slave calls dissipate, have to recycle the task stub. - */ -inline void -handleCreate( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) - { VSsSemReq *semReq; - SlaveVP *newSlv; - VSsSemData *semData, *parentSemData; - - semReq = VMS_PI__take_sem_reqst_from( req ); - - semEnv->numLiveThreadSlvs += 1; - - //Deceptive -- must work when creator is a normal task, or seed, - // or another thd.. think have valid sem data and task stub for all - //This hdlr is NOT called when creating the seed slave - parentSemData = (VSsSemData *)semReq->callingSlv->semanticData; - parentSemData->taskStub->numLiveChildThreads += 1; - - //use an idle "extra" slave, if have one - newSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); - if( newSlv != NULL ) //got an idle one, so reset it - { semData = (VSsSemData *)newSlv->semanticData; - semData->highestTransEntered = -1; - semData->lastTransEntered = NULL; - VMS_int__reset_slaveVP_to_TopLvlFn( newSlv, semReq->fnPtr, - semReq->initData ); - } - else //no idle ones, create a new - { newSlv = VSs__create_slave_helper( semReq->fnPtr, semReq->initData, - semEnv, semReq->coreToAssignOnto ); - semData = (VSsSemData *)newSlv->semanticData; - } - - //now, create a new task and assign to the thread - semData->needsTaskAssigned = FALSE; //thread has a permanent task - semData->taskStub = create_thread_task_stub( semReq->initData ); - semData->taskStub->parentTaskStub = parentSemData->taskStub; - semData->slaveType = ThreadSlv; //this hdlr only creates thread slvs - - DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", - requestingSlv->slaveID, newSlv->slaveID) - - #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newd; - newd.from_vp = requestingSlv->slaveID; - newd.from_task = requestingSlv->assignCount; - newd.to_vp = newSlv->slaveID; - newd.to_task = 1; - addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); - #endif - - //For VSs, caller needs ptr to created thread returned to it - requestingSlv->dataRetFromReq = newSlv; - resume_slaveVP(requestingSlv , semEnv ); - resume_slaveVP( newSlv, semEnv ); - } - //=========================== Helper ============================== void @@ -478,6 +182,8 @@ { //both suspended tasks and suspended explicit slaves resumed with this writePrivQ( slave, semEnv->slavesReadyToResumeQ ); + if( semEnv->protoSemEnv->hasWork != TRUE ) + semEnv->protoSemEnv->hasWork = TRUE; #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS /* @@ -487,19 +193,19 @@ */ #endif #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - slave->assignCount++; //Somewhere here! - Unit newu; - newu.vp = slave->slaveID; - newu.task = slave->assignCount; - addToListOfArrays(Unit,newu,semEnv->unitList); + slave->numTimesAssignedToASlot++; //Somewhere here! + Unit newU; + newU.vp = slave->slaveID; + newU.task = slave->numTimesAssignedToASlot; + addToListOfArrays(Unit,newU,semEnv->unitList); - if (slave->assignCount > 1){ - Dependency newd; - newd.from_vp = slave->slaveID; - newd.from_task = slave->assignCount - 1; - newd.to_vp = slave->slaveID; - newd.to_task = slave->assignCount; - addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList); - } + if (slave->numTimesAssignedToASlot > 1) + { Dependency newD; + newD.from_vp = slave->slaveID; + newD.from_task = slave->numTimesAssignedToASlot - 1; + newD.to_vp = slave->slaveID; + newD.to_task = slave->numTimesAssignedToASlot; + addToListOfArrays(Dependency, newD ,semEnv->ctlDependenciesList); + } #endif } diff -r 5bc52d3eae7d -r a60399b62614 VSs_Request_Handlers.c --- a/VSs_Request_Handlers.c Mon Sep 03 03:26:12 2012 -0700 +++ b/VSs_Request_Handlers.c Thu Oct 18 02:44:30 2012 -0700 @@ -7,7 +7,7 @@ #include #include -#include "VMS_impl/VMS.h" +#include "PR_impl/PR.h" #include "Queue_impl/PrivateQueue.h" #include "Hash_impl/PrivateHash.h" #include "VSs.h" @@ -32,7 +32,7 @@ cloneReq( VSsSemReq *semReq ) { VSsSemReq *clonedReq; - clonedReq = VMS_PI__malloc( sizeof(VSsSemReq) ); + clonedReq = PR_PI__malloc( sizeof(VSsSemReq) ); clonedReq->reqType = semReq->reqType; clonedReq->senderSlv = semReq->senderSlv; clonedReq->receiverSlv= semReq->receiverSlv; @@ -71,7 +71,7 @@ create_pointer_entry( ) { VSsPointerEntry *newEntry; - newEntry = VMS_PI__malloc( sizeof(VSsPointerEntry) ); + newEntry = PR_PI__malloc( sizeof(VSsPointerEntry) ); newEntry->hasEnabledNonFinishedWriter = FALSE; newEntry->numEnabledNonDoneReaders = 0; newEntry->waitersQ = makePrivQ(); @@ -85,13 +85,12 @@ inline VSsTaskStub * create_task_stub( VSsTaskType *taskType, void **args ) { void **newArgs; - VSsTaskStub* newStub = VMS_int__malloc( sizeof(VSsTaskStub) + taskType->sizeOfArgs ); + VSsTaskStub* newStub = PR_int__malloc( sizeof(PRMetaTask) + taskType->sizeOfArgs ); newStub->numBlockingProp = taskType->numCtldArgs; - newStub->slaveAssignedTo = NULL; newStub->taskType = taskType; newStub->ptrEntries = - VMS_int__malloc( taskType->numCtldArgs * sizeof(VSsPointerEntry *) ); - newArgs = (void **)( (uint8 *)newStub + sizeof(VSsTaskStub) ); + PR_int__malloc( taskType->numCtldArgs * sizeof(VSsPointerEntry *) ); + newArgs = (void **)( (uint8 *)newStub + sizeof(PRMetaTask) ); newStub->args = newArgs; newStub->numLiveChildTasks = 0; newStub->numLiveChildThreads = 0; @@ -108,17 +107,189 @@ create_task_carrier( VSsTaskStub *taskStub, int32 argNum, int32 rdOrWrite ) { VSsTaskStubCarrier *newCarrier; - newCarrier = VMS_PI__malloc( sizeof(VSsTaskStubCarrier) ); + newCarrier = PR_PI__malloc( sizeof(VSsTaskStubCarrier) ); newCarrier->taskStub = taskStub; newCarrier->argNum = argNum; newCarrier->isReader = rdOrWrite == READER; } + + +//=========================== ============================== + +/*Application invokes this via wrapper library, when it explicitly creates a + * thread with the "VSs__create_thread()" command. + * + *Slave creation is a special form, so PR does handling before calling this. + * It does creation of the new slave, and hands it to this handler. + *This handler is registered with PR during VSs__start(). + * + *So, here, create a task Stub that contains a marker stating this is a thread. + * Then, attach the task stub to the slave's meta Task via a PR command. + * + *When slave dissipates, PR will call the registered recycler for the task stub. + */ +inline void +handleCreateThd( PRReqst *req, SlaveVP *requestingSlv, SlaveVP *newSlv, VSsSemEnv *semEnv ) + { VSsSemReq *semReq; + VSsTaskStub *taskStub, *parentTaskStub; + + semReq = PR_PI__take_sem_reqst_from( req ); + + parentTaskStub = PR_PI__give_lang_meta_task( requestingSlv ); + parentTaskStub->numLiveChildThreads += 1; + + taskStub = create_thread_task_stub(); //only used for wait info + taskStub->parentTaskStub = parentTaskStub; + + //note, semantic data will be initialized by separate, registered + // initializer, at the point it is accessed the first time. + + //================= Assign the new thread to a core =================== + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + newSlv->coreAnimatedBy = 0; + + #else + //Assigning slaves to cores is part of SSR code.. + int32 coreToAssignOnto = semReq->coreToAssignOnto; + if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES ) + { //out-of-range, so round-robin assignment + newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv; + + if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 ) + semEnv->nextCoreToGetNewSlv = 0; + else + semEnv->nextCoreToGetNewSlv += 1; + } + else //core num in-range, so use it + { newSlv->coreAnimatedBy = coreToAssignOnto; + } + #endif + //======================================================================== + + + + DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", + requestingSlv->slaveID, newSlv->slaveID) + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newD; + newD.from_vp = requestingSlv->slaveID; + newD.from_task = requestingSlv->numTimesAssignedToASlot; + newD.to_vp = newSlv->slaveID; + newD.to_task = 1; + addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); + #endif + + //For VSs, caller needs ptr to created thread returned to it + requestingSlv->dataRetFromReq = newSlv; + resume_slaveVP(requestingSlv , semEnv ); + resume_slaveVP( newSlv, semEnv ); + } + +/*Initialize semantic data struct.. this initializer doesn't need any input, + * but some languages may need something from inside the request that was sent + * to create a slave.. in that case, just make initializer do the malloc then + * use the PR_PI__give_sem_data inside the create handler, and fill in the + * semData values there. + */ +void * createInitialSemanticData( ) + { VSsSemData *semData; + + semData = PR_PI__malloc( sizeof(VSsSemData) ); + + semData->highestTransEntered = -1; + semData->lastTransEntered = NULL; + return semData; + } + +/*SlaveVP dissipate -- this is NOT task-end!, only call this to end explicitly + * created threads + */ +inline void +handleDissipate( SlaveVP *requestingSlv, VSsSemEnv *semEnv ) + { VSsSemData *semData; + VSsTaskStub *parentTaskStub, *ownTaskStub; + + DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d", + requestingSlv->slaveID) + + ownTaskStub = PR_PI__give_lang_meta_task( requestingSlv, VSs_MAGIC_NUMBER ); + parentTaskStub = ownTaskStub->parentTaskStub; + parentTaskStub->numLiveChildThreads -= 1; //parent wasn't freed, even if ended + + //if all children ended, then free this task's stub + // else, keep stub around, and last child will free it (below) + if( ownTaskStub->numLiveChildTasks == 0 && + ownTaskStub->numLiveChildThreads == 0 ) + free_task_stub( ownTaskStub ); + else + ownTaskStub->isEnded = TRUE; //for children to see when they end + + //Now, check on parents waiting on child threads to end + if( parentTaskStub->isWaitingForChildThreadsToEnd && + parentTaskStub->numLiveChildThreads == 0 ) + { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE; + if( parentTaskStub->isWaitingForChildTasksToEnd ) + return; //still waiting on tasks (should be impossible) + else //parent free to resume + resume_slaveVP( PR_PI__give_slave_assigned_to(parentTaskStub), semEnv ); + } + + //check if this is last child of ended parent (note, not possible to + // have more than one level of ancestor waiting to be freed) + if( parentTaskStub->isEnded && + parentTaskStub->numLiveChildTasks == 0 && + parentTaskStub->numLiveChildThreads == 0 ) + { free_task_stub( parentTaskStub ); //just stub, semData already freed + } + + FreeSlaveStateAndReturn: + //Used to free the semData and requesting slave's base state, but + // now PR does those things, so nothing more to do.. +//PR handles this: PR_PI__free( semData ); +//PR handles this: PR_PI__dissipate_slaveVP( requestingSlv ); + return; + } + +/*Register this with PR, during VSs start + * + *At some point, may change PR so that it recycles semData, in which case this + * only gets called when a process shuts down.. at that point, PR will call + * dissipate on all the slaves it has in the recycle Q. + */ +void +freeVSsSemData( void *_semData ) + { // + PR_PI__free( _semData ); + } + +void resetVSsSemData( void *_semData ) + { VSsSemData *semData = (VSsSemData *)_semData; + + semData->highestTransEntered = -1; + semData->lastTransEntered = NULL; + } + //========================================================================== // // /*Submit Task - * + * + *PR creates a PRMetaTask and passes it in. This handler adds language- + * specific stuff to it. The language-specific stuff is linked to the + * PRMetaTask, but if the task is suspended for any reason, the lang-specific + * part is moved to the semData of the slave that is animating the task. + *So, while the PRMetaTask is inside the creating language's semantic + * env, waiting to be assigned to a slave for animation, the lang-specific + * task info is accessed from the PRMetaTask. But once the task suspends, + * that lang-specific task info transfers to the slave's semData. All lang + * constructs that want to access it must get it from the semData. + *However, taskEnd still accesses the lang-specific task info from the + * PRMetaTask, whether it suspended or not.. and the task code can access + * data to be used within the application behavior via + * PR__give_task_info( animatingSlave ). + * *Uses a hash table to match the arg-pointers to each other. So, an * argument-pointer is one-to-one with a hash-table entry. * @@ -182,79 +353,45 @@ * the chain. (Means no-longer-used pointers accumulate at end of chain, * decide garbage collection of no-longer-used pointers later) * - * - * ========================== end of task =========================== - * - *At the end of a task, - *The task's controlled arguments are processed one by one. - *Processing an argument means getting the hash of the pointer. Then, - * looking up the hash entry (and putting the entry at the start of the - * chain, if there was a chain). - *With the hash entry: - * - *If the arg is a reader, then decrement the enabled and non-finished - * reader-count in the hash-entry. If the count becomes zero, then take - * the next entry from the Q. It should be a writer, or else there's a - * bug in this algorithm. - *Set the hash-entry to have an enabled non-finished writer. Decrement - * the blocking-propendent-count of the writer's task-stub. If the count - * has reached zero, then put the task-stub into the readyQ. - * - *If the arg is a writer, then clear the enabled non-finished writer flag - * of the hash-entry. Take the next entry from the Q. - *If it is a writer, then turn the flag back on. Decrement the writer's - * blocking-propendent-count in its task-stub. If it becomes zero, then - * put the task-stub into the readyQ. - * - *If it is a reader, then increment the hash-entry's count of enabled - * non-finished readers. Decrement the blocking propendents count of the - * reader's task-stub. If it reaches zero, then put the task-stub into the - * readyQ. - *Then repeat until encounter a writer -- put that writer back into the Q. - * - *That should be it -- that should work. */ -inline void +inline +void * handleSubmitTask( VSsSemReq *semReq, VSsSemEnv *semEnv ) { uint32 key[3]; HashEntry *rawHashEntry; //has char *, but use with uint32 * VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer void **args; - VSsTaskStub *taskStub; + VSsTaskStub *taskStub, *parentTaskStub; VSsTaskType *taskType; VSsTaskStubCarrier *taskCarrier; HashTable * argPtrHashTbl = semEnv->argPtrHashTbl; - //suspending a task always makes the slave into an extra slot slave, - // because it ends up in the resumeQ, even when resumes immediately. - //Eventually task_end will put the slave into the freeExtraTaskSlvQ - replaceWithNewSlotSlvIfNeeded( semReq->callingSlv, semEnv ); /* ========================== creation ========================== - * - *At creation, make a task-stub. Set the count of blocking propendents + *Make a task-stub. Set the count of blocking propendents * to the number of controlled arguments (a task can have * arguments that are not controlled by the language, like simple integer * inputs from the sequential portion. Note that all controlled arguments * are pointers, and marked as controlled in the application code). */ args = semReq->args; - taskType = semReq->taskType; + taskType = semReq->taskType; //this is VSs task type struct taskStub = create_task_stub( taskType, args );//copies arg ptrs + taskStub->numBlockingProp = taskType->numCtldArgs; - taskStub->taskID = semReq->taskID; //may be NULL - - VSsSemData* - parentSemData = (VSsSemData*) semReq->callingSlv->semanticData; - taskStub->parentTaskStub = (void*) parentSemData->taskStub; - parentSemData->taskStub->numLiveChildTasks += 1; + //PR does this (metaTask contains taskID): taskStub->taskID = semReq->taskID; + + parentTaskStub = (VSsTaskStub *)PR_PI__give_lang_meta_task(semReq->callingSlv, VSs_MAGIC_NUMBER); + taskStub->parentTaskStub = parentTaskStub; + parentTaskStub->numLiveChildTasks += 1; //DEBUG__printf3(dbgRqstHdlr,"Submit req from slaveID: %d, from task: %d, for task: %d", semReq->callingSlv->slaveID, parentSemData->taskStub->taskID[1], taskStub->taskID[1]) DEBUG__printf2(dbgRqstHdlr,"Submit req from slaveID: %d, for task: %d", semReq->callingSlv->slaveID, taskStub->taskID[1]) - /*The controlled arguments are then processed one by one. + /*=============== Process args ================= + *The controlled arguments are processed one by one. *Processing an argument means getting the hash of the pointer. Then, * looking up the hash entry. (If none, create one). */ @@ -295,6 +432,8 @@ taskStub->numBlockingProp -= 1; if( taskStub->numBlockingProp == 0 ) { writePrivQ( taskStub, semEnv->taskReadyQ ); + if( semEnv->protoSemEnv->hasWork != TRUE ) + semEnv->protoSemEnv->hasWork = TRUE; } ptrEntry->numEnabledNonDoneReaders += 1; } @@ -318,6 +457,8 @@ taskStub->numBlockingProp -= 1; if( taskStub->numBlockingProp == 0 ) { writePrivQ( taskStub, semEnv->taskReadyQ ); + if( semEnv->protoSemEnv->hasWork != TRUE ) + semEnv->protoSemEnv->hasWork = TRUE; } ptrEntry->hasEnabledNonFinishedWriter = TRUE; } @@ -329,7 +470,7 @@ } } //for argNum - + //resume the parent, creator resume_slaveVP( semReq->callingSlv, semEnv ); return; @@ -372,36 +513,38 @@ * and no readers and no writers.. */ inline void -handleEndTask( VSsSemReq *semReq, VSsSemEnv *semEnv ) +handleEndTask( void *langMetaTask, VSsSemReq *semReq, VSsSemEnv *semEnv ) { VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer void **args; VSsSemData *endingSlvSemData; - VSsTaskStub *endingTaskStub, *waitingTaskStub, *parent; + VSsTaskStub *endingTaskStub, *waitingTaskStub, *parentStub; VSsTaskType *endingTaskType; VSsTaskStubCarrier *waitingTaskCarrier; VSsPointerEntry **ptrEntries; - endingSlvSemData = (VSsSemData *)semReq->callingSlv->semanticData; - endingTaskStub = endingSlvSemData->taskStub; +// endingTaskStub = (VSsTaskStub *)PR_PI__give_lang_spec_task_info( semReq->callingSlv ); + + endingTaskStub = (VSsTaskStub *)langMetaTask; args = endingTaskStub->args; endingTaskType = endingTaskStub->taskType; ptrEntries = endingTaskStub->ptrEntries; //saved in stub when create DEBUG__printf2(dbgRqstHdlr,"EndTask req from slaveID: %d, task: %d",semReq->callingSlv->slaveID, endingTaskStub->taskID[1]) - //Check if parent was waiting on this task - parent = (VSsTaskStub *) endingTaskStub->parentTaskStub; - parent->numLiveChildTasks -= 1; - if( parent->isWaitingForChildTasksToEnd && parent->numLiveChildTasks == 0) + //"wait" functionality: Check if parent was waiting on this task + parentStub = endingTaskStub->parentTaskStub; + parentStub->numLiveChildTasks -= 1; + if( parentStub->isWaitingForChildTasksToEnd && + parentStub->numLiveChildTasks == 0) { - parent->isWaitingForChildTasksToEnd = FALSE; - resume_slaveVP( parent->slaveAssignedTo, semEnv ); + parentStub->isWaitingForChildTasksToEnd = FALSE; + resume_slaveVP( PR_PI__give_slave_assigned_to(parentStub), semEnv ); } //Check if parent ended, and this was last descendent, then free it - if( parent->isEnded && parent->numLiveChildTasks == 0 ) - { VMS_PI__free( parent ); + if( parentStub->isEnded && parentStub->numLiveChildTasks == 0 ) + { free_task_stub( parentStub ); } @@ -411,32 +554,16 @@ */ int32 argNum; for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ ) - { - /* commented out 'cause remembering entry ptr when create stub - key[0] = 2; //says are 2 32b values in key - *( (uint64*)&key[1] ) = args[argNum]; //write 64b ptr into two 32b - - /*If the hash entry was chained, put it at the - * start of the chain. (Means no-longer-used pointers accumulate - * at end of chain, decide garbage collection later) - */ - /*NOTE: don't do hash lookups here, instead, have a pointer to the - * hash entry inside task-stub, put there during task creation. - rawHashEntry = getEntryFromTable32( key, ptrHashTbl ); - ptrEntry = (VSsPointerEntry *)rawHashEntry->content; - if( ptrEntry == NULL ) - VMS_App__throw_exception("hash entry NULL", NULL, NULL); - */ - + { ptrEntry = ptrEntries[argNum]; - /*check if the ending task was reader of this arg*/ + //check if the ending task was reader of this arg if( endingTaskType->argTypes[argNum] == READER ) - { /*then decrement the enabled and non-finished reader-count in - * the hash-entry. */ + { //then decrement the enabled and non-finished reader-count in + // the hash-entry. ptrEntry->numEnabledNonDoneReaders -= 1; - /*If the count becomes zero, then take the next entry from the Q. - *It should be a writer, or else there's a bug in this algorithm.*/ + //If the count becomes zero, then take the next entry from the Q. + //It should be a writer, or else there's a bug in this algorithm. if( ptrEntry->numEnabledNonDoneReaders == 0 ) { waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); if( waitingTaskCarrier == NULL ) @@ -444,27 +571,29 @@ continue; //next iter of loop } if( waitingTaskCarrier->isReader ) - VMS_App__throw_exception("READER waiting", NULL, NULL); + PR_App__throw_exception("READER waiting", NULL, NULL); waitingTaskStub = waitingTaskCarrier->taskStub; - /*Set the hash-entry to have an enabled non-finished writer.*/ + //Set the hash-entry to have an enabled non-finished writer. ptrEntry->hasEnabledNonFinishedWriter = TRUE; - /* Decrement the blocking-propendent-count of the writer's - * task-stub. If the count has reached zero, then put the - * task-stub into the readyQ.*/ + // Decrement the blocking-propendent-count of the writer's + // task-stub. If the count has reached zero, then put the + // task-stub into the readyQ. waitingTaskStub->numBlockingProp -= 1; if( waitingTaskStub->numBlockingProp == 0 ) { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); + if( semEnv->protoSemEnv->hasWork != TRUE ) + semEnv->protoSemEnv->hasWork = TRUE; } } } - else /*the ending task is a writer of this arg*/ - { /*clear the enabled non-finished writer flag of the hash-entry.*/ + else //the ending task is a writer of this arg + { //clear the enabled non-finished writer flag of the hash-entry. ptrEntry->hasEnabledNonFinishedWriter = FALSE; - /*Take the next waiter from the hash-entry's Q.*/ + //Take the next waiter from the hash-entry's Q. waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); if( waitingTaskCarrier == NULL ) { //TODO: looks safe to delete ptr entry at this point @@ -472,36 +601,40 @@ } waitingTaskStub = waitingTaskCarrier->taskStub; - /*If task is a writer of this hash-entry's pointer*/ + //If task is a writer of this hash-entry's pointer if( !waitingTaskCarrier->isReader ) - { /* then turn the flag back on.*/ + { // then turn the flag back on. ptrEntry->hasEnabledNonFinishedWriter = TRUE; - /*Decrement the writer's blocking-propendent-count in task-stub - * If it becomes zero, then put the task-stub into the readyQ.*/ + //Decrement the writer's blocking-propendent-count in task-stub + // If it becomes zero, then put the task-stub into the readyQ. waitingTaskStub->numBlockingProp -= 1; if( waitingTaskStub->numBlockingProp == 0 ) { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); + if( semEnv->protoSemEnv->hasWork != TRUE ) + semEnv->protoSemEnv->hasWork = TRUE; } } else - { /*Waiting task is a reader, so do a loop, of all waiting readers - * until encounter a writer or waitersQ is empty*/ - while( TRUE ) /*The checks guarantee have a waiting reader*/ - { /*Increment the hash-entry's count of enabled non-finished - * readers.*/ + { //Waiting task is a reader, so do a loop, of all waiting readers + // until encounter a writer or waitersQ is empty + while( TRUE ) //The checks guarantee have a waiting reader + { //Increment the hash-entry's count of enabled non-finished + // readers. ptrEntry->numEnabledNonDoneReaders += 1; - /*Decrement the blocking propendents count of the reader's - * task-stub. If it reaches zero, then put the task-stub - * into the readyQ.*/ + //Decrement the blocking propendents count of the reader's + // task-stub. If it reaches zero, then put the task-stub + // into the readyQ. waitingTaskStub->numBlockingProp -= 1; if( waitingTaskStub->numBlockingProp == 0 ) { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); + if( semEnv->protoSemEnv->hasWork != TRUE ) + semEnv->protoSemEnv->hasWork = TRUE; } - /*Get next waiting task*/ + //Get next waiting task waitingTaskCarrier = peekPrivQ( ptrEntry->waitersQ ); - if( waitingTaskCarrier == NULL ) break; - if( !waitingTaskCarrier->isReader ) break; + if( waitingTaskCarrier == NULL ) break; //no more waiting readers + if( !waitingTaskCarrier->isReader ) break; //no more waiting readers waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); waitingTaskStub = waitingTaskCarrier->taskStub; }//while waiter is a reader @@ -510,32 +643,23 @@ }//for argnum in ending task - //done ending the task, now free the stub + args copy - // if still has live children, then keep stub around + //done ending the task, if still has live children, then keep stub around + // else, free the stub and args copy if( endingTaskStub->numLiveChildTasks == 0 && endingTaskStub->numLiveChildThreads == 0 ) { free_task_stub( endingTaskStub ); } - - endingSlvSemData->needsTaskAssigned = TRUE; - - //Check if the slave is an extra task slave, and put into free Q - if( endingSlvSemData->slaveType == ExtraTaskSlv ) - { writePrivQ( semReq->callingSlv, semEnv->freeExtraTaskSlvQ ); - } - - //otherwise, it's a slot slave, so it will get used from matrix - // so, do nothing with it, just return return; } + inline void free_task_stub( VSsTaskStub *stubToFree ) { if(stubToFree->ptrEntries != NULL ) //a thread stub has NULL entry - { VMS_PI__free( stubToFree->ptrEntries ); + { PR_PI__free( stubToFree->ptrEntries ); } - VMS_PI__free( stubToFree ); + PR_PI__free( stubToFree ); } //========================== Task Comm handlers =========================== @@ -567,14 +691,10 @@ DEBUG__printf2(dbgRqstHdlr,"SendType req from sender slaveID: %d, recTask: %d", senderSlv->slaveID, receiverID[1]) - //suspending a task always makes the slave into an extra slot slave, - // because it ends up in the resumeQ, even when resumes immediately. - //Eventually task_end will put the slave into the freeExtraTaskSlvQ - replaceWithNewSlotSlvIfNeeded( senderSlv, semEnv ); receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); - key = VMS_PI__malloc( keySz ); + key = PR_PI__malloc( keySz ); key[0] = receiverIDNumInt + 1; //loc 0 is num int32 in key memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); key[ 1 + receiverIDNumInt ] = semReq->msgType; @@ -604,13 +724,13 @@ else { #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newd; - newd.from_vp = senderID->slaveID; - newd.from_task = senderID->assignCount; - newd.to_vp = receiverID->slaveID; - newd.to_task = receiverID->assignCount +1; - //(newd,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); + Dependency newD; + newD.from_vp = senderID->slaveID; + newD.from_task = senderID->numTimesAssignedToASlot; + newD.to_vp = receiverID->slaveID; + newD.to_task = receiverID->numTimesAssignedToASlot +1; + //(newD,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newD,semEnv->dynDependenciesList); int32 groupId = semReq->msgType; if(semEnv->ntonGroupsInfo->numInArray <= groupId){ makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); @@ -620,10 +740,10 @@ } Unit u; u.vp = senderID->slaveID; - u.task = senderID->assignCount; + u.task = senderID->numTimesAssignedToASlot; addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); u.vp = receiverID->slaveID; - u.task = receiverID->assignCount +1; + u.task = receiverID->numTimesAssignedToASlot +1; addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); #endif @@ -633,7 +753,7 @@ //waiting request is a receive_type_to, so it pairs to this send //First, remove the waiting receive request from the entry entry->content = waitingReq->nextReqInHashEntry; - VMS_PI__free( waitingReq ); //Don't use contents -- so free it + PR_PI__free( waitingReq ); //Don't use contents -- so free it if( entry->content == NULL ) { //TODO: mod hash table to double-link, so can delete entry from @@ -654,7 +774,12 @@ } -/*Looks like can make single handler for both sends.. +/*If Send or Receive are called within a task, it causes the task to suspend, + * which converts the slave animating it to a free slave and suspends that slave. + *Which means that send and receive operate upon slaves, no matter whether they + * were called from within a task or a slave. + * + *Looks like can make single handler for both kinds of send.. */ //TODO: combine both send handlers into single handler inline void @@ -673,15 +798,11 @@ senderID = semReq->senderID; senderSlv = semReq->senderSlv; - //suspending a task always makes the slave into an extra slot slave, - // because it ends up in the resumeQ, even when resumes immediately. - //Eventually task_end will put the slave into the freeExtraTaskSlvQ - replaceWithNewSlotSlvIfNeeded( senderSlv, semEnv ); receiverIDNumInt = receiverID[0] + 1; //include the count in the key senderIDNumInt = senderID[0] + 1; keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); - key = VMS_PI__malloc( keySz ); + key = PR_PI__malloc( keySz ); key[0] = receiverIDNumInt + senderIDNumInt; memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); @@ -700,13 +821,13 @@ else { //waiting request is a receive, so it completes pair with this send #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newd; - newd.from_vp = sendPr->slaveID; - newd.from_task = sendPr->assignCount; - newd.to_vp = receivePr->slaveID; - newd.to_task = receivePr->assignCount +1; - //addToListOfArraysDependency(newd,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); + Dependency newD; + newD.from_vp = sendPr->slaveID; + newD.from_task = sendPr->numTimesAssignedToASlot; + newD.to_vp = receivePr->slaveID; + newD.to_task = receivePr->numTimesAssignedToASlot +1; + //addToListOfArraysDependency(newD,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); #endif //set receiver slave, from the waiting request @@ -714,7 +835,7 @@ //First, remove the waiting receive request from the entry entry->content = waitingReq->nextReqInHashEntry; - VMS_PI__free( waitingReq ); //Don't use contents -- so free it + PR_PI__free( waitingReq ); //Don't use contents -- so free it //can only be one waiting req for "from-to" semantics if( entry->content != NULL ) @@ -755,15 +876,11 @@ receiverID = semReq->receiverID; //For "send", know both send & recv procrs receiverSlv = semReq->receiverSlv; - //suspending a task always makes the slave into an extra slot slave, - // because it ends up in the resumeQ, even when resumes immediately. - //Eventually task_end will put the slave into the freeExtraTaskSlvQ - replaceWithNewSlotSlvIfNeeded( receiverSlv, semEnv ); //key is the receiverID plus the type -- have to copy them into key receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); - key = VMS_PI__malloc( keySz ); + key = PR_PI__malloc( keySz ); key[0] = receiverIDNumInt + 1; //loc 0 is num int32s in key memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); key[ 1 + receiverIDNumInt ] = semReq->msgType; @@ -793,16 +910,16 @@ receiverSlv->dataRetFromReq = waitingReq->msg; //bring both processors back from suspend - VMS_PI__free( waitingReq ); + PR_PI__free( waitingReq ); #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newd; - newd.from_vp = sendPr->slaveID; - newd.from_task = sendPr->assignCount; - newd.to_vp = receivePr->slaveID; - newd.to_task = receivePr->assignCount +1; - //addToListOfArraysDependency(newd,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); + Dependency newD; + newD.from_vp = sendPr->slaveID; + newD.from_task = sendPr->numTimesAssignedToASlot; + newD.to_vp = receivePr->slaveID; + newD.to_task = receivePr->numTimesAssignedToASlot +1; + //addToListOfArraysDependency(newD,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newD,semEnv->dynDependenciesList); int32 groupId = semReq->msgType; if(semEnv->ntonGroupsInfo->numInArray <= groupId){ makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); @@ -812,10 +929,10 @@ } Unit u; u.vp = sendPr->slaveID; - u.task = sendPr->assignCount; + u.task = sendPr->numTimesAssignedToASlot; addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); u.vp = receivePr->slaveID; - u.task = receivePr->assignCount +1; + u.task = receivePr->numTimesAssignedToASlot +1; addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); #endif @@ -845,15 +962,10 @@ senderID = semReq->senderID; receiverSlv = semReq->receiverSlv; - //suspending a task always makes the slave into an extra slot slave, - // because it ends up in the resumeQ, even when resumes immediately. - //Eventually task_end will put the slave into the freeExtraTaskSlvQ - replaceWithNewSlotSlvIfNeeded( receiverSlv, semEnv ); - receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself senderIDNumInt = senderID[0] + 1; keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); - key = VMS_PI__malloc( keySz ); + key = PR_PI__malloc( keySz ); key[0] = receiverIDNumInt + senderIDNumInt; //loc 0 is num int32s in key memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32)); @@ -869,13 +981,13 @@ if( waitingReq->reqType == send_from_to ) { //waiting request is a send, so pair it with this receive #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC - Dependency newd; - newd.from_vp = sendPr->slaveID; - newd.from_task = sendPr->assignCount; - newd.to_vp = receivePr->slaveID; - newd.to_task = receivePr->assignCount +1; - //addToListOfArraysDependency(newd,semEnv->commDependenciesList); - addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); + Dependency newD; + newD.from_vp = sendPr->slaveID; + newD.from_task = sendPr->numTimesAssignedToASlot; + newD.to_vp = receivePr->slaveID; + newD.to_task = receivePr->numTimesAssignedToASlot +1; + //addToListOfArraysDependency(newD,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newD,semEnv->commDependenciesList); #endif //have receiver slave, now set sender slave @@ -891,7 +1003,7 @@ receiverSlv->dataRetFromReq = waitingReq->msg; //bring both processors back from suspend - VMS_PI__free( waitingReq ); + PR_PI__free( waitingReq ); resume_slaveVP( senderSlv, semEnv ); resume_slaveVP( receiverSlv, semEnv ); @@ -901,66 +1013,26 @@ printf("\nLang Impl Error: Should never be two waiting receives!\n"); } -//========================================================================== -inline void -replaceWithNewSlotSlvIfNeeded( SlaveVP *requestingSlv, VSsSemEnv *semEnv ) - { SlaveVP *newSlotSlv; - VSsSemData *semData, *reqSemData; - reqSemData = (VSsSemData *)requestingSlv->semanticData; - if( reqSemData->slaveType != SlotTaskSlv ) - return; //already replaced, so just return - - //get a new slave to be the slot slave - newSlotSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); - if( newSlotSlv == NULL ) - { newSlotSlv = VSs__create_slave_helper( &idle_fn, NULL, semEnv, 0); - //just made a new extra task slave, so count it - semEnv->numLiveExtraTaskSlvs += 1; - } - - //set slave values to make it the slot slave - semData = newSlotSlv->semanticData; - semData->taskStub = NULL; - semData->slaveType = SlotTaskSlv; - semData->needsTaskAssigned = TRUE; - - //a slot slave is pinned to a particular slot on a particular core - newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo; - newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy; - - //put it into the slot slave matrix - int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; - int32 coreNum = requestingSlv->coreAnimatedBy; - semEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv; - - //Fix up requester, to be an extra slave now (but not a free one) - // because it's not free, doesn't go into freeExtraTaskSlvQ - semData = requestingSlv->semanticData; - semData->slaveType = ExtraTaskSlv; - } - +/*Waits for all tasks that are direct children to end, then resumes calling + * task or thread + */ inline void handleTaskwait( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv) - { VSsTaskStub* requestingTaskStub; - VSsSemData* semData; - DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d", + { VSsTaskStub* taskStub; + + DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d", requestingSlv->slaveID) - semData = (VSsSemData *)semReq->callingSlv->semanticData; - requestingTaskStub = semData->taskStub; + taskStub = (VSsTaskStub *)PR_PI__give_lang_meta_task( requestingSlv, VSs_MAGIC_NUMBER); - if( semData->taskStub->numLiveChildTasks == 0 ) + if( taskStub->numLiveChildTasks == 0 ) { //nobody to wait for, resume resume_slaveVP( requestingSlv, semEnv ); } - else //have to wait, replace requester with new slot slv & mark waiting - { - if(semData->slaveType == SlotTaskSlv){ - replaceWithNewSlotSlvIfNeeded( requestingSlv, semEnv ); - } - - requestingTaskStub->isWaitingForChildTasksToEnd = TRUE; + else //have to wait, mark waiting + { + taskStub->isWaitingForChildTasksToEnd = TRUE; } } @@ -974,7 +1046,7 @@ DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveID) - ptr = VMS_PI__malloc( semReq->sizeToMalloc ); + ptr = PR_PI__malloc( semReq->sizeToMalloc ); requestingSlv->dataRetFromReq = ptr; resume_slaveVP( requestingSlv, semEnv ); } @@ -985,7 +1057,7 @@ handleFree( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) { DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveID) - VMS_PI__free( semReq->ptrToFree ); + PR_PI__free( semReq->ptrToFree ); resume_slaveVP( requestingSlv, semEnv ); } @@ -1034,8 +1106,8 @@ DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveID) if( *(semReq->singletonPtrAddr) == NULL ) - { singleton = VMS_PI__malloc( sizeof(VSsSingleton) ); - singleton->waitQ = makeVMSQ(); + { singleton = PR_PI__malloc( sizeof(VSsSingleton) ); + singleton->waitQ = makePRQ(); singleton->endInstrAddr = 0x0; singleton->hasBeenStarted = FALSE; singleton->hasFinished = FALSE; @@ -1133,13 +1205,13 @@ //check ordering of entering transactions is correct semData = requestingSlv->semanticData; if( semData->highestTransEntered > semReq->transID ) - { //throw VMS exception, which shuts down VMS. - VMS_PI__throw_exception( "transID smaller than prev", requestingSlv, NULL); + { //throw PR exception, which shuts down PR. + PR_PI__throw_exception( "transID smaller than prev", requestingSlv, NULL); } //add this trans ID to the list of transactions entered -- check when // end a transaction semData->highestTransEntered = semReq->transID; - nextTransElem = VMS_PI__malloc( sizeof(TransListElem) ); + nextTransElem = PR_PI__malloc( sizeof(TransListElem) ); nextTransElem->transID = semReq->transID; nextTransElem->nextTrans = semData->lastTransEntered; semData->lastTransEntered = nextTransElem; @@ -1189,7 +1261,7 @@ //make sure transaction ended in same VP as started it. if( transStruc->VPCurrentlyExecuting != requestingSlv ) { - VMS_PI__throw_exception( "trans ended in diff VP", requestingSlv, NULL ); + PR_PI__throw_exception( "trans ended in diff VP", requestingSlv, NULL ); } //make sure nesting is correct -- last ID entered should == this ID @@ -1197,7 +1269,7 @@ lastTrans = semData->lastTransEntered; if( lastTrans->transID != semReq->transID ) { - VMS_PI__throw_exception( "trans incorrectly nested", requestingSlv, NULL ); + PR_PI__throw_exception( "trans incorrectly nested", requestingSlv, NULL ); } semData->lastTransEntered = semData->lastTransEntered->nextTrans; diff -r 5bc52d3eae7d -r a60399b62614 VSs_Request_Handlers.h --- a/VSs_Request_Handlers.h Mon Sep 03 03:26:12 2012 -0700 +++ b/VSs_Request_Handlers.h Thu Oct 18 02:44:30 2012 -0700 @@ -53,9 +53,7 @@ handleEndDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); inline void -free_task_stub( VSsTaskStub *stubToFree ); -inline void -replaceWithNewSlotSlvIfNeeded( SlaveVP *requestingSlv, VSsSemEnv *semEnv ); +free_task_stub( PRMetaTask *stubToFree ); #endif /* _VSs_REQ_H */ diff -r 5bc52d3eae7d -r a60399b62614 VSs_singleton_asm.s --- a/VSs_singleton_asm.s Mon Sep 03 03:26:12 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ - -//Assembly code takes the return addr off the stack and saves -// into the singleton. The first field in the singleton is the -// "endInstrAddr" field, and the return addr is at 0x4(%ebp) -.globl asm_save_ret_to_singleton -asm_save_ret_to_singleton: - movq 0x8(%rbp), %rax #get ret address, ebp is the same as in the calling function - movq %rax, (%rdi) #write ret addr to endInstrAddr field - ret - - -//Assembly code changes the return addr on the stack to the one -// saved into the singleton by the end-singleton-fn -//The stack's return addr is at 0x4(%%ebp) -.globl asm_write_ret_from_singleton -asm_write_ret_from_singleton: - movq (%rdi), %rax #get endInstrAddr field - movq %rax, 0x8(%rbp) #write return addr to the stack of the caller - ret - -