seanhalle@0: /* seanhalle@0: * Copyright 2010 OpenSourceCodeStewardshipFoundation seanhalle@0: * seanhalle@0: * Licensed under BSD seanhalle@0: */ seanhalle@0: seanhalle@0: #include seanhalle@0: #include seanhalle@0: #include seanhalle@0: seanhalle@0: #include "Queue_impl/PrivateQueue.h" seanhalle@0: #include "Hash_impl/PrivateHash.h" seanhalle@0: seanhalle@2: #include "VSs.h" seanhalle@3: #include "Measurement/VSs_Counter_Recording.h" seanhalle@0: seanhalle@0: //========================================================================== seanhalle@27: void seanhalle@27: VSs__init_Helper(); seanhalle@27: seanhalle@27: SlaveVP * seanhalle@27: VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, seanhalle@27: int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ); seanhalle@0: seanhalle@0: //========================================================================== seanhalle@0: seanhalle@0: seanhalle@0: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@0: seanhalle@0: /*These are the library functions *called in the application* seanhalle@0: * seanhalle@0: *There's a pattern for the outside sequential code to interact with the seanhalle@26: * PR_HW code. seanhalle@26: *The PR_HW system is inside a boundary.. every VSs system is in its seanhalle@0: * own directory that contains the functions for each of the processor types. seanhalle@0: * One of the processor types is the "seed" processor that starts the seanhalle@0: * cascade of creating all the processors that do the work. seanhalle@0: *So, in the directory is a file called "EntryPoint.c" that contains the seanhalle@0: * function, named appropriately to the work performed, that the outside seanhalle@0: * sequential code calls. This function follows a pattern: seanhalle@2: *1) it calls VSs__init() seanhalle@0: *2) it creates the initial data for the seed processor, which is passed seanhalle@0: * in to the function seanhalle@2: *3) it creates the seed VSs processor, with the data to start it with. seanhalle@2: *4) it calls startVSsThenWaitUntilWorkDone seanhalle@0: *5) it gets the returnValue from the transfer struc and returns that seanhalle@0: * from the function seanhalle@0: * seanhalle@2: *For now, a new VSs system has to be created via VSs__init every seanhalle@0: * time an entry point function is called -- later, might add letting the seanhalle@2: * VSs system be created once, and let all the entry points just reuse seanhalle@0: * it -- want to be as simple as possible now, and see by using what makes seanhalle@0: * sense for later.. seanhalle@0: */ seanhalle@0: seanhalle@0: seanhalle@0: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@0: int32 seanhalle@2: VSs__giveMinWorkUnitCycles( float32 percentOverhead ) seanhalle@0: { seanhalle@0: return MIN_WORK_UNIT_CYCLES; seanhalle@0: } seanhalle@0: seanhalle@0: int32 seanhalle@2: VSs__giveIdealNumWorkUnits() seanhalle@0: { seanhalle@0: return NUM_ANIM_SLOTS * NUM_CORES; seanhalle@0: } seanhalle@0: seanhalle@0: int32 seanhalle@2: VSs__give_number_of_cores_to_schedule_onto() seanhalle@0: { seanhalle@0: return NUM_CORES; seanhalle@0: } seanhalle@0: seanhalle@0: /*For now, use TSC -- later, make these two macros with assembly that first seanhalle@0: * saves jump point, and second jumps back several times to get reliable time seanhalle@0: */ seanhalle@0: void seanhalle@27: VSs__begin_primitive( SlaveVP *animSlv ) seanhalle@27: { VSsLangData *langData; seanhalle@26: seanhalle@27: langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER); seanhalle@26: seanhalle@27: saveLowTimeStampCountInto( langData->primitiveStartTime ); seanhalle@0: } seanhalle@0: seanhalle@0: /*Just quick and dirty for now -- make reliable later seanhalle@0: * will want this to jump back several times -- to be sure cache is warm seanhalle@0: * because don't want comm time included in calc-time measurement -- and seanhalle@0: * also to throw out any "weird" values due to OS interrupt or TSC rollover seanhalle@0: */ seanhalle@0: int32 seanhalle@27: VSs__end_primitive_and_give_cycles( SlaveVP *animSlv ) seanhalle@0: { int32 endTime, startTime; seanhalle@27: VSsLangData *langData; seanhalle@26: seanhalle@0: //TODO: fix by repeating time-measurement seanhalle@0: saveLowTimeStampCountInto( endTime ); seanhalle@27: langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER); seanhalle@27: startTime = langData->primitiveStartTime; seanhalle@0: return (endTime - startTime); seanhalle@0: } seanhalle@0: seanhalle@26: seanhalle@0: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@2: SlaveVP * seanhalle@7: VSs__create_thread( TopLevelFnPtr fnPtr, void *initData, seanhalle@7: SlaveVP *creatingThd ) seanhalle@26: { seanhalle@26: return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID, seanhalle@26: ANY_CORE, creatingThd ); seanhalle@26: } seanhalle@26: seanhalle@26: SlaveVP * seanhalle@26: VSs__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID, seanhalle@26: SlaveVP *creatingThd ) seanhalle@26: { seanhalle@26: return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, thdID, seanhalle@26: ANY_CORE, creatingThd ); seanhalle@26: } seanhalle@26: seanhalle@27: /* old version -- looks safe to delete seanhalle@27: SlaveVP * seanhalle@27: VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, seanhalle@27: SlaveVP *creatingSlv, int32 coreToAssignOnto ) seanhalle@27: { VSsLangReq reqData; seanhalle@27: seanhalle@27: //the lang request data is on the stack and disappears when this seanhalle@27: // call returns -- it's guaranteed to remain in the VP's stack for as seanhalle@27: // long as the VP is suspended. seanhalle@27: reqData.reqType = create_slave_w_aff; //not used, May 2012 seanhalle@27: reqData.coreToAssignOnto = coreToAssignOnto; seanhalle@27: reqData.fnPtr = fnPtr; seanhalle@27: reqData.initData = initData; seanhalle@27: reqData.callingSlv = creatingSlv; seanhalle@27: seanhalle@27: PR_WL__send_create_slaveVP_req( &reqData, creatingSlv, VSs_MAGIC_NUMBER ); seanhalle@27: seanhalle@27: return creatingSlv->dataRetFromReq; seanhalle@27: } seanhalle@27: */ seanhalle@27: seanhalle@26: seanhalle@26: SlaveVP * seanhalle@26: VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, seanhalle@26: int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ) seanhalle@27: { VSsLangReq reqData; seanhalle@0: seanhalle@27: //the lang request data is on the stack and disappears when this seanhalle@0: // call returns -- it's guaranteed to remain in the VP's stack for as seanhalle@0: // long as the VP is suspended. seanhalle@27: reqData.reqType = create_slave; //know type because in a PR create req seanhalle@27: reqData.coreToAssignOnto = coreToAssignOnto; seanhalle@27: reqData.fnPtr = fnPtr; seanhalle@27: reqData.initData = initData; seanhalle@26: seanhalle@27: PR_WL__send_create_slaveVP_req( &reqData, thdID, &handleCreateThd, seanhalle@26: creatingThd, VSs_MAGIC_NUMBER ); seanhalle@27: return (SlaveVP *)creatingThd->dataRetFromReq; seanhalle@0: } seanhalle@0: seanhalle@10: /*This is always the last thing done in the code animated by a thread VP. seanhalle@7: * Normally, this would be the last line of the thread's top level function. seanhalle@7: * But, if the thread exits from any point, it has to do so by calling seanhalle@7: * this. seanhalle@10: * seanhalle@10: *It simply sends a dissipate request, which handles all the state cleanup. seanhalle@7: */ seanhalle@2: void seanhalle@7: VSs__end_thread( SlaveVP *thdToEnd ) seanhalle@26: { seanhalle@27: //the lang request is null for VSs version of end slave seanhalle@27: PR_WL__send_end_slave_req( NULL, &handleDissipate, thdToEnd, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@0: seanhalle@10: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@0: seanhalle@4: //======================= task submit and end ============================== seanhalle@4: /* seanhalle@2: */ seanhalle@4: void seanhalle@2: VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv) seanhalle@27: { VSsLangReq reqData; seanhalle@0: seanhalle@2: reqData.reqType = submit_task; seanhalle@4: seanhalle@2: reqData.taskType = taskType; seanhalle@2: reqData.args = args; seanhalle@4: reqData.callingSlv = animSlv; seanhalle@4: seanhalle@26: //Create task is a special form, so have to pass as parameters, the seanhalle@26: // top-level-fn of task and the data for that fn, plus lang's req, seanhalle@26: // animating slave, and lang's magic number seanhalle@27: PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID, seanhalle@27: &handleSubmitTask, animSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: void seanhalle@4: VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, seanhalle@27: SlaveVP *animSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@26: seanhalle@4: reqData.reqType = submit_task; seanhalle@4: seanhalle@4: reqData.taskType = taskType; seanhalle@4: reqData.args = args; seanhalle@4: reqData.callingSlv = animSlv; seanhalle@4: seanhalle@27: PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID, seanhalle@27: &handleSubmitTask, animSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: /*This call is the last to happen in every task. It causes the slave to seanhalle@2: * suspend and get the next task out of the task-queue. Notice there is no seanhalle@2: * assigner here.. only one slave, no slave ReadyQ, and so on.. seanhalle@2: *Can either make the assigner take the next task out of the taskQ, or can seanhalle@2: * leave all as it is, and make task-end take the next task. seanhalle@26: *Note: this fits the case in the new PR for no-context tasks, so will use seanhalle@26: * the built-in taskQ of new PR, and should be local and much faster. seanhalle@2: * seanhalle@2: *The task-stub is saved in the animSlv, so the request handler will get it seanhalle@2: * from there, along with the task-type which has arg types, and so on.. seanhalle@4: * seanhalle@4: * NOTE: if want, don't need to send the animating SlaveVP around.. seanhalle@4: * instead, can make a single slave per core, and coreCtrlr looks up the seanhalle@4: * slave from having the core number. seanhalle@4: * seanhalle@26: *But, to stay compatible with all the other PR languages, leave it in.. seanhalle@0: */ seanhalle@0: void seanhalle@2: VSs__end_task( SlaveVP *animSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@2: seanhalle@27: //VSs has nothing extra to communicate to end task handler, so lang req is NULL seanhalle@27: PR_WL__send_end_task_request( NULL, &handleEndTask, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@4: seanhalle@26: /*Waits for all tasks that are direct children to end, then resumes calling seanhalle@26: * task or thread seanhalle@26: */ nengel@5: void nengel@5: VSs__taskwait(SlaveVP *animSlv) seanhalle@26: { seanhalle@27: VSsLangReq reqData; nengel@5: nengel@5: reqData.reqType = taskwait; nengel@5: reqData.callingSlv = animSlv; nengel@5: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleTaskwait, animSlv, VSs_MAGIC_NUMBER ); seanhalle@26: } nengel@5: nengel@5: nengel@5: seanhalle@4: //========================== send and receive ============================ seanhalle@4: // seanhalle@4: seanhalle@4: inline int32 * seanhalle@4: VSs__give_self_taskID( SlaveVP *animSlv ) seanhalle@4: { seanhalle@27: return PR__give_ID_from_slave( animSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: //================================ send =================================== seanhalle@4: seanhalle@4: void seanhalle@4: VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID, seanhalle@4: SlaveVP *senderSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = send_type_to; seanhalle@4: seanhalle@4: reqData.msg = msg; seanhalle@4: reqData.msgType = type; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.senderSlv = senderSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleSendTypeTo, senderSlv, VSs_MAGIC_NUMBER ); seanhalle@4: seanhalle@4: //When come back from suspend, no longer own data reachable from msg seanhalle@4: } seanhalle@4: seanhalle@4: void seanhalle@4: VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = send_from_to; seanhalle@4: seanhalle@4: reqData.msg = msg; seanhalle@4: reqData.senderID = senderID; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.senderSlv = senderSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleSendFromTo, senderSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: //================================ receive ================================ seanhalle@4: seanhalle@4: /*The "type" version of send and receive creates a many-to-one relationship. seanhalle@4: * The sender is anonymous, and many sends can stack up, waiting to be seanhalle@4: * received. The same receiver can also have send from-to's seanhalle@4: * waiting for it, and those will be kept separate from the "type" seanhalle@4: * messages. seanhalle@4: */ seanhalle@4: void * seanhalle@4: VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ) seanhalle@4: { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] ); seanhalle@27: VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = receive_type_to; seanhalle@4: seanhalle@4: reqData.msgType = type; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.receiverSlv = receiverSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleReceiveTypeTo, receiverSlv, VSs_MAGIC_NUMBER ); seanhalle@4: seanhalle@4: return receiverSlv->dataRetFromReq; seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: seanhalle@4: /*Call this at the point a receiving task wants in-coming data. seanhalle@4: * Use this from-to form when know senderID -- it makes a direct channel seanhalle@4: * between sender and receiver. seanhalle@4: */ seanhalle@4: void * seanhalle@4: VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ) seanhalle@4: { seanhalle@27: VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = receive_from_to; seanhalle@4: seanhalle@4: reqData.senderID = senderID; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.receiverSlv = receiverSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); seanhalle@4: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleReceiveFromTo, receiverSlv, VSs_MAGIC_NUMBER ); seanhalle@4: seanhalle@4: return receiverSlv->dataRetFromReq; seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: seanhalle@4: seanhalle@2: //========================================================================== seanhalle@0: // seanhalle@0: /*A function singleton is a function whose body executes exactly once, on a seanhalle@0: * single core, no matter how many times the fuction is called and no seanhalle@0: * matter how many cores or the timing of cores calling it. seanhalle@0: * seanhalle@0: *A data singleton is a ticket attached to data. That ticket can be used seanhalle@0: * to get the data through the function exactly once, no matter how many seanhalle@0: * times the data is given to the function, and no matter the timing of seanhalle@0: * trying to get the data through from different cores. seanhalle@0: */ seanhalle@0: seanhalle@0: /*asm function declarations*/ seanhalle@2: void asm_save_ret_to_singleton(VSsSingleton *singletonPtrAddr); seanhalle@2: void asm_write_ret_from_singleton(VSsSingleton *singletonPtrAddr); seanhalle@0: seanhalle@0: /*Fn singleton uses ID as index into array of singleton structs held in the seanhalle@27: * language environment. seanhalle@0: */ seanhalle@0: void seanhalle@3: VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: // seanhalle@0: reqData.reqType = singleton_fn_start; seanhalle@0: reqData.singletonID = singletonID; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleStartFnSingleton, animSlv, VSs_MAGIC_NUMBER ); seanhalle@3: if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton seanhalle@0: { seanhalle@27: VSsLangEnv *langEnv = seanhalle@27: PR_int__give_lang_env_for_slave__ML( animSlv, VSs_MAGIC_NUMBER ); seanhalle@27: asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID])); seanhalle@0: } seanhalle@0: } seanhalle@0: seanhalle@0: /*Data singleton hands addr of loc holding a pointer to a singleton struct. seanhalle@0: * The start_data_singleton makes the structure and puts its addr into the seanhalle@0: * location. seanhalle@0: */ seanhalle@0: void seanhalle@3: VSs__start_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: if( *singletonAddr && (*singletonAddr)->hasFinished ) seanhalle@0: goto JmpToEndSingleton; seanhalle@0: seanhalle@0: reqData.reqType = singleton_data_start; seanhalle@0: reqData.singletonPtrAddr = singletonAddr; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleStartDataSingleton, animSlv, VSs_MAGIC_NUMBER ); seanhalle@3: if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr seanhalle@0: { //Assembly code changes the return addr on the stack to the one seanhalle@0: // saved into the singleton by the end-singleton-fn seanhalle@0: //The return addr is at 0x4(%%ebp) seanhalle@0: JmpToEndSingleton: seanhalle@0: asm_write_ret_from_singleton(*singletonAddr); seanhalle@0: } seanhalle@0: //now, simply return seanhalle@0: //will exit either from the start singleton call or the end-singleton call seanhalle@0: } seanhalle@0: seanhalle@0: /*Uses ID as index into array of flags. If flag already set, resumes from seanhalle@0: * end-label. Else, sets flag and resumes normally. seanhalle@0: * seanhalle@0: *Note, this call cannot be inlined because the instr addr at the label seanhalle@0: * inside is shared by all invocations of a given singleton ID. seanhalle@0: */ seanhalle@0: void seanhalle@3: VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: //don't need this addr until after at least one singleton has reached seanhalle@0: // this function seanhalle@27: VSsLangEnv * seanhalle@27: langEnv = PR_int__give_lang_env_for_slave__ML( animSlv, VSs_MAGIC_NUMBER ); seanhalle@27: seanhalle@27: asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID])); seanhalle@0: seanhalle@0: reqData.reqType = singleton_fn_end; seanhalle@0: reqData.singletonID = singletonID; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleEndFnSingleton, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: seanhalle@0: EndSingletonInstrAddr: seanhalle@0: return; seanhalle@0: } seanhalle@0: seanhalle@0: void seanhalle@3: VSs__end_data_singleton( VSsSingleton **singletonPtrAddr, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: //don't need this addr until after singleton struct has reached seanhalle@0: // this function for first time seanhalle@0: //do assembly that saves the return addr of this fn call into the seanhalle@0: // data singleton -- that data-singleton can only be given to exactly seanhalle@0: // one instance in the code of this function. However, can use this seanhalle@0: // function in different places for different data-singletons. seanhalle@0: asm_save_ret_to_singleton(*singletonPtrAddr); seanhalle@0: seanhalle@0: reqData.reqType = singleton_data_end; seanhalle@0: reqData.singletonPtrAddr = singletonPtrAddr; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleEndDataSingleton, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@0: /*This executes the function in the masterVP, so it executes in isolation seanhalle@0: * from any other copies -- only one copy of the function can ever execute seanhalle@0: * at a time. seanhalle@0: * seanhalle@0: *It suspends to the master, and the request handler takes the function seanhalle@0: * pointer out of the request and calls it, then resumes the VP. seanhalle@0: *Only very short functions should be called this way -- for longer-running seanhalle@0: * isolation, use transaction-start and transaction-end, which run the code seanhalle@0: * between as work-code. seanhalle@0: */ seanhalle@0: void seanhalle@2: VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, seanhalle@3: void *data, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: // seanhalle@0: reqData.reqType = atomic; seanhalle@0: reqData.fnToExecInMaster = ptrToFnToExecInMaster; seanhalle@0: reqData.dataForFn = data; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleAtomic, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@0: seanhalle@0: /*This suspends to the master. seanhalle@0: *First, it looks at the VP's data, to see the highest transactionID that VP seanhalle@0: * already has entered. If the current ID is not larger, it throws an seanhalle@0: * exception stating a bug in the code. Otherwise it puts the current ID seanhalle@0: * there, and adds the ID to a linked list of IDs entered -- the list is seanhalle@0: * used to check that exits are properly ordered. seanhalle@0: *Next it is uses transactionID as index into an array of transaction seanhalle@0: * structures. seanhalle@0: *If the "VP_currently_executing" field is non-null, then put requesting VP seanhalle@0: * into queue in the struct. (At some point a holder will request seanhalle@0: * end-transaction, which will take this VP from the queue and resume it.) seanhalle@0: *If NULL, then write requesting into the field and resume. seanhalle@0: */ seanhalle@0: void seanhalle@3: VSs__start_transaction( int32 transactionID, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: // seanhalle@26: reqData.callingSlv = animSlv; seanhalle@0: reqData.reqType = trans_start; seanhalle@0: reqData.transID = transactionID; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleTransStart, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@0: /*This suspends to the master, then uses transactionID as index into an seanhalle@0: * array of transaction structures. seanhalle@0: *It looks at VP_currently_executing to be sure it's same as requesting VP. seanhalle@0: * If different, throws an exception, stating there's a bug in the code. seanhalle@0: *Next it looks at the queue in the structure. seanhalle@0: *If it's empty, it sets VP_currently_executing field to NULL and resumes. seanhalle@0: *If something in, gets it, sets VP_currently_executing to that VP, then seanhalle@0: * resumes both. seanhalle@0: */ seanhalle@0: void seanhalle@3: VSs__end_transaction( int32 transactionID, SlaveVP *animSlv ) seanhalle@0: { seanhalle@27: VSsLangReq reqData; seanhalle@0: seanhalle@0: // seanhalle@3: reqData.callingSlv = animSlv; seanhalle@0: reqData.reqType = trans_end; seanhalle@0: reqData.transID = transactionID; seanhalle@0: seanhalle@27: PR_WL__send_lang_request( &reqData, &handleTransEnd, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@7: seanhalle@7: //======================== Internal ================================== seanhalle@7: