changeset 3:505d3c674ce8

Nov 20 PLDI final version -- working data singletons, meas hist macros in plugin
author Me
date Sat, 20 Nov 2010 08:39:58 +0100
parents e960a8d18f7c
children cfd2f7e54129
files VPThread.h VPThread_PluginFns.c VPThread_Request_Handlers.c VPThread_Request_Handlers.h VPThread_lib.c
diffstat 5 files changed, 303 insertions(+), 88 deletions(-) [+]
line diff
     1.1 --- a/VPThread.h	Tue Nov 16 16:04:29 2010 +0100
     1.2 +++ b/VPThread.h	Sat Nov 20 08:39:58 2010 +0100
     1.3 @@ -31,6 +31,17 @@
     1.4  //===========================================================================
     1.5  
     1.6  
     1.7 +/*WARNING: assembly hard-codes position of endInstrAddr as first field
     1.8 + */
     1.9 +typedef struct
    1.10 + {
    1.11 +   void           *endInstrAddr;
    1.12 +   int32           hasBeenStarted;
    1.13 +   int32           hasFinished;
    1.14 +   PrivQueueStruc *waitQ;
    1.15 + }
    1.16 +VPThdSingleton;
    1.17 +
    1.18  /*Semantic layer-specific data sent inside a request from lib called in app
    1.19   * to request handler called in MasterLoop
    1.20   */
    1.21 @@ -45,8 +56,10 @@
    1.22     make_procr,
    1.23     malloc_req,
    1.24     free_req,
    1.25 -   singleton_start,
    1.26 -   singleton_end,
    1.27 +   singleton_fn_start,
    1.28 +   singleton_fn_end,
    1.29 +   singleton_data_start,
    1.30 +   singleton_data_end,
    1.31     atomic,
    1.32     trans_start,
    1.33     trans_end
    1.34 @@ -66,7 +79,7 @@
    1.35     void                *ptrToFree;
    1.36  
    1.37     int32              singletonID;
    1.38 -   void              *endJumpPt;
    1.39 +   VPThdSingleton     **singletonPtrAddr;
    1.40  
    1.41     PtrToAtomicFn      fnToExecInMaster;
    1.42     void              *dataForFn;
    1.43 @@ -83,14 +96,6 @@
    1.44   }
    1.45  VPThdTrans;
    1.46  
    1.47 -typedef struct
    1.48 - {
    1.49 -   int32           hasBeenStarted;
    1.50 -   int32           hasFinished;
    1.51 -   void           *endInstrAddr;
    1.52 -   PrivQueueStruc *waitQ;
    1.53 - }
    1.54 -VPThdSingleton;
    1.55  
    1.56  typedef struct
    1.57   {
    1.58 @@ -143,8 +148,7 @@
    1.59     void             *applicationGlobals;
    1.60  
    1.61                         //fix limit on num with dynArray
    1.62 -   VPThdSingleton    singletons[NUM_STRUCS_IN_SEM_ENV];
    1.63 -   void             *singletonEndInstrAddr;
    1.64 +   VPThdSingleton     fnSingletons[NUM_STRUCS_IN_SEM_ENV];
    1.65  
    1.66     VPThdTrans        transactionStrucs[NUM_STRUCS_IN_SEM_ENV];
    1.67   }
    1.68 @@ -199,12 +203,17 @@
    1.69  
    1.70  
    1.71  //=======================
    1.72 +void
    1.73 +VPThread__start_fn_singleton( int32 singletonID, VirtProcr *animPr );
    1.74  
    1.75  void
    1.76 -VPThread__end_singleton( int32 singletonID, VirtProcr *animPr );
    1.77 +VPThread__end_fn_singleton( int32 singletonID, VirtProcr *animPr );
    1.78  
    1.79 -inline void
    1.80 -VPThread__start_singleton( int32 singletonID, VirtProcr *animPr );
    1.81 +void
    1.82 +VPThread__start_data_singleton( VPThdSingleton **singeltonAddr, VirtProcr *animPr );
    1.83 +
    1.84 +void
    1.85 +VPThread__end_data_singleton( VPThdSingleton **singletonAddr, VirtProcr *animPr );
    1.86  
    1.87  void
    1.88  VPThread__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
    1.89 @@ -237,5 +246,8 @@
    1.90  void
    1.91  VPThread__cleanup_after_shutdown();
    1.92  
    1.93 +void inline
    1.94 +resume_procr( VirtProcr *procr, VPThdSemEnv *semEnv );
    1.95 +
    1.96  #endif	/* _VPThread_H */
    1.97  
     2.1 --- a/VPThread_PluginFns.c	Tue Nov 16 16:04:29 2010 +0100
     2.2 +++ b/VPThread_PluginFns.c	Sat Nov 20 08:39:58 2010 +0100
     2.3 @@ -13,16 +13,14 @@
     2.4  #include "VPThread_Request_Handlers.h"
     2.5  
     2.6  //=========================== Local Fn Prototypes ===========================
     2.7 -void inline
     2.8 -resume_procr( VirtProcr *procr, VPThdSemEnv *semEnv );
     2.9  
    2.10  void inline
    2.11  handleSemReq( VMSReqst *req, VirtProcr *requestingPr, VPThdSemEnv *semEnv );
    2.12  
    2.13 -void
    2.14 +inline void
    2.15  handleDissipate(             VirtProcr *requestingPr, VPThdSemEnv *semEnv );
    2.16  
    2.17 -void
    2.18 +inline void
    2.19  handleCreate( VMSReqst *req, VirtProcr *requestingPr, VPThdSemEnv *semEnv  );
    2.20  
    2.21  
    2.22 @@ -111,12 +109,30 @@
    2.23           break;
    2.24        case cond_signal:    handleCondSignal( semReq, semEnv);
    2.25           break;
    2.26 +      case malloc_req:    handleMalloc( semReq, reqPr, semEnv);
    2.27 +         break;
    2.28 +      case free_req:    handleFree( semReq, reqPr, semEnv);
    2.29 +         break;
    2.30 +      case singleton_fn_start:  handleStartFnSingleton(semReq, reqPr, semEnv);
    2.31 +         break;
    2.32 +      case singleton_fn_end:    handleEndFnSingleton(  semReq, reqPr, semEnv);
    2.33 +         break;
    2.34 +      case singleton_data_start:handleStartDataSingleton(semReq,reqPr,semEnv);
    2.35 +         break;
    2.36 +      case singleton_data_end:  handleEndDataSingleton(semReq, reqPr, semEnv);
    2.37 +         break;
    2.38 +      case atomic:    handleAtomic( semReq, reqPr, semEnv);
    2.39 +         break;
    2.40 +      case trans_start:    handleTransStart( semReq, reqPr, semEnv);
    2.41 +         break;
    2.42 +      case trans_end:    handleTransEnd( semReq, reqPr, semEnv);
    2.43 +         break;
    2.44      }
    2.45   }
    2.46  
    2.47  //=========================== VMS Request Handlers ===========================
    2.48  //
    2.49 -void
    2.50 +inline void
    2.51  handleDissipate( VirtProcr *requestingPr, VPThdSemEnv *semEnv )
    2.52   {
    2.53        //free any semantic data allocated to the virt procr
    2.54 @@ -137,8 +153,8 @@
    2.55  inline VirtProcr *
    2.56  VPThread__create_procr_helper( VirtProcrFnPtr fnPtr, void *initData,
    2.57                            VPThdSemEnv *semEnv,    int32 coreToScheduleOnto )
    2.58 - { VirtProcr    *newPr;
    2.59 -   VPThdSemData    semData;
    2.60 + { VirtProcr      *newPr;
    2.61 +   VPThdSemData   *semData;
    2.62  
    2.63        //This is running in master, so use internal version
    2.64     newPr = VMS__create_procr( fnPtr, initData );
    2.65 @@ -175,11 +191,13 @@
    2.66     return newPr;
    2.67   }
    2.68  
    2.69 -void
    2.70 +inline void
    2.71  handleCreate( VMSReqst *req, VirtProcr *requestingPr, VPThdSemEnv *semEnv  )
    2.72   { VPThdSemReq *semReq;
    2.73     VirtProcr    *newPr;
    2.74  
    2.75 +         Meas_startCreate
    2.76 +
    2.77     semReq = VMS__take_sem_reqst_from( req );
    2.78  
    2.79     newPr = VPThread__create_procr_helper( semReq->fnPtr, semReq->initData, 
    2.80 @@ -190,6 +208,16 @@
    2.81  
    2.82     resume_procr( newPr,        semEnv );
    2.83     resume_procr( requestingPr, semEnv );
    2.84 +
    2.85 +         //========================= MEASUREMENT STUFF ======================
    2.86 +         Meas_endCreate
    2.87 +         #ifdef MEAS__TIME_PLUGIN
    2.88 +         #ifdef MEAS__SUB_CREATE
    2.89 +         subIntervalFromHist( startStamp, endStamp,
    2.90 +                                        _VMSMasterEnv->reqHdlrHighTimeHist );
    2.91 +         #endif
    2.92 +         #endif
    2.93 +         //==================================================================
    2.94   }
    2.95  
    2.96  
     3.1 --- a/VPThread_Request_Handlers.c	Tue Nov 16 16:04:29 2010 +0100
     3.2 +++ b/VPThread_Request_Handlers.c	Sat Nov 20 08:39:58 2010 +0100
     3.3 @@ -24,8 +24,8 @@
     3.4     VirtProcr   *requestingPr;
     3.5  
     3.6     requestingPr = semReq->requestingPr;
     3.7 -   newMutex = VMS__malloc( sizeof(VPThdMutex), requestingPr );
     3.8 -   newMutex->waitingQueue = makePrivQ( requestingPr );
     3.9 +   newMutex = VMS__malloc( sizeof(VPThdMutex) );
    3.10 +   newMutex->waitingQueue = makeVMSPrivQ( requestingPr );
    3.11     newMutex->holderOfLock = NULL;
    3.12  
    3.13        //The mutex struc contains an int that identifies it -- use that as
    3.14 @@ -36,7 +36,7 @@
    3.15     semReq->requestingPr->dataRetFromReq = newMutex->mutexIdx;
    3.16  
    3.17        //re-animate the requester
    3.18 -   resume_procr( requestingPr );
    3.19 +   resume_procr( requestingPr, semEnv );
    3.20   }
    3.21  
    3.22  
    3.23 @@ -49,6 +49,7 @@
    3.24     
    3.25     #endif
    3.26     //=================================================================
    3.27 +         Meas_startMutexLock
    3.28        //lookup mutex struc, using mutexIdx as index
    3.29     mutex = semEnv->mutexDynArray[ semReq->mutexIdx ];
    3.30  
    3.31 @@ -58,12 +59,13 @@
    3.32        mutex->holderOfLock = semReq->requestingPr;
    3.33  
    3.34           //re-animate requester, now that it has the lock
    3.35 -      resume_procr( semReq->requestingPr );
    3.36 +      resume_procr( semReq->requestingPr, semEnv );
    3.37      }
    3.38     else //queue up requester to wait for release of lock
    3.39      {
    3.40        writePrivQ( semReq->requestingPr, mutex->waitingQueue );
    3.41      }
    3.42 +         Meas_endMutexLock
    3.43   }
    3.44  
    3.45  /*
    3.46 @@ -72,6 +74,7 @@
    3.47  handleMutexUnlock( VPThdSemReq *semReq, VPThdSemEnv *semEnv)
    3.48   { VPThdMutex  *mutex;
    3.49  
    3.50 +         Meas_startMutexUnlock
    3.51        //lookup mutex struc, using mutexIdx as index
    3.52     mutex = semEnv->mutexDynArray[ semReq->mutexIdx ];
    3.53  
    3.54 @@ -81,11 +84,12 @@
    3.55        //if have new non-NULL holder, re-animate it
    3.56     if( mutex->holderOfLock != NULL )
    3.57      {
    3.58 -      resume_procr( mutex->holderOfLock );
    3.59 +      resume_procr( mutex->holderOfLock, semEnv );
    3.60      }
    3.61  
    3.62        //re-animate the releaser of the lock
    3.63 -   resume_procr( semReq->requestingPr );
    3.64 +   resume_procr( semReq->requestingPr, semEnv );
    3.65 +         Meas_endMutexUnlock
    3.66   }
    3.67  
    3.68  //===========================  Condition Vars  ==============================
    3.69 @@ -106,10 +110,10 @@
    3.70     VirtProcr  *requestingPr;
    3.71  
    3.72     requestingPr  = semReq->requestingPr;
    3.73 -   newCond = VMS__malloc( sizeof(VPThdCond), requestingPr );
    3.74 +   newCond = VMS__malloc( sizeof(VPThdCond) );
    3.75     newCond->partnerMutex = semEnv->mutexDynArray[ semReq->mutexIdx ];
    3.76  
    3.77 -   newCond->waitingQueue = makePrivQ();
    3.78 +   newCond->waitingQueue = makeVMSPrivQ();
    3.79  
    3.80        //The cond struc contains an int that identifies it -- use that as
    3.81        // its index within the array of conds.  Add the new cond to array.
    3.82 @@ -119,7 +123,7 @@
    3.83     semReq->requestingPr->dataRetFromReq = newCond->condIdx;
    3.84     
    3.85        //re-animate the requester
    3.86 -   resume_procr( requestingPr );
    3.87 +   resume_procr( requestingPr, semEnv );
    3.88   }
    3.89  
    3.90  
    3.91 @@ -131,8 +135,8 @@
    3.92  handleCondWait( VPThdSemReq *semReq, VPThdSemEnv *semEnv)
    3.93   { VPThdCond   *cond;
    3.94     VPThdMutex  *mutex;
    3.95 -   VirtProcr  *pr;
    3.96  
    3.97 +         Meas_startCondWait
    3.98        //get cond struc out of array of them that's in the sem env
    3.99     cond = semEnv->condDynArray[ semReq->condIdx ];
   3.100  
   3.101 @@ -145,8 +149,9 @@
   3.102  
   3.103     if( mutex->holderOfLock != NULL )
   3.104      {
   3.105 -      resume_procr( mutex->holderOfLock );
   3.106 +      resume_procr( mutex->holderOfLock, semEnv );
   3.107      }
   3.108 +         Meas_endCondWait
   3.109   }
   3.110  
   3.111  
   3.112 @@ -159,6 +164,7 @@
   3.113     VPThdMutex  *mutex;
   3.114     VirtProcr  *waitingPr, *pr;
   3.115  
   3.116 +         Meas_startCondSignal
   3.117        //get cond struc out of array of them that's in the sem env
   3.118     cond = semEnv->condDynArray[ semReq->condIdx ];
   3.119     
   3.120 @@ -171,7 +177,8 @@
   3.121     pushPrivQ( waitingPr, mutex->waitingQueue ); //is first out when read
   3.122  
   3.123        //re-animate the signalling procr
   3.124 -   resume_procr( semReq->requestingPr );
   3.125 +   resume_procr( semReq->requestingPr, semEnv );
   3.126 +         Meas_endCondSignal
   3.127   }
   3.128  
   3.129  
   3.130 @@ -184,73 +191,147 @@
   3.131  handleMalloc(VPThdSemReq *semReq, VirtProcr *requestingPr,VPThdSemEnv *semEnv)
   3.132   { void *ptr;
   3.133  
   3.134 +         //========================= MEASUREMENT STUFF ======================
   3.135 +         #ifdef MEAS__TIME_PLUGIN
   3.136 +         int32 startStamp, endStamp;
   3.137 +         saveLowTimeStampCountInto( startStamp );
   3.138 +         #endif
   3.139 +         //==================================================================
   3.140     ptr = VMS__malloc( semReq->sizeToMalloc );
   3.141     requestingPr->dataRetFromReq = ptr;
   3.142     resume_procr( requestingPr, semEnv );
   3.143 - }
   3.144 +         //========================= MEASUREMENT STUFF ======================
   3.145 +         #ifdef MEAS__TIME_PLUGIN
   3.146 +         saveLowTimeStampCountInto( endStamp );
   3.147 +         subIntervalFromHist( startStamp, endStamp,
   3.148 +                                        _VMSMasterEnv->reqHdlrHighTimeHist );
   3.149 +         #endif
   3.150 +         //==================================================================
   3.151 +  }
   3.152  
   3.153  /*
   3.154   */
   3.155  void inline
   3.156  handleFree( VPThdSemReq *semReq, VirtProcr *requestingPr, VPThdSemEnv *semEnv)
   3.157   {
   3.158 +         //========================= MEASUREMENT STUFF ======================
   3.159 +         #ifdef MEAS__TIME_PLUGIN
   3.160 +         int32 startStamp, endStamp;
   3.161 +         saveLowTimeStampCountInto( startStamp );
   3.162 +         #endif
   3.163 +         //==================================================================
   3.164     VMS__free( semReq->ptrToFree );
   3.165     resume_procr( requestingPr, semEnv );
   3.166 +         //========================= MEASUREMENT STUFF ======================
   3.167 +         #ifdef MEAS__TIME_PLUGIN
   3.168 +         saveLowTimeStampCountInto( endStamp );
   3.169 +         subIntervalFromHist( startStamp, endStamp,
   3.170 +                                        _VMSMasterEnv->reqHdlrHighTimeHist );
   3.171 +         #endif
   3.172 +         //==================================================================
   3.173   }
   3.174  
   3.175  
   3.176 -//============================================================================
   3.177 +//===========================================================================
   3.178  //
   3.179  /*Uses ID as index into array of flags.  If flag already set, resumes from
   3.180   * end-label.  Else, sets flag and resumes normally.
   3.181 - *Note, because of one-master-at-a-time, if flag is set,
   3.182   */
   3.183  void inline
   3.184 -handleStartSingleton( VPThdSemReq *semReq, VirtProcr *reqstingPr,
   3.185 -                      VPThdSemEnv *semEnv )
   3.186 +handleStartSingleton_helper( VPThdSingleton *singleton, VirtProcr *reqstingPr,
   3.187 +                             VPThdSemEnv    *semEnv )
   3.188   {
   3.189 -   if( semEnv->singletons[ semReq->singletonID ].hasFinished )
   3.190 +   if( singleton->hasFinished )
   3.191      {    //the code that sets the flag to true first sets the end instr addr
   3.192 -      reqstingPr->nextInstrPt = semEnv->singletonEndInstrAddr;
   3.193 +      reqstingPr->dataRetFromReq = singleton->endInstrAddr;
   3.194        resume_procr( reqstingPr, semEnv );
   3.195        return;
   3.196      }
   3.197 -   else if( semEnv->singletons[ semReq->singletonID ].hasBeenStarted )
   3.198 +   else if( singleton->hasBeenStarted )
   3.199      {    //singleton is in-progress in a diff slave, so wait for it to finish
   3.200 -      writePrivQ(reqstingPr, semEnv->singletons[semReq->singletonID].waitQ );
   3.201 +      writePrivQ(reqstingPr, singleton->waitQ );
   3.202        return;
   3.203      }
   3.204     else
   3.205      {    //hasn't been started, so this is the first attempt at the singleton
   3.206 -      semEnv->singletons[ semReq->singletonID ].hasBeenStarted = TRUE;
   3.207 +      singleton->hasBeenStarted = TRUE;
   3.208 +      reqstingPr->dataRetFromReq = 0x0;
   3.209        resume_procr( reqstingPr, semEnv );
   3.210        return;
   3.211      }
   3.212   }
   3.213 +void inline
   3.214 +handleStartFnSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
   3.215 +                      VPThdSemEnv *semEnv )
   3.216 + { VPThdSingleton *singleton;
   3.217 +
   3.218 +   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
   3.219 +   handleStartSingleton_helper( singleton, requestingPr, semEnv );
   3.220 + }
   3.221 +void inline
   3.222 +handleStartDataSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
   3.223 +                      VPThdSemEnv *semEnv )
   3.224 + { VPThdSingleton *singleton;
   3.225 +
   3.226 +   if( *(semReq->singletonPtrAddr) == NULL )
   3.227 +    { singleton                 = VMS__malloc( sizeof(VPThdSingleton) );
   3.228 +      singleton->waitQ          = makeVMSPrivQ();
   3.229 +      singleton->endInstrAddr   = 0x0;
   3.230 +      singleton->hasBeenStarted = FALSE;
   3.231 +      singleton->hasFinished    = FALSE;
   3.232 +      *(semReq->singletonPtrAddr)  = singleton;
   3.233 +    }
   3.234 +   else
   3.235 +      singleton = *(semReq->singletonPtrAddr);
   3.236 +   handleStartSingleton_helper( singleton, requestingPr, semEnv );
   3.237 + }
   3.238 +
   3.239  
   3.240  void inline
   3.241 -handleEndSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
   3.242 -                    VPThdSemEnv *semEnv )
   3.243 - {
   3.244 -   PrivQueueStruc waitQ;
   3.245 -   int32          numWaiting, i;
   3.246 -   
   3.247 -   if( semEnv->singletons[ semReq->singletonID ].hasFinished )
   3.248 +handleEndSingleton_helper( VPThdSingleton *singleton, VirtProcr *requestingPr,
   3.249 +                           VPThdSemEnv    *semEnv )
   3.250 + { PrivQueueStruc *waitQ;
   3.251 +   int32           numWaiting, i;
   3.252 +   VirtProcr      *resumingPr;
   3.253 +
   3.254 +   if( singleton->hasFinished )
   3.255      { //by definition, only one slave should ever be able to run end singleton
   3.256        // so if this is true, is an error
   3.257 -      VMS__throw_exception( "singleton code ran twice");
   3.258 +      //VMS__throw_exception( "singleton code ran twice", requestingPr, NULL);
   3.259      }
   3.260  
   3.261 -   semEnv->singletons[ semReq->singletonID ].hasFinished = TRUE;
   3.262 -   waitQ = semEnv->singletons[ semReq->singletonID ].waitQ;
   3.263 +   singleton->hasFinished = TRUE;
   3.264 +   waitQ = singleton->waitQ;
   3.265     numWaiting = numInPrivQ( waitQ );
   3.266     for( i = 0; i < numWaiting; i++ )
   3.267 -    {
   3.268 -      resume_procr( readPrivQ( waitQ ) );
   3.269 +    {    //they will resume inside start singleton, then jmp to end singleton
   3.270 +      resumingPr = readPrivQ( waitQ );
   3.271 +      resumingPr->dataRetFromReq = singleton->endInstrAddr;
   3.272 +      resume_procr( resumingPr, semEnv );
   3.273      }
   3.274 -   
   3.275 -   resume_procr( requestingPr );
   3.276 -  }
   3.277 +
   3.278 +   resume_procr( requestingPr, semEnv );
   3.279 +
   3.280 + }
   3.281 +void inline
   3.282 +handleEndFnSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
   3.283 +                        VPThdSemEnv *semEnv )
   3.284 + {
   3.285 +   VPThdSingleton   *singleton;
   3.286 +
   3.287 +   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
   3.288 +   handleEndSingleton_helper( singleton, requestingPr, semEnv );
   3.289 + }
   3.290 +void inline
   3.291 +handleEndDataSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
   3.292 +                        VPThdSemEnv *semEnv )
   3.293 + {
   3.294 +   VPThdSingleton   *singleton;
   3.295 +
   3.296 +   singleton = *(semReq->singletonPtrAddr);
   3.297 +   handleEndSingleton_helper( singleton, requestingPr, semEnv );
   3.298 + }
   3.299 +
   3.300  
   3.301  /*This executes the function in the masterVP, take the function
   3.302   * pointer out of the request and call it, then resume the VP.
     4.1 --- a/VPThread_Request_Handlers.h	Tue Nov 16 16:04:29 2010 +0100
     4.2 +++ b/VPThread_Request_Handlers.h	Sat Nov 20 08:39:58 2010 +0100
     4.3 @@ -14,27 +14,33 @@
     4.4  /*This header defines everything specific to the VPThread semantic plug-in
     4.5   */
     4.6  
     4.7 -void
     4.8 +inline void
     4.9  handleMakeMutex(  VPThdSemReq *semReq, VPThdSemEnv *semEnv);
    4.10 -void
    4.11 +inline void
    4.12  handleMutexLock(  VPThdSemReq *semReq, VPThdSemEnv *semEnv);
    4.13 -void
    4.14 +inline void
    4.15  handleMutexUnlock(VPThdSemReq *semReq, VPThdSemEnv *semEnv);
    4.16 -void
    4.17 +inline void
    4.18  handleMakeCond(   VPThdSemReq *semReq, VPThdSemEnv *semEnv);
    4.19 -void
    4.20 +inline void
    4.21  handleCondWait(   VPThdSemReq *semReq, VPThdSemEnv *semEnv);
    4.22 -void
    4.23 +inline void
    4.24  handleCondSignal( VPThdSemReq *semReq, VPThdSemEnv *semEnv);
    4.25  void inline
    4.26  handleMalloc(VPThdSemReq *semReq, VirtProcr *requestingPr,VPThdSemEnv *semEnv);
    4.27  void inline
    4.28  handleFree( VPThdSemReq *semReq, VirtProcr *requestingPr, VPThdSemEnv *semEnv);
    4.29 -void inline
    4.30 -handleStartSingleton( VPThdSemReq *semReq, VirtProcr *reqstingPr,
    4.31 +inline void
    4.32 +handleStartFnSingleton( VPThdSemReq *semReq, VirtProcr *reqstingPr,
    4.33                        VPThdSemEnv *semEnv );
    4.34 -void inline
    4.35 -handleEndSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
    4.36 +inline void
    4.37 +handleEndFnSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
    4.38 +                    VPThdSemEnv *semEnv );
    4.39 +inline void
    4.40 +handleStartDataSingleton( VPThdSemReq *semReq, VirtProcr *reqstingPr,
    4.41 +                      VPThdSemEnv *semEnv );
    4.42 +inline void
    4.43 +handleEndDataSingleton( VPThdSemReq *semReq, VirtProcr *requestingPr,
    4.44                      VPThdSemEnv *semEnv );
    4.45  void inline
    4.46  handleAtomic( VPThdSemReq *semReq, VirtProcr *requestingPr,
     5.1 --- a/VPThread_lib.c	Tue Nov 16 16:04:29 2010 +0100
     5.2 +++ b/VPThread_lib.c	Sat Nov 20 08:39:58 2010 +0100
     5.3 @@ -123,7 +123,7 @@
     5.4   */
     5.5  inline void
     5.6  VPThread__start_primitive()
     5.7 - { saveLowTimeStampCountInto( ((VPThreadSemEnv *)(_VMSMasterEnv->semanticEnv))->
     5.8 + { saveLowTimeStampCountInto( ((VPThdSemEnv *)(_VMSMasterEnv->semanticEnv))->
     5.9                                primitiveStartTime );
    5.10   }
    5.11  
    5.12 @@ -190,7 +190,7 @@
    5.13  
    5.14     for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
    5.15      {
    5.16 -      readyVPQs[ coreIdx ] = makePrivQ();
    5.17 +      readyVPQs[ coreIdx ] = makeVMSPrivQ();
    5.18      }
    5.19     
    5.20     semanticEnv->readyVPQs          = readyVPQs;
    5.21 @@ -209,10 +209,11 @@
    5.22     //semanticEnv->transactionStrucs = makeDynArrayInfo( );
    5.23     for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ )
    5.24      {
    5.25 -      semanticEnv->singletons[i].hasBeenStarted    = FALSE;
    5.26 -      semanticEnv->singletons[i].hasFinished       = FALSE;
    5.27 -      semanticEnv->singletons[i].waitQ             = makePrivQ;
    5.28 -      semanticEnv->transactionStrucs[i].waitingVPQ = makePrivQ();
    5.29 +      semanticEnv->fnSingletons[i].endInstrAddr      = NULL;
    5.30 +      semanticEnv->fnSingletons[i].hasBeenStarted    = FALSE;
    5.31 +      semanticEnv->fnSingletons[i].hasFinished       = FALSE;
    5.32 +      semanticEnv->fnSingletons[i].waitQ             = makeVMSPrivQ();
    5.33 +      semanticEnv->transactionStrucs[i].waitingVPQ   = makeVMSPrivQ();
    5.34      }   
    5.35   }
    5.36  
    5.37 @@ -438,40 +439,95 @@
    5.38  
    5.39     VMS__send_sem_request( &reqData, signallingPr );
    5.40   }
    5.41 -//============================================================================
    5.42  
    5.43 -/*Uses ID as index into array of flags.  If flag already set, resumes from
    5.44 - * end-label.  Else, sets flag and resumes normally.
    5.45 +
    5.46 +//===========================================================================
    5.47 +//
    5.48 +/*A function singleton is a function whose body executes exactly once, on a
    5.49 + * single core, no matter how many times the fuction is called and no
    5.50 + * matter how many cores or the timing of cores calling it.
    5.51 + *
    5.52 + *A data singleton is a ticket attached to data.  That ticket can be used
    5.53 + * to get the data through the function exactly once, no matter how many
    5.54 + * times the data is given to the function, and no matter the timing of
    5.55 + * trying to get the data through from different cores.
    5.56   */
    5.57 -inline void
    5.58 -VPThread__start_singleton( int32 singletonID, VirtProcr *animPr )
    5.59 +
    5.60 +/*Fn singleton uses ID as index into array of singleton structs held in the
    5.61 + * semantic environment.
    5.62 + */
    5.63 +void
    5.64 +VPThread__start_fn_singleton( int32 singletonID,   VirtProcr *animPr )
    5.65   {
    5.66     VPThdSemReq  reqData;
    5.67  
    5.68 -   reqData.reqType     = singleton_start;
    5.69 +      //
    5.70 +   reqData.reqType     = singleton_fn_start;
    5.71     reqData.singletonID = singletonID;
    5.72  
    5.73     VMS__send_sem_request( &reqData, animPr );
    5.74 +   if( animPr->dataRetFromReq ) //will be 0 or addr of label in end singleton
    5.75 +    {
    5.76 +      asm volatile("movl         %0,      %%eax;  \
    5.77 +                    jmp                  *%%eax"  \
    5.78 +      /* outputs */ :                             \
    5.79 +      /* inputs  */ : "g"(animPr->dataRetFromReq) \
    5.80 +      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
    5.81 +                   );
    5.82 +    }
    5.83   }
    5.84  
    5.85 +/*Data singleton hands addr of loc holding a pointer to a singleton struct.
    5.86 + * The start_data_singleton makes the structure and puts its addr into the
    5.87 + * location.
    5.88 + */
    5.89 +void
    5.90 +VPThread__start_data_singleton( VPThdSingleton **singletonAddr,  VirtProcr *animPr )
    5.91 + {
    5.92 +   VPThdSemReq  reqData;
    5.93 +
    5.94 +   if( *singletonAddr && (*singletonAddr)->hasFinished )
    5.95 +      goto JmpToEndSingleton;
    5.96 +      //
    5.97 +   reqData.reqType       = singleton_data_start;
    5.98 +   reqData.singletonPtrAddr = singletonAddr;
    5.99 +
   5.100 +   VMS__send_sem_request( &reqData, animPr );
   5.101 +   if( animPr->dataRetFromReq ) //either 0 or end singleton's return addr
   5.102 +    {    //Assembly code changes the return addr on the stack to the one
   5.103 +         // saved into the singleton by the end-singleton-fn
   5.104 +         //The stack's return addr is at 0x4(%%ebp)
   5.105 +      JmpToEndSingleton:
   5.106 +      asm volatile("movl        %0,      %%eax;   \
   5.107 +                    movl    (%%eax),     %%ebx;   \
   5.108 +                    movl    (%%ebx),     %%eax;   \
   5.109 +                    movl     %%eax,  0x4(%%ebp);" \
   5.110 +      /* outputs */ :                             \
   5.111 +      /* inputs  */ : "m"(singletonAddr) \
   5.112 +      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   5.113 +                   );
   5.114 +    }
   5.115 +   //now, simply return
   5.116 +   //will exit either from the start singleton call or the end-singleton call
   5.117 + }
   5.118  
   5.119  /*Uses ID as index into array of flags.  If flag already set, resumes from
   5.120   * end-label.  Else, sets flag and resumes normally.
   5.121   *
   5.122   *Note, this call cannot be inlined because the instr addr at the label
   5.123 - * inside is shared by all invocations of singleton.
   5.124 + * inside is shared by all invocations of a given singleton ID.
   5.125   */
   5.126  void
   5.127 -VPThread__end_singleton( int32 singletonID, VirtProcr *animPr )
   5.128 +VPThread__end_fn_singleton( int32 singletonID, VirtProcr *animPr )
   5.129   {
   5.130     VPThdSemReq  reqData;
   5.131  
   5.132        //don't need this addr until after at least one singleton has reached
   5.133        // this function
   5.134     VPThdSemEnv *semEnv = VMS__give_sem_env_for( animPr );
   5.135 -   semEnv->singletons[ singletonID ].endInstrAddr = &&EndSingletonInstrAddr;
   5.136 -      
   5.137 -   reqData.reqType     = singleton_end;
   5.138 +   semEnv->fnSingletons[ singletonID].endInstrAddr = &&EndSingletonInstrAddr;
   5.139 +
   5.140 +   reqData.reqType     = singleton_fn_end;
   5.141     reqData.singletonID = singletonID;
   5.142  
   5.143     VMS__send_sem_request( &reqData, animPr );
   5.144 @@ -480,6 +536,38 @@
   5.145     return;
   5.146   }
   5.147  
   5.148 +void
   5.149 +VPThread__end_data_singleton(  VPThdSingleton **singletonPtrAddr, VirtProcr *animPr )
   5.150 + {
   5.151 +   VPThdSemReq  reqData;
   5.152 +
   5.153 +      //don't need this addr until after singleton struct has reached
   5.154 +      // this function for first time
   5.155 +      //do assembly that saves the return addr of this fn call into the
   5.156 +      // data singleton -- that data-singleton can only be given to exactly
   5.157 +      // one instance in the code of this function.  However, can use this
   5.158 +      // function in different places for different data-singletons.
   5.159 +//   (*(singletonAddr))->endInstrAddr =  &&EndDataSingletonInstrAddr;
   5.160 +
   5.161 +         //Assembly code takes the return addr off the stack and saves
   5.162 +         // into the singleton.  The first field in the singleton is the
   5.163 +         // "endInstrAddr" field, and the return addr is at 0x4(%%ebp)
   5.164 +      asm volatile("movl 0x4(%%ebp),     %%eax;   \
   5.165 +                    movl        %0,      %%ebx;   \
   5.166 +                    movl    (%%ebx),     %%ecx;   \
   5.167 +                    movl     %%eax,     (%%ecx);" \
   5.168 +      /* outputs */ :                             \
   5.169 +      /* inputs  */ : "m"(singletonPtrAddr) \
   5.170 +      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   5.171 +                   );
   5.172 +
   5.173 +   reqData.reqType          = singleton_data_end;
   5.174 +   reqData.singletonPtrAddr = singletonPtrAddr;
   5.175 +
   5.176 +   VMS__send_sem_request( &reqData, animPr );
   5.177 + }
   5.178 +
   5.179 +
   5.180  /*This executes the function in the masterVP, so it executes in isolation
   5.181   * from any other copies -- only one copy of the function can ever execute
   5.182   * at a time.