# HG changeset patch # User Sean Halle # Date 1339724687 25200 # Node ID 13af59ed7ea5db5e7a3af4f581bf78d71966e929 # Parent 468b8638ff92b0c1513f8abfc11d4ed78a769a84 Works -- with send-receive plus normal dependencies diff -r 468b8638ff92 -r 13af59ed7ea5 VSs.c --- a/VSs.c Wed Jun 06 17:55:36 2012 -0700 +++ b/VSs.c Thu Jun 14 18:44:47 2012 -0700 @@ -226,6 +226,7 @@ semanticEnv->numSlaveVP = 0; semanticEnv->argPtrHashTbl = makeHashTable32( 16, &VMS_int__free ); + semanticEnv->commHashTbl = makeHashTable32( 16, &VMS_int__free ); //TODO: bug -- turn these arrays into dyn arrays to eliminate limit //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); @@ -429,31 +430,50 @@ //=========================================================================== -//=========================================================================== -/*Returns a taskID, which can be used to communicate between tasks with - * send-receive, or to use other kinds of constructs with tasks. +//======================= task submit and end ============================== +/* */ -int32 +void VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv) { VSsSemReq reqData; reqData.reqType = submit_task; - reqData.callingSlv = animSlv; + reqData.taskType = taskType; reqData.args = args; + reqData.callingSlv = animSlv; + reqData.taskID = NULL; VMS_WL__send_sem_request( &reqData, animSlv ); - return (int32)animSlv->dataRetFromReq; } -/*NOTE: if want, don't need to send the animating SlaveVP around.. - * instead, can make a single slave per core, and coreCtrlr looks up the - * slave from having the core number. - * - *But, to stay compatible with all the other VMS languages, leave it in.. - * - *This call is the last to happen in every task. It causes the slave to +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; + } + +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 ); + } + + +/*This call is the last to happen in every task. It causes the slave to * suspend and get the next task out of the task-queue. Notice there is no * assigner here.. only one slave, no slave ReadyQ, and so on.. *Can either make the assigner take the next task out of the taskQ, or can @@ -463,6 +483,12 @@ * *The task-stub is saved in the animSlv, so the request handler will get it * from there, along with the task-type which has arg types, and so on.. + * + * NOTE: if want, don't need to send the animating SlaveVP around.. + * instead, can make a single slave per core, and coreCtrlr looks up the + * slave from having the core number. + * + *But, to stay compatible with all the other VMS languages, leave it in.. */ void VSs__end_task( SlaveVP *animSlv ) @@ -474,6 +500,108 @@ VMS_WL__send_sem_request( &reqData, animSlv ); } + +//========================== send and receive ============================ +// + +inline int32 * +VSs__give_self_taskID( SlaveVP *animSlv ) + { + return ((VSsSemData*)animSlv->semanticData)->taskStub->taskID; + } + +//================================ send =================================== + +void +VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID, + SlaveVP *senderSlv ) + { VSsSemReq reqData; + + reqData.reqType = send_type_to; + + reqData.msg = msg; + reqData.msgType = type; + reqData.receiverID = receiverID; + reqData.senderSlv = senderSlv; + + reqData.nextReqInHashEntry = NULL; + + VMS_WL__send_sem_request( &reqData, senderSlv ); + + //When come back from suspend, no longer own data reachable from msg + } + +void +VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ) + { VSsSemReq reqData; + + reqData.reqType = send_from_to; + + reqData.msg = msg; + reqData.senderID = senderID; + reqData.receiverID = receiverID; + reqData.senderSlv = senderSlv; + + reqData.nextReqInHashEntry = NULL; + + VMS_WL__send_sem_request( &reqData, senderSlv ); + } + + +//================================ receive ================================ + +/*The "type" version of send and receive creates a many-to-one relationship. + * The sender is anonymous, and many sends can stack up, waiting to be + * received. The same receiver can also have send from-to's + * waiting for it, and those will be kept separate from the "type" + * messages. + */ +void * +VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ) + { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] ); + VSsSemReq reqData; + + reqData.reqType = receive_type_to; + + reqData.msgType = type; + reqData.receiverID = receiverID; + reqData.receiverSlv = receiverSlv; + + reqData.nextReqInHashEntry = NULL; + + VMS_WL__send_sem_request( &reqData, receiverSlv ); + + return receiverSlv->dataRetFromReq; + } + + + +/*Call this at the point a receiving task wants in-coming data. + * Use this from-to form when know senderID -- it makes a direct channel + * between sender and receiver. + */ +void * +VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ) + { + VSsSemReq reqData; + + reqData.reqType = receive_from_to; + + reqData.senderID = senderID; + reqData.receiverID = receiverID; + reqData.receiverSlv = receiverSlv; + + reqData.nextReqInHashEntry = NULL; + DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); + + VMS_WL__send_sem_request( &reqData, receiverSlv ); + + return receiverSlv->dataRetFromReq; + } + + + + //========================================================================== // /*A function singleton is a function whose body executes exactly once, on a diff -r 468b8638ff92 -r 13af59ed7ea5 VSs.h --- a/VSs.h Wed Jun 06 17:55:36 2012 -0700 +++ b/VSs.h Thu Jun 14 18:44:47 2012 -0700 @@ -33,12 +33,13 @@ typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master //=========================================================================== -#define IN 1 -#define OUT 2 -#define INOUT 2 +#define NONCTLD 0 +#define IN 1 /*Trick -- READER same as IN*/ +#define OUT 2 /*Trick -- WRITER same as OUT and INOUT*/ +#define INOUT 2 /*Trick -- WRITER same as OUT and INOUT*/ -#define READER 1 -#define WRITER 2 +#define READER 1 /*Trick -- READER same as IN*/ +#define WRITER 2 /*Trick -- WRITER same as OUT and INOUT*/ typedef struct { @@ -64,6 +65,7 @@ { void **args; //ctld args must come first, as ptrs VSsTaskType *taskType; + int32 *taskID; int32 numBlockingProp; SlaveVP *slaveAssignedTo; VSsPointerEntry **ptrEntries; @@ -116,6 +118,11 @@ create_slave_w_aff, dissipate_slave, //=============================== + send_type_to, + receive_type_to, + send_from_to, + receive_from_to, + //=============================== malloc_req, free_req, singleton_fn_start, @@ -134,6 +141,15 @@ void *args; VSsTaskStub *taskStub; + SlaveVP *senderSlv; + SlaveVP *receiverSlv; + int32 *senderID; + int32 *receiverID; + int32 msgType; + void *msg; + VSsSemReq *nextReqInHashEntry; + int32 *taskID; + TopLevelFnPtr fnPtr; void *initData; int32 coreToAssignOnto; @@ -157,6 +173,7 @@ PrivQueueStruc **readyVPQs; PrivQueueStruc *taskReadyQ; //Q: shared or local? HashTable *argPtrHashTbl; + HashTable *commHashTbl; int32 numSlaveVP; int32 nextCoreToGetNewSlv; int32 primitiveStartTime; @@ -235,11 +252,11 @@ //======================= - SlaveVP * +SlaveVP * VSs__create_slave_with( TopLevelFnPtr fnPtr, void *initData, SlaveVP *creatingSlv ); - SlaveVP * +SlaveVP * VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, SlaveVP *creatingSlv, int32 coreToAssignOnto); @@ -254,13 +271,36 @@ //======================= -int32 +void VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv); +inline int32 * +VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv ); + +void +VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, + SlaveVP *animSlv); void VSs__end_task( SlaveVP *animSlv ); +//========================= + +inline int32 * +VSs__give_self_taskID( SlaveVP *animSlv ); + +void +VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID, + SlaveVP *senderSlv ); + +void +VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ); + +void * +VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ); + +void * +VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ); //======================= Concurrency Stuff ====================== void diff -r 468b8638ff92 -r 13af59ed7ea5 VSs_PluginFns.c --- a/VSs_PluginFns.c Wed Jun 06 17:55:36 2012 -0700 +++ b/VSs_PluginFns.c Thu Jun 14 18:44:47 2012 -0700 @@ -217,6 +217,15 @@ break; case end_task: handleEndTask( semReq, semEnv); break; + case send_type_to: handleSendTypeTo( semReq, semEnv); + break; + case send_from_to: handleSendFromTo( semReq, semEnv); + break; + case receive_type_to: handleReceiveTypeTo(semReq, semEnv); + break; + case receive_from_to: handleReceiveFromTo(semReq, semEnv); + break; + //==================================================================== case malloc_req: handleMalloc( semReq, reqSlv, semEnv); break; diff -r 468b8638ff92 -r 13af59ed7ea5 VSs_Request_Handlers.c --- a/VSs_Request_Handlers.c Wed Jun 06 17:55:36 2012 -0700 +++ b/VSs_Request_Handlers.c Thu Jun 14 18:44:47 2012 -0700 @@ -25,33 +25,34 @@ // /*Only clone the elements of req used in these reqst handlers - * - VSsSemReq * + */ +VSsSemReq * cloneReq( VSsSemReq *semReq ) { VSsSemReq *clonedReq; clonedReq = VMS_PI__malloc( sizeof(VSsSemReq) ); clonedReq->reqType = semReq->reqType; - clonedReq->callingSlv = semReq->callingSlv; + clonedReq->senderSlv = semReq->senderSlv; + clonedReq->receiverSlv= semReq->receiverSlv; clonedReq->msg = semReq->msg; clonedReq->nextReqInHashEntry = NULL; return clonedReq; } -*/ -/* + + HashEntry * -giveEntryElseInsertReqst( char *key, VSsSemReq *semReq, - HashTable *commHashTbl ) +giveEntryElseInsertReqst32( int32 *key, VSsSemReq *semReq, + HashTable *commHashTbl ) { HashEntry *entry; VSsSemReq *waitingReq; - entry = getEntryFromTable( (char *)key, commHashTbl ); + entry = getEntryFromTable32( key, commHashTbl ); if( entry == NULL ) { //no waiting sends or receives, so add this request and exit // note: have to clone the request because it's on stack of sender - addValueIntoTable( key, cloneReq( semReq ), commHashTbl ); + addValueIntoTable32( key, cloneReq( semReq ), commHashTbl ); return NULL; } waitingReq = (VSsSemReq *)entry->content; @@ -62,19 +63,7 @@ } return entry; } -*/ - -/*Various ideas for getting the 64b pointer into the two 32b key-array - * positions - key[0] = 2; //two 32b values in key - OR - (uint64) (key[1]) = argPtr; - OR - *( (uint64*)&key[1] ) = argPtr; - OR - key[2] = (uint32)argPtr; //low bits - key[1] = (uint32)(argPtr >> 32); //high bits -*/ + inline VSsPointerEntry * create_pointer_entry( ) @@ -224,7 +213,7 @@ */ void handleSubmitTask( VSsSemReq *semReq, VSsSemEnv *semEnv ) - { uint32 key[3]; + { uint32 key[3]; HashEntry *rawHashEntry; //has char *, but use with uint32 * VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer void **args; @@ -249,6 +238,7 @@ taskType = semReq->taskType; taskStub = create_task_stub( taskType, args );//copies arg ptrs taskStub->numBlockingProp = taskType->numCtldArgs; + taskStub->taskID = semReq->taskID; //may be NULL /*The controlled arguments are then processed one by one. *Processing an argument means getting the hash of the pointer. Then, @@ -331,6 +321,10 @@ return; } +inline void +handleSubmitTaskWID( VSsSemReq *semReq, VSsSemEnv *semEnv) + { + } /* ========================== end of task =========================== @@ -399,7 +393,7 @@ int32 argNum; for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ ) { - /* + /* commented out 'cause saving 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 @@ -509,6 +503,340 @@ } +//========================== Task Comm handlers =========================== + + + +//============================ Send Handlers ============================== +/*Send of Type -- The semantic request has the receiving task ID and Type + * + *Messages of a given Type have to be kept separate.. so need a separate + * entry in the hash table for each pair: receiverID, Type + * + *Also, if same sender sends multiple before any get received, then need to + * stack the sends up -- even if a send waits until it's paired, several + * separate tasks can send to the same receiver, and doing hash on the + * receive task, so they will stack up. + */ +void +handleSendTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv ) + { SlaveVP *senderSlv, *receiverSlv; + int32 *senderID, *receiverID; + int32 *key, keySz, receiverIDNumInt; + VSsSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf1(dbgRqstHdlr,"SendType request from processor %d",semReq->sendPr->slaveID) + + receiverID = semReq->receiverID; //For "send", know both send & recv procrs + senderSlv = semReq->senderSlv; + + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself + keySz = receiverIDNumInt * sizeof(int32) + sizeof(int32); + key = VMS_PI__malloc( keySz ); + memcpy( key, receiverID, receiverIDNumInt * sizeof(int32) ); + key[ receiverIDNumInt ] = semReq->msgType; //no +1 'cause starts at 0 + + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); + if( entry == NULL ) return; //was just inserted + + //if here, found a waiting request with same key + waitingReq = (VSsSemReq *)entry->content; + + //At this point, know have waiting request(s) -- either sends or recv + //Note, can only have max of one receive waiting, and cannot have both + // sends and receives waiting (they would have paired off) + // but can have multiple sends from diff sending VPs, all same msg-type + if( waitingReq->reqType == send_type_to ) + { //waiting request is another send, so stack this up on list + // but first clone the sending request so it persists. + VSsSemReq *clonedReq = cloneReq( semReq ); + clonedReq-> nextReqInHashEntry = waitingReq->nextReqInHashEntry; + waitingReq->nextReqInHashEntry = clonedReq; + DEBUG__printf2( dbgRqstHdlr, "linked requests: %p, %p ", clonedReq,\ + waitingReq ) + return; + } + else + { + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = senderID->slaveID; + newd.from_task = senderID->assignCount; + newd.to_vp = receiverID->slaveID; + newd.to_task = receiverID->assignCount +1; + //(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); + int32 groupId = semReq->msgType; + if(semEnv->ntonGroupsInfo->numInArray <= groupId){ + makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); + } + if(semEnv->ntonGroups[groupId] == NULL){ + semEnv->ntonGroups[groupId] = new_NtoN(groupId); + } + Unit u; + u.vp = senderID->slaveID; + u.task = senderID->assignCount; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); + u.vp = receiverID->slaveID; + u.task = receiverID->assignCount +1; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); + #endif + + //set receiver slave, from the waiting request + receiverSlv = waitingReq->receiverSlv; + + //waiting request is a receive_type_to, so it pairs to this send + //First, remove the waiting receive request from the entry + entry->content = waitingReq->nextReqInHashEntry; + VMS_PI__free( waitingReq ); //Don't use contents -- so free it + + if( entry->content == NULL ) + { //TODO: mod hash table to double-link, so can delete entry from + // table without hashing the key and looking it up again + deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees hashEntry + } + + //attach msg that's in this send request to receiving task's Slv + // when comes back from suspend will have msg in dataRetFromReq + receiverSlv->dataRetFromReq = semReq->msg; + + //bring both processors back from suspend + resume_slaveVP( senderSlv, semEnv ); + resume_slaveVP( receiverSlv, semEnv ); + + return; + } + } + + +/*Looks like can make single handler for both sends.. + */ +//TODO: combine both send handlers into single handler +void +handleSendFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv) + { SlaveVP *senderSlv, *receiverSlv; + int32 *senderID, *receiverID; + int32 *key, keySz, receiverIDNumInt, senderIDNumInt; + VSsSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf2(dbgRqstHdlr,"SendFromTo request from processor %d to %d",semReq->sendPr->slaveID,semReq->receivePr->slaveID) + + receiverID = semReq->receiverID; //For "send", know both send & recv procrs + senderID = semReq->senderID; + //receiverSlv = semReq->receiverSlv; + senderSlv = semReq->senderSlv; + + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself + senderIDNumInt = senderID[0] + 1; + keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32); + key = VMS_PI__malloc( keySz ); + memcpy( key, receiverID, receiverIDNumInt * sizeof(int32) ); + memcpy( &key[receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); + + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); + if( entry == NULL ) return; //was just inserted + + waitingReq = (VSsSemReq *)entry->content; + + //At this point, know have waiting request(s) -- either sends or recv + if( waitingReq->reqType == send_from_to ) + { printf("\n ERROR: shouldn't be two send-from-tos waiting \n"); + } + else + { //waiting request is a receive, so it completes pair with this send + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = sendPr->slaveID; + newd.from_task = sendPr->assignCount; + newd.to_vp = receivePr->slaveID; + newd.to_task = receivePr->assignCount +1; + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); + #endif + + //set receiver slave, from the waiting request + receiverSlv = waitingReq->receiverSlv; + + //First, remove the waiting receive request from the entry + entry->content = waitingReq->nextReqInHashEntry; + VMS_PI__free( waitingReq ); //Don't use contents -- so free it + + //can only be one waiting req for "from-to" semantics + if( entry->content != NULL ) + { + printf("\nERROR in handleSendFromTo\n"); + } + deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry + + //attach msg that's in this send request to receiving procr + // when comes back from suspend, will have msg in dataRetFromReq + receiverSlv->dataRetFromReq = semReq->msg; + + //bring both processors back from suspend + resume_slaveVP( senderSlv, semEnv ); + resume_slaveVP( receiverSlv, semEnv ); + + return; + } + } + + + +//============================== Receives =========================== +// + + +void +handleReceiveTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv) + { SlaveVP *senderSlv, *receiverSlv; + int32 *receiverID; + int32 *key, keySz, receiverIDNumInt; + VSsSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf1(dbgRqstHdlr,"SendType request from processor %d",semReq->sendPr->slaveID) + + receiverID = semReq->receiverID; //For "send", know both send & recv procrs + receiverSlv = semReq->receiverSlv; + + //key is the receiverID plus the type -- have to copy them into key + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself + keySz = receiverIDNumInt * sizeof(int32) + sizeof(int32); + key = VMS_PI__malloc( keySz ); + memcpy( key, receiverID, receiverIDNumInt * sizeof(int32) ); + key[ receiverIDNumInt ] = semReq->msgType; //no +1 'cause starts at 0 + + + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );//clones + if( entry == NULL ) return; //was just inserted + + waitingReq = (VSsSemReq *)entry->content; //previously cloned by insert + + //At this point, know have waiting request(s) -- should be send(s) + if( waitingReq->reqType == send_type_to ) + { + //set sending slave from the request + senderSlv = waitingReq->senderSlv; + + //waiting request is a send, so pair it with this receive + //first, remove the waiting send request from the list in entry + entry->content = waitingReq->nextReqInHashEntry; + if( entry->content == NULL ) + { deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry + } + + //attach msg that's in the send request to receiving procr + // when comes back from suspend, will have msg in dataRetFromReq + receiverSlv->dataRetFromReq = waitingReq->msg; + + //bring both processors back from suspend + VMS_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); + int32 groupId = semReq->msgType; + if(semEnv->ntonGroupsInfo->numInArray <= groupId){ + makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); + } + if(semEnv->ntonGroups[groupId] == NULL){ + semEnv->ntonGroups[groupId] = new_NtoN(groupId); + } + Unit u; + u.vp = sendPr->slaveID; + u.task = sendPr->assignCount; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); + u.vp = receivePr->slaveID; + u.task = receivePr->assignCount +1; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); + #endif + + resume_slaveVP( senderSlv, semEnv ); + resume_slaveVP( receiverSlv, semEnv ); + + return; + } + printf("\nLang Impl Error: Should never be two waiting receives!\n"); + } + + +/* + */ +void +handleReceiveFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv) + { SlaveVP *senderSlv, *receiverSlv; + int32 *senderID, *receiverID; + int32 *key, keySz, receiverIDNumInt, senderIDNumInt; + VSsSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf2(dbgRqstHdlr,"SendFromTo request from processor %d to %d",semReq->sendPr->slaveID,semReq->receivePr->slaveID) + + receiverID = semReq->receiverID; //For "send", know both send & recv procrs + senderID = semReq->senderID; + receiverSlv = semReq->receiverSlv; + + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself + senderIDNumInt = senderID[0] + 1; + keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32); + key = VMS_PI__malloc( keySz ); + memcpy( key, receiverID, receiverIDNumInt * sizeof(int32) ); + memcpy( &key[receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); + + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); + if( entry == NULL ) return; //was just inserted + + waitingReq = (VSsSemReq *)entry->content; + + //At this point, know have waiting request(s) -- should be send(s) + 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); + #endif + + //have receiver slave, now set sender slave + senderSlv = waitingReq->senderSlv; + + //For from-to, should only ever be a single reqst waiting tobe paird + entry->content = waitingReq->nextReqInHashEntry; + if( entry->content != NULL ) printf("\nERROR in handleRecvFromTo\n"); + deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees entry too + + //attach msg that's in the send request to receiving procr + // when comes back from suspend, will have msg in dataRetFromReq + receiverSlv->dataRetFromReq = waitingReq->msg; + + //bring both processors back from suspend + VMS_PI__free( waitingReq ); + + resume_slaveVP( senderSlv, semEnv ); + resume_slaveVP( receiverSlv, semEnv ); + + return; + } + printf("\nLang Impl Error: Should never be two waiting receives!\n"); + } + + + //========================================================================== /* */