# HG changeset patch # User Sean Halle # Date 1343894594 25200 # Node ID eb3d77ca9f594ca9dab1e9a73f8cd80d15e34953 # Parent 3999b8429dddc44c930b01c497081d22839f8c9e Code complete -- not debuggedd yet diff -r 3999b8429ddd -r eb3d77ca9f59 VSs.c --- a/VSs.c Wed Aug 01 03:16:27 2012 -0700 +++ b/VSs.c Thu Aug 02 01:03:14 2012 -0700 @@ -76,7 +76,7 @@ { VSsSemEnv *semEnv; SlaveVP *seedSlv; VSsSemData *semData; - VSsTaskStub *explPrTaskStub; + VSsTaskStub *threadTaskStub, *parentTaskStub; VSs__init(); //normal multi-thd @@ -87,14 +87,21 @@ seedSlv = VSs__create_slave_helper( fnPtr, initData, semEnv, semEnv->nextCoreToGetNewSlv++ ); - //seed slave is an explicit processor, so make one of the special - // task stubs for explicit processors, and attach it to the slave - explPrTaskStub = create_expl_proc_task_stub( initData ); + //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->parentTasksStub = parentTaskStub; semData = (VSsSemData *)seedSlv->semanticData; - //seedVP already has a permanent task + //seedVP is a thread, so has a permanent task semData->needsTaskAssigned = FALSE; - semData->taskStub = explPrTaskStub; + semData->taskStub = threadTaskStub; resume_slaveVP( seedSlv, semEnv ); //returns right away, just queues Slv @@ -239,7 +246,8 @@ semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSQ(); } - semanticEnv->numAdditionalSlvs = 0; //must be last + semanticEnv->numLiveExtraTaskSlvs = 0; //must be last + semanticEnv->numLiveThreadSlvs = 1; //must be last, count the seed #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC semanticEnv->unitList = makeListOfArrays(sizeof(Unit),128); @@ -415,18 +423,24 @@ * this. * *This must update the count of active sub-tasks (sub-threads) of parents, - * and the semantic data and task stub must stay + * and the semantic data and task stub must stay. */ void VSs__end_thread( SlaveVP *thdToEnd ) - { + { VSsSemData *semData; + //check whether all sub-tasks have ended.. if not, don't free the // semantic data nor task stub of this thread. - check_sub_tasks(); + semData = (VSsSemData *)thdToEnd->semanticData; + if( semData->taskStub->numLiveChildTasks != 0 ) + { + fix_me(); + } //Update the count of live sub-tasks in parent. If parent was a // thread and has already ended, then if this was the last sub-task, // free the semantic data and task stub of the parent. + VMS_WL__send_dissipate_req( thdToEnd ); } diff -r 3999b8429ddd -r eb3d77ca9f59 VSs.h --- a/VSs.h Wed Aug 01 03:16:27 2012 -0700 +++ b/VSs.h Thu Aug 02 01:03:14 2012 -0700 @@ -41,6 +41,10 @@ #define READER 1 /*Trick -- READER same as IN*/ #define WRITER 2 /*Trick -- WRITER same as OUT and INOUT*/ +#define IS_A_THREAD NULL +#define IS_ENDED NULL +#define SEED_SLV NULL + typedef struct { VSsTaskFnPtr fn; @@ -69,22 +73,15 @@ int32 numBlockingProp; SlaveVP *slaveAssignedTo; VSsPointerEntry **ptrEntries; - void* parent; - bool32 parentIsTask; - int32 numChildTasks; - bool32 isWaiting; + void* parentTasksStub; + int32 numLiveChildTasks; + int32 numLiveChildThreads; + bool32 isWaitingForChildTasksToEnd; + bool32 isWaitingForChildThreadsToEnd; + bool32 isEnded; } VSsTaskStub; -typedef struct - { - void* parent; - bool32 parentIsTask; - int32 numChildTasks; - bool32 isWaiting; - SlaveVP *slaveAssignedTo; - } -VSsThreadInfo; typedef struct { @@ -186,12 +183,13 @@ typedef struct { PrivQueueStruc **slavesReadyToResumeQ; //Shared (slaves not pinned) - PrivQueueStruc **extraTaskSlvQ; //Shared + PrivQueueStruc **freeExtraTaskSlvQ; //Shared PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) SlaveVP *currTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; HashTable *argPtrHashTbl; HashTable *commHashTbl; - int32 numAdditionalSlvs; + int32 numLiveExtraTaskSlvs; + int32 numLiveThreadSlvs; int32 nextCoreToGetNewSlv; int32 primitiveStartTime; @@ -230,7 +228,11 @@ }; //TransListElem - +enum VSsSlvType + { extraTaskSlv = 1, + slotTaskSlv, + threadSlv + }; typedef struct { @@ -238,7 +240,7 @@ TransListElem *lastTransEntered; bool32 needsTaskAssigned; VSsTaskStub *taskStub; - VSsThreadInfo *threadInfo; + VSsSlvType slaveType; } VSsSemData; @@ -357,7 +359,7 @@ VSsSemEnv *semEnv, int32 coreToAssignOnto ); VSsTaskStub * -create_expl_proc_task_stub( void *initData ); +create_thread_task_stub( void *initData ); SlaveVP * diff -r 3999b8429ddd -r eb3d77ca9f59 VSs_PluginFns.c --- a/VSs_PluginFns.c Wed Aug 01 03:16:27 2012 -0700 +++ b/VSs_PluginFns.c Thu Aug 02 01:03:14 2012 -0700 @@ -50,38 +50,29 @@ */ SlaveVP * VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot ) - { SlaveVP *returnSlv; - VSsSemEnv *semEnv; - VSsSemData *semData; - int32 coreNum, slotNum; - + { SlaveVP *returnSlv; + VSsSemEnv *semEnv; + VSsSemData *semData; + int32 coreNum, slotNum; + VSsTaskStub *newTaskStub; + SlaveVP *extraSlv; + coreNum = slot->coreSlotIsOn; slotNum = slot->slotIdx; semEnv = (VSsSemEnv *)_semEnv; + //Speculatively set the return slave to the current taskSlave + //TODO: false sharing ? Always read.. + returnSlv = semEnv->currTaskSlvs[coreNum][slotNum]; - //Speculatively set the return slave to the current taskSlave - //TODO: false sharing ? Always read.. - returnSlv = semEnv->currTaskSlvs[coreNum][slotNum]; - -/* request handlers do this now.. move it to there.. - if( returnSlv == NULL ) - { //make a new slave to animate - //This happens for the first task on the core and when all available - //slaves are blocked by constructs like send, or mutex, and so on. - returnSlv = VSs__create_slave_helper( NULL, NULL, semEnv, coreNum ); - } - */ 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) - VSsTaskStub *newTaskStub; - SlaveVP *extraSlv; + // (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 + { //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; @@ -92,7 +83,7 @@ goto ReturnTheSlv; } else - { //no task, so try to get a ready to resume slave + { //no task, so try to get a ready to resume slave returnSlv = readPrivQ( semEnv->slavesReadyToResumeQ ); if( returnSlv != NULL ) //Yes, have a slave, so return it. { returnSlv->coreAnimatedBy = coreNum; @@ -100,8 +91,8 @@ semEnv->coreIsDone[coreNum] = FALSE; //don't just write always goto ReturnTheSlv; } - //If get here, then no task, so check if have extra free slaves - extraSlv = readPrivQ( semEnv->extraTaskSlvQ ); + //If get here, then no task, so check if have extra free slaves + extraSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); if( extraSlv != NULL ) { //means have two slaves need tasks -- redundant, kill one handleDissipate( extraSlv, semEnv ); @@ -111,9 +102,10 @@ } else { //candidate for shutdown.. if all extras dissipated, and no tasks - // and no ready to resume slaves, then then no way to generate + // and no ready to resume slaves, then no way to generate // more tasks.. - if( semEnv->numAdditionalSlvs == 0 ) //means none suspended + 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; @@ -272,21 +264,67 @@ //=========================== VMS Request Handlers ============================== -/*SlaveVP dissipate (NOT task-end!) +/*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) - - semEnv->numAdditionalSlvs -= 1; + 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__throw_exception(); + } + + //if make it to here, then is a thread slave + semEnv->numLiveThreadSlvs -= 1; //for detecting shutdown condition + ownTaskStub = semData->taskStub; + parentTaskStub = ownTaskStub->parentTasksStub; - //free any semantic data allocated to the virt procr - VMS_PI__free( requestingSlv->semanticData ); + //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, call VMS to free_all AppVP state -- stack and so on + //check if this is last child of ended parent + parentTaskStub->numLiveChildThreads -= 1; //parent stub cannot be NULL + if( parentTaskStub->isEnded ) + { if( parentTaskStub->numLiveChildTasks == 0 && + parentTaskStub->numLiveChildThreads == 0 ) + free_task_stub( parentTaskStub ); //just stub, semData already freed + } + + //Now, check on waiting parents -- could be waiting on just tasks or + // just threads or both. Handle each case. + if( parentTaskStub->isWaitingForChildThreadsToEnd ) + { if( parentTaskStub->numLiveChildThreads == 0 ) + { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE; + if( parentTaskStub->isWaitingForChildTasksToEnd ) + return; //still waiting on tasks, nothing to do + else //parent free to resume + resume_slaveVP( parentTaskStub->slaveAssignedTo, semEnv ); + } + } + + //Free the semData and requesting slave's base state for all cases + FreeSlaveStateAndReturn: + VMS_PI__free( semData ); VMS_PI__dissipate_slaveVP( requestingSlv ); + return; } /*Re-use this in the entry-point fn @@ -300,20 +338,14 @@ //This is running in master, so use internal version newSlv = VMS_PI__create_slaveVP( fnPtr, initData ); - semEnv->numAdditionalSlvs += 1; - + //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->threadInfo = VMS_PI__malloc( sizeof(VSsThreadInfo) ); - semData->threadInfo->isWaiting = FALSE; - semData->threadInfo->numChildTasks = 0; - semData->threadInfo->parent = NULL; - semData->threadInfo->parentIsTask = FALSE; - semData->threadInfo->slaveAssignedTo = newSlv; - newSlv->semanticData = semData; //=================== Assign new processor to a core ===================== @@ -340,64 +372,22 @@ return newSlv; } -/*This has been removed, because have changed things.. the only way to - * create a slaveVP now is to either do an explicit create in the app, or - * else for req hdlr to create it when a task suspends if no extras are - * free. - *So, only have handleExplCreate for now.. and have the req hdlrs use the - * helper - *SlaveVP create (NOT task create!) - * - */ -/* -inline void -handleCreate( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) - { VSsSemReq *semReq; - SlaveVP *newSlv; - - - semReq = VMS_PI__take_sem_reqst_from( req ); - - newSlv = VSs__create_slave_helper( semReq->fnPtr, semReq->initData, - semEnv, semReq->coreToAssignOnto ); - - ((VSsSemData*)newSlv->semanticData)->threadInfo->parent = requestingSlv; - - 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 processor returned to it - requestingSlv->dataRetFromReq = newSlv; - - resume_slaveVP( requestingSlv, semEnv ); - resume_slaveVP( newSlv, semEnv ); - } -*/ - VSsTaskStub * -create_expl_proc_task_stub( void *initData ) +create_thread_task_stub( void *initData ) { VSsTaskStub *newStub; newStub = VMS_PI__malloc( sizeof(VSsTaskStub) ); newStub->numBlockingProp = 0; newStub->slaveAssignedTo = NULL; //set later - newStub->taskType = NULL; //Identifies as an explicit processor + newStub->taskType = IS_A_THREAD; newStub->ptrEntries = NULL; newStub->args = initData; - newStub->numChildTasks = 0; - newStub->parent = NULL; - newStub->isWaiting = FALSE; + newStub->numLiveChildTasks = 0; + newStub->numLiveChildThreads = 0; + newStub->parentTasksStub = NULL; + newStub->isWaitingForChildTasksToEnd = FALSE; + newStub->isWaitingForChildThreadsToEnd = FALSE; newStub->taskID = NULL; - newStub->parentIsTask = FALSE; return newStub; } @@ -405,6 +395,8 @@ /*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. @@ -418,27 +410,38 @@ { VSsSemReq *semReq; SlaveVP *newSlv; VSsSemData *semData, *parentSemData; - VSsTaskStub *explPrTaskStub; semReq = VMS_PI__take_sem_reqst_from( req ); - //use an idle "extra" slave, if have one - newSlv = readPrivQ( semEnv->extraTaskSlvQ ); - if( newSlv == NULL ) //or, create a new slave, if no extras - newSlv = VSs__create_slave_helper( semReq->fnPtr, semReq->initData, - semEnv, semReq->coreToAssignOnto ); - - - semData = ( (VSsSemData *)newSlv->semanticData ); - semData->needsTaskAssigned = FALSE; - semData->taskStub = create_expl_proc_task_stub( semReq->initData ); - semData->taskStub->parent = semReq->callingSlv; + 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->numChildTasks += 1; - + 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->parentTasksStub = parentSemData->taskStub; + semData->slaveType = threadSlv; //this hdlr only creates thread slvs + DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", requestingSlv->slaveID, newSlv->slaveID) @@ -451,7 +454,7 @@ addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); #endif - //For VSs, caller needs ptr to created processor returned to it + //For VSs, caller needs ptr to created thread returned to it requestingSlv->dataRetFromReq = newSlv; resume_slaveVP( requestingSlv, semEnv ); diff -r 3999b8429ddd -r eb3d77ca9f59 VSs_Request_Handlers.c --- a/VSs_Request_Handlers.c Wed Aug 01 03:16:27 2012 -0700 +++ b/VSs_Request_Handlers.c Thu Aug 02 01:03:14 2012 -0700 @@ -83,18 +83,18 @@ inline VSsTaskStub * create_task_stub( VSsTaskType *taskType, void **args ) { void **newArgs; - int32 i, numArgs; VSsTaskStub * newStub = VMS_int__malloc( sizeof(VSsTaskStub) + taskType->sizeOfArgs ); newStub->numBlockingProp = taskType->numCtldArgs; newStub->slaveAssignedTo = NULL; - newStub->taskType = taskType; + newStub->taskType = taskType; newStub->ptrEntries = VMS_int__malloc( taskType->numCtldArgs * sizeof(VSsPointerEntry *) ); newArgs = (void **)( (uint8 *)newStub + sizeof(VSsTaskStub) ); newStub->args = newArgs; - newStub->numChildTasks = 0; - newStub->parent = NULL; + newStub->numLiveChildTasks = 0; + newStub->numLiveChildThreads = 0; + //Copy the arg-pointers.. can be more arguments than just the ones // that StarSs uses to control ordering of task execution. memcpy( newArgs, args, taskType->sizeOfArgs ); @@ -239,20 +239,12 @@ taskType = semReq->taskType; taskStub = create_task_stub( taskType, args );//copies arg ptrs taskStub->numBlockingProp = taskType->numCtldArgs; - taskStub->taskID = semReq->taskID; //may be NULL - taskStub->numChildTasks = 0; + taskStub->taskID = semReq->taskID; //may be NULL - VSsSemData* parentSemData = (VSsSemData*) semReq->callingSlv->semanticData; - if(parentSemData->taskStub != NULL){ //calling is task - taskStub->parentIsTask = TRUE; - taskStub->parent = (void*) parentSemData->taskStub; - parentSemData->taskStub->numChildTasks++; - } else { - taskStub->parentIsTask = FALSE; - taskStub->parent = (void*) parentSemData->threadInfo; - parentSemData->threadInfo->numChildTasks++; - } - + VSsSemData* + parentSemData = (VSsSemData*) semReq->callingSlv->semanticData; + taskStub->parentTasksStub = (void*) parentSemData->taskStub; + parentSemData->taskStub->numLiveChildTasks += 1; /*The controlled arguments are then processed one by one. *Processing an argument means getting the hash of the pointer. Then, @@ -373,56 +365,45 @@ */ inline void handleEndTask( VSsSemReq *semReq, VSsSemEnv *semEnv ) - { uint32 key[3]; - HashEntry *rawHashEntry; - VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer + { VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer void **args; - VSsTaskStub *endingTaskStub, *waitingTaskStub; + VSsSemData *endingSlvSemData; + VSsTaskStub *endingTaskStub, *waitingTaskStub, *parent; VSsTaskType *endingTaskType; VSsWaiterCarrier *waitingTaskCarrier; VSsPointerEntry **ptrEntries; - - HashTable * - ptrHashTbl = semEnv->argPtrHashTbl; - + DEBUG__printf1(dbgRqstHdlr,"EndTask request from processor %d",semReq->callingSlv->slaveID) - /* ========================== end of task =========================== - *At the end of a task, the task-stub is sent in the request. - */ - endingTaskStub = - ((VSsSemData *)semReq->callingSlv->semanticData)->taskStub; - args = endingTaskStub->args; - endingTaskType = endingTaskStub->taskType; - ptrEntries = endingTaskStub->ptrEntries; //saved in stub when create + endingSlvSemData = (VSsSemData *)semReq->callingSlv->semanticData; + endingTaskStub = endingSlvSemData->taskStub; + args = endingTaskStub->args; + endingTaskType = endingTaskStub->taskType; + ptrEntries = endingTaskStub->ptrEntries; //saved in stub when create - /* Check if parent was waiting on this task */ - if(endingTaskStub->parentIsTask) - { VSsTaskStub* parent = (VSsTaskStub*) endingTaskStub->parent; - parent->numChildTasks--; - if(parent->isWaiting && parent->numChildTasks == 0) - { - parent->isWaiting = FALSE; - resume_slaveVP( parent->slaveAssignedTo, semEnv ); - } - } - else - { VSsThreadInfo* parent = (VSsThreadInfo*) endingTaskStub->parent; - parent->numChildTasks--; - if(parent->isWaiting && parent->numChildTasks == 0) - { - parent->isWaiting = FALSE; - resume_slaveVP( parent->slaveAssignedTo, semEnv ); - } + //Check if parent was waiting on this task + parent = (VSsTaskStub *) endingTaskStub->parentTasksStub; + parent->numLiveChildTasks -= 1; + if( parent->isWaitingForChildTasksToEnd && parent->numLiveChildTasks == 0) + { + parent->isWaitingForChildTasksToEnd = FALSE; + resume_slaveVP( parent->slaveAssignedTo, semEnv ); } + //Check if parent ended, and this was last descendent, then free it + if( parent->isEnded && parent->numLiveChildTasks == 0 ) + { VMS_PI__free( parent ); + } + + + //Now, update state of dependents and start ready tasks /*The task's controlled arguments are processed one by one. *Processing an argument means getting arg-pointer's entry. */ int32 argNum; for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ ) { - /* commented out 'cause saving entry ptr when create stub + /* 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 @@ -519,18 +500,32 @@ }//if-else, check of ending task, whether writer or reader }//for argnum in ending task - //done ending the task, now free the stub + args copy - VMS_PI__free( endingTaskStub->ptrEntries ); - VMS_PI__free( endingTaskStub ); - //Resume the slave that animated the task -- assigner will give new task - ((VSsSemData *)semReq->callingSlv->semanticData)->needsTaskAssigned = - TRUE; - resume_slaveVP( semReq->callingSlv, semEnv ); - - return; + //done ending the task, now free the stub + args copy + // if still has live children, then keep stub around + 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 ) + { VMS_PI__free( stubToFree->ptrEntries ); + VMS_PI__free( stubToFree ); + } //========================== Task Comm handlers =========================== @@ -568,7 +563,14 @@ key[ receiverIDNumInt ] = semReq->msgType; //no +1 'cause starts at 0 entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); - if( entry == NULL ) return; //was just inserted + if( entry == NULL ) //was just inserted, means task has to wait + { //the task is in a slot slave, which stays suspended, so replace + // it with a new slave (causes it to become an extraTaskSlv) + //Once the waiting slave resumes and gets to task_end, the task_end + // puts the slave into the freeExtraTaskSlvQ + replaceWithNewSlotSlv( receiverSlv, semEnv ); + return; + } //if here, found a waiting request with same key waitingReq = (VSsSemReq *)entry->content; @@ -667,7 +669,14 @@ memcpy( &key[receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); - if( entry == NULL ) return; //was just inserted + if( entry == NULL ) //was just inserted, means task has to wait + { //the task is in a slot slave, which stays suspended, so replace + // it with a new slave (causes it to become an extraTaskSlv) + //Once the waiting slave resumes and gets to task_end, the task_end + // puts the slave into the freeExtraTaskSlvQ + replaceWithNewSlotSlv( receiverSlv, semEnv ); + return; + } waitingReq = (VSsSemReq *)entry->content; @@ -742,7 +751,14 @@ entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );//clones - if( entry == NULL ) return; //was just inserted + if( entry == NULL ) //was just inserted, means task has to wait + { //the task is in a slot slave, which stays suspended, so replace + // it with a new slave (causes it to become an extraTaskSlv) + //Once the waiting slave resumes and gets to task_end, the task_end + // puts the slave into the freeExtraTaskSlvQ + replaceWithNewSlotSlv( receiverSlv, semEnv ); + return; + } waitingReq = (VSsSemReq *)entry->content; //previously cloned by insert @@ -821,14 +837,21 @@ keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32); key = VMS_PI__malloc( keySz ); memcpy( key, receiverID, receiverIDNumInt * sizeof(int32) ); - memcpy( &key[receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); + memcpy( &key[receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32)); entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); - if( entry == NULL ) return; //was just inserted + if( entry == NULL ) //was just inserted, means task has to wait + { //the task is in a slot slave, which stays suspended, so replace + // it with a new slave (causes it to become an extraTaskSlv) + //Once the waiting slave resumes and gets to task_end, the task_end + // puts the slave into the freeExtraTaskSlvQ + replaceWithNewSlotSlv( receiverSlv, semEnv ); + return; + } waitingReq = (VSsSemReq *)entry->content; - //At this point, know have waiting request(s) -- should be send(s) + //At this point, know have a request to rendez-vous -- should be send if( waitingReq->reqType == send_from_to ) { //waiting request is a send, so pair it with this receive #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC @@ -866,33 +889,56 @@ //========================================================================== inline void +replaceWithNewSlotSlv( SlaveVP *requestingSlv, VSsSemEnv *semEnv ) + { SlaveVP *newSlotSlv; + VSsSemData *semData; + + //get a new slave to be the slot slave + newSlotSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); + if( newSlotSlv == NULL ) + { newSlotSlv = VMS_int__create_slaveVP( &idle_fn, NULL ); + } + + //set slave values to make it the slot slave + semData = newSlotSlv->semanticData; + semData->taskStub = NULL; + semData->slaveType = slotTaskSlv; + semData->needsTaskAssigned = TRUE; + 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->currTaskSlvs[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; + } + +inline void handleTaskwait( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv) - { - VSsTaskStub* requestingTaskStub; + { VSsTaskStub* requestingTaskStub; + VSsSemData* semData; + DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d", + requestingSlv->slaveID) - DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d",requestingSlv->slaveID) - - VSsSemData* semData = ((VSsSemData *)semReq->callingSlv->semanticData); - - requestingTaskStub = semData->taskStub; - - if(requestingTaskStub == NULL){ //calling VP is hosting a thread - if(semData->threadInfo->numChildTasks == 0){ //nobody to wait for, proceed - resume_slaveVP( requestingSlv, semEnv ); - } else { //have to wait - semData->threadInfo->isWaiting = TRUE; - return; - } - } else { //calling VP is executing a task - if(requestingTaskStub->numChildTasks == 0){ - resume_slaveVP( requestingSlv, semEnv ); - } else { //have to wait - requestingTaskStub->isWaiting = TRUE; - return; - } + semData = (VSsSemData *)semReq->callingSlv->semanticData; + requestingTaskStub = semData->taskStub; + + if( semData->taskStub->numLiveChildTasks == 0 ) + { //nobody to wait for, resume + resume_slaveVP( requestingSlv, semEnv ); } - -} + else //have to wait, replace requester with new slot slv & mark waiting + { + replaceWithNewSlotSlv( requestingSlv, semEnv ); + + requestingTaskStub->isWaitingForChildTasksToEnd = TRUE; + } + } //==========================================================================