# HG changeset patch # User Me # Date 1289919869 -3600 # Node ID e960a8d18f7c34146c78e8c8ae6f00dcc09472bb # Parent 1d3157ac56c4993bc3ad68d1cb8cae54ad6b51f9 Added singleton, atomic, transactions -- don't think it's working singletons yet diff -r 1d3157ac56c4 -r e960a8d18f7c VPThread.h --- a/VPThread.h Thu Nov 11 04:29:10 2010 -0800 +++ b/VPThread.h Tue Nov 16 16:04:29 2010 +0100 @@ -45,7 +45,8 @@ make_procr, malloc_req, free_req, - singleton, + singleton_start, + singleton_end, atomic, trans_start, trans_end @@ -82,30 +83,14 @@ } VPThdTrans; - typedef struct { - //Standard stuff will be in most every semantic env - PrivQueueStruc **readyVPQs; - int32 numVirtPr; - int32 nextCoreToGetNewPr; - int32 primitiveStartTime; - - //Specific to this semantic layer - VPThdMutex **mutexDynArray; - PrivDynArrayInfo *mutexDynArrayInfo; - - VPThdCond **condDynArray; - PrivDynArrayInfo *condDynArrayInfo; - - void *applicationGlobals; - - //fix limit on num with dynArray - int32 singletonHasBeenExecutedFlags[NUM_STRUCS_IN_SEM_ENV]; - VPThdTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; + int32 hasBeenStarted; + int32 hasFinished; + void *endInstrAddr; + PrivQueueStruc *waitQ; } -VPThdSemEnv; - +VPThdSingleton; typedef struct { @@ -140,6 +125,32 @@ VPThdSemData; +typedef struct + { + //Standard stuff will be in most every semantic env + PrivQueueStruc **readyVPQs; + int32 numVirtPr; + int32 nextCoreToGetNewPr; + int32 primitiveStartTime; + + //Specific to this semantic layer + VPThdMutex **mutexDynArray; + PrivDynArrayInfo *mutexDynArrayInfo; + + VPThdCond **condDynArray; + PrivDynArrayInfo *condDynArrayInfo; + + void *applicationGlobals; + + //fix limit on num with dynArray + VPThdSingleton singletons[NUM_STRUCS_IN_SEM_ENV]; + void *singletonEndInstrAddr; + + VPThdTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; + } +VPThdSemEnv; + + //=========================================================================== inline void @@ -187,6 +198,24 @@ VPThread__cond_signal( int32 condIdx, VirtProcr *signallingPr ); +//======================= + +void +VPThread__end_singleton( int32 singletonID, VirtProcr *animPr ); + +inline void +VPThread__start_singleton( int32 singletonID, VirtProcr *animPr ); + +void +VPThread__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, + void *data, VirtProcr *animPr ); + +void +VPThread__start_transaction( int32 transactionID, VirtProcr *animPr ); + +void +VPThread__end_transaction( int32 transactionID, VirtProcr *animPr ); + //========================= Internal use only ============================= diff -r 1d3157ac56c4 -r e960a8d18f7c VPThread_Request_Handlers.c --- a/VPThread_Request_Handlers.c Thu Nov 11 04:29:10 2010 -0800 +++ b/VPThread_Request_Handlers.c Tue Nov 16 16:04:29 2010 +0100 @@ -203,19 +203,54 @@ // /*Uses ID as index into array of flags. If flag already set, resumes from * end-label. Else, sets flag and resumes normally. + *Note, because of one-master-at-a-time, if flag is set, */ void inline -handleSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr, - VPThdSemEnv *semEnv ) +handleStartSingleton( VPThdSemReq *semReq, VirtProcr *reqstingPr, + VPThdSemEnv *semEnv ) { - if( semEnv->singletonHasBeenExecutedFlags[ semReq->singletonID ] ) - requestingPr->nextInstrPt = semReq->endJumpPt; + if( semEnv->singletons[ semReq->singletonID ].hasFinished ) + { //the code that sets the flag to true first sets the end instr addr + reqstingPr->nextInstrPt = semEnv->singletonEndInstrAddr; + resume_procr( reqstingPr, semEnv ); + return; + } + else if( semEnv->singletons[ semReq->singletonID ].hasBeenStarted ) + { //singleton is in-progress in a diff slave, so wait for it to finish + writePrivQ(reqstingPr, semEnv->singletons[semReq->singletonID].waitQ ); + return; + } else - semEnv->singletonHasBeenExecutedFlags[ semReq->singletonID ] = TRUE; - - resume_procr( requestingPr, semEnv ); + { //hasn't been started, so this is the first attempt at the singleton + semEnv->singletons[ semReq->singletonID ].hasBeenStarted = TRUE; + resume_procr( reqstingPr, semEnv ); + return; + } } +void inline +handleEndSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr, + VPThdSemEnv *semEnv ) + { + PrivQueueStruc waitQ; + int32 numWaiting, i; + + if( semEnv->singletons[ semReq->singletonID ].hasFinished ) + { //by definition, only one slave should ever be able to run end singleton + // so if this is true, is an error + VMS__throw_exception( "singleton code ran twice"); + } + + semEnv->singletons[ semReq->singletonID ].hasFinished = TRUE; + waitQ = semEnv->singletons[ semReq->singletonID ].waitQ; + numWaiting = numInPrivQ( waitQ ); + for( i = 0; i < numWaiting; i++ ) + { + resume_procr( readPrivQ( waitQ ) ); + } + + resume_procr( requestingPr ); + } /*This executes the function in the masterVP, take the function * pointer out of the request and call it, then resume the VP. diff -r 1d3157ac56c4 -r e960a8d18f7c VPThread_Request_Handlers.h --- a/VPThread_Request_Handlers.h Thu Nov 11 04:29:10 2010 -0800 +++ b/VPThread_Request_Handlers.h Tue Nov 16 16:04:29 2010 +0100 @@ -26,6 +26,26 @@ handleCondWait( VPThdSemReq *semReq, VPThdSemEnv *semEnv); void handleCondSignal( VPThdSemReq *semReq, VPThdSemEnv *semEnv); +void inline +handleMalloc(VPThdSemReq *semReq, VirtProcr *requestingPr,VPThdSemEnv *semEnv); +void inline +handleFree( VPThdSemReq *semReq, VirtProcr *requestingPr, VPThdSemEnv *semEnv); +void inline +handleStartSingleton( VPThdSemReq *semReq, VirtProcr *reqstingPr, + VPThdSemEnv *semEnv ); +void inline +handleEndSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr, + VPThdSemEnv *semEnv ); +void inline +handleAtomic( VPThdSemReq *semReq, VirtProcr *requestingPr, + VPThdSemEnv *semEnv); +void inline +handleTransStart( VPThdSemReq *semReq, VirtProcr *requestingPr, + VPThdSemEnv *semEnv ); +void inline +handleTransEnd( VPThdSemReq *semReq, VirtProcr *requestingPr, + VPThdSemEnv *semEnv); + #endif /* _VPThread_REQ_H */ diff -r 1d3157ac56c4 -r e960a8d18f7c VPThread_lib.c --- a/VPThread_lib.c Thu Nov 11 04:29:10 2010 -0800 +++ b/VPThread_lib.c Tue Nov 16 16:04:29 2010 +0100 @@ -209,9 +209,11 @@ //semanticEnv->transactionStrucs = makeDynArrayInfo( ); for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) { - semanticEnv->singletonHasBeenExecutedFlags[i] = FALSE; + semanticEnv->singletons[i].hasBeenStarted = FALSE; + semanticEnv->singletons[i].hasFinished = FALSE; + semanticEnv->singletons[i].waitQ = makePrivQ; semanticEnv->transactionStrucs[i].waitingVPQ = makePrivQ(); - } + } } @@ -436,4 +438,116 @@ VMS__send_sem_request( &reqData, signallingPr ); } +//============================================================================ + +/*Uses ID as index into array of flags. If flag already set, resumes from + * end-label. Else, sets flag and resumes normally. + */ +inline void +VPThread__start_singleton( int32 singletonID, VirtProcr *animPr ) + { + VPThdSemReq reqData; + + reqData.reqType = singleton_start; + reqData.singletonID = singletonID; + + VMS__send_sem_request( &reqData, animPr ); + } + + +/*Uses ID as index into array of flags. If flag already set, resumes from + * end-label. Else, sets flag and resumes normally. + * + *Note, this call cannot be inlined because the instr addr at the label + * inside is shared by all invocations of singleton. + */ +void +VPThread__end_singleton( int32 singletonID, VirtProcr *animPr ) + { + VPThdSemReq reqData; + + //don't need this addr until after at least one singleton has reached + // this function + VPThdSemEnv *semEnv = VMS__give_sem_env_for( animPr ); + semEnv->singletons[ singletonID ].endInstrAddr = &&EndSingletonInstrAddr; + + reqData.reqType = singleton_end; + reqData.singletonID = singletonID; + + VMS__send_sem_request( &reqData, animPr ); + +EndSingletonInstrAddr: + return; + } + +/*This executes the function in the masterVP, so it executes in isolation + * from any other copies -- only one copy of the function can ever execute + * at a time. + * + *It suspends to the master, and the request handler takes the function + * pointer out of the request and calls it, then resumes the VP. + *Only very short functions should be called this way -- for longer-running + * isolation, use transaction-start and transaction-end, which run the code + * between as work-code. + */ +void +VPThread__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, + void *data, VirtProcr *animPr ) + { + VPThdSemReq reqData; + + // + reqData.reqType = atomic; + reqData.fnToExecInMaster = ptrToFnToExecInMaster; + reqData.dataForFn = data; + + VMS__send_sem_request( &reqData, animPr ); + } + + +/*This suspends to the master. + *First, it looks at the VP's data, to see the highest transactionID that VP + * already has entered. If the current ID is not larger, it throws an + * exception stating a bug in the code. Otherwise it puts the current ID + * there, and adds the ID to a linked list of IDs entered -- the list is + * used to check that exits are properly ordered. + *Next it is uses transactionID as index into an array of transaction + * structures. + *If the "VP_currently_executing" field is non-null, then put requesting VP + * into queue in the struct. (At some point a holder will request + * end-transaction, which will take this VP from the queue and resume it.) + *If NULL, then write requesting into the field and resume. + */ +void +VPThread__start_transaction( int32 transactionID, VirtProcr *animPr ) + { + VPThdSemReq reqData; + + // + reqData.reqType = trans_start; + reqData.transID = transactionID; + + VMS__send_sem_request( &reqData, animPr ); + } + +/*This suspends to the master, then uses transactionID as index into an + * array of transaction structures. + *It looks at VP_currently_executing to be sure it's same as requesting VP. + * If different, throws an exception, stating there's a bug in the code. + *Next it looks at the queue in the structure. + *If it's empty, it sets VP_currently_executing field to NULL and resumes. + *If something in, gets it, sets VP_currently_executing to that VP, then + * resumes both. + */ +void +VPThread__end_transaction( int32 transactionID, VirtProcr *animPr ) + { + VPThdSemReq reqData; + + // + reqData.reqType = trans_end; + reqData.transID = transactionID; + + VMS__send_sem_request( &reqData, animPr ); + } //===========================================================================