diff Vthread.c @ 29:b94dc57e4455

refactored many files -- chgd names, moved code around -- doesn't compile
author Some Random Person <seanhalle@yahoo.com>
date Wed, 09 May 2012 13:24:19 -0700
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Vthread.c	Wed May 09 13:24:19 2012 -0700
     1.3 @@ -0,0 +1,464 @@
     1.4 +/*
     1.5 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
     1.6 + *
     1.7 + * Licensed under BSD
     1.8 + */
     1.9 +
    1.10 +#include <stdio.h>
    1.11 +#include <stdlib.h>
    1.12 +
    1.13 +#include "VMS_impl/VMS.h"
    1.14 +#include "Vthread.h"
    1.15 +#include "Vthread_helper.h"
    1.16 +#include "C_Libraries/Queue_impl/PrivateQueue.h"
    1.17 +#include "C_Libraries/Hash_impl/PrivateHash.h"
    1.18 +
    1.19 +
    1.20 +//==========================================================================
    1.21 +
    1.22 +void
    1.23 +Vthread__init();
    1.24 +
    1.25 +void
    1.26 +Vthread__init_Seq();
    1.27 +
    1.28 +void
    1.29 +Vthread__init_Helper();
    1.30 +
    1.31 +
    1.32 +//===========================================================================
    1.33 +
    1.34 +/*These are the library functions *called in the application*
    1.35 + * 
    1.36 + */
    1.37 +
    1.38 +
    1.39 +
    1.40 +//===========================================================================
    1.41 +
    1.42 +inline int32
    1.43 +Vthread__giveMinWorkUnitCycles( float32 percentOverhead )
    1.44 + {
    1.45 +   return MIN_WORK_UNIT_CYCLES;
    1.46 + }
    1.47 +
    1.48 +inline int32
    1.49 +Vthread__giveIdealNumWorkUnits()
    1.50 + {
    1.51 +   return NUM_SCHED_SLOTS * NUM_CORES;
    1.52 + }
    1.53 +
    1.54 +inline int32
    1.55 +Vthread__give_number_of_cores_to_schedule_onto()
    1.56 + {
    1.57 +   return NUM_CORES;
    1.58 + }
    1.59 +
    1.60 +/*For now, use TSC -- later, make these two macros with assembly that first
    1.61 + * saves jump point, and second jumps back several times to get reliable time
    1.62 + */
    1.63 +inline void
    1.64 +Vthread__start_primitive()
    1.65 + { saveLowTimeStampCountInto( ((VthdSemEnv *)(_VMSMasterEnv->semanticEnv))->
    1.66 +                              primitiveStartTime );
    1.67 + }
    1.68 +
    1.69 +/*Just quick and dirty for now -- make reliable later
    1.70 + * will want this to jump back several times -- to be sure cache is warm
    1.71 + * because don't want comm time included in calc-time measurement -- and
    1.72 + * also to throw out any "weird" values due to OS interrupt or TSC rollover
    1.73 + */
    1.74 +inline int32
    1.75 +Vthread__end_primitive_and_give_cycles()
    1.76 + { int32 endTime, startTime;
    1.77 +   //TODO: fix by repeating time-measurement
    1.78 +   saveLowTimeStampCountInto( endTime );
    1.79 +   startTime=((VthdSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime;
    1.80 +   return (endTime - startTime);
    1.81 + }
    1.82 +
    1.83 +
    1.84 +
    1.85 +//===========================================================================
    1.86 +
    1.87 +/*Re-use this in the entry-point fn
    1.88 + */
    1.89 +inline SlaveVP *
    1.90 +Vthread__create_slaveVP_helper( TopLevelFnPtr fnPtr, void *initData,
    1.91 +                          VthdSemEnv *semEnv,    int32 coreToScheduleOnto )
    1.92 + { SlaveVP      *newSlv;
    1.93 +   VthdSemData   *semData;
    1.94 +
    1.95 +      //This is running in master, so use internal version
    1.96 +   newSlv = VMS_WL__create_slaveVP( fnPtr, initData );
    1.97 +
    1.98 +   semData = VMS_WL__malloc( sizeof(VthdSemData) );
    1.99 +   semData->highestTransEntered = -1;
   1.100 +   semData->lastTransEntered    = NULL;
   1.101 +
   1.102 +   newSlv->semanticData = semData;
   1.103 +
   1.104 +   //=================== Assign new processor to a core =====================
   1.105 +   #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
   1.106 +   newSlv->coreAnimatedBy = 0;
   1.107 +
   1.108 +   #else
   1.109 +
   1.110 +   if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES )
   1.111 +    {    //out-of-range, so round-robin assignment
   1.112 +      newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv;
   1.113 +
   1.114 +      if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 )
   1.115 +          semEnv->nextCoreToGetNewSlv  = 0;
   1.116 +      else
   1.117 +          semEnv->nextCoreToGetNewSlv += 1;
   1.118 +    }
   1.119 +   else //core num in-range, so use it
   1.120 +    { newSlv->coreAnimatedBy = coreToScheduleOnto;
   1.121 +    }
   1.122 +   #endif
   1.123 +   //========================================================================
   1.124 +
   1.125 +   return newSlv;
   1.126 + }
   1.127 +
   1.128 +
   1.129 +/*
   1.130 + */
   1.131 +inline SlaveVP *
   1.132 +Vthread__create_thread( TopLevelFnPtr fnPtr, void *initData,
   1.133 +                          SlaveVP *creatingSlv )
   1.134 + { VthdSemReq  reqData;
   1.135 +
   1.136 +      //the semantic request data is on the stack and disappears when this
   1.137 +      // call returns -- it's guaranteed to remain in the Slv's stack for as
   1.138 +      // long as the Slv is suspended.
   1.139 +   reqData.reqType            = 0; //know the type because is a VMS create req
   1.140 +   reqData.coreToScheduleOnto = -1; //means round-robin schedule
   1.141 +   reqData.fnPtr              = fnPtr;
   1.142 +   reqData.initData           = initData;
   1.143 +   reqData.requestingSlv       = creatingSlv;
   1.144 +
   1.145 +   VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv );
   1.146 +
   1.147 +   return creatingSlv->dataRetFromReq;
   1.148 + }
   1.149 +
   1.150 +
   1.151 +inline SlaveVP *
   1.152 +Vthread__create_thread_with_affinity( TopLevelFnPtr fnPtr, void *initData,
   1.153 +                           SlaveVP *creatingSlv,  int32  coreToScheduleOnto )
   1.154 + { VthdSemReq  reqData;
   1.155 +
   1.156 +      //the semantic request data is on the stack and disappears when this
   1.157 +      // call returns -- it's guaranteed to remain in the Slv's stack for as
   1.158 +      // long as the Slv is suspended.
   1.159 +   reqData.reqType            = 0; //know type because in a VMS create req
   1.160 +   reqData.coreToScheduleOnto = coreToScheduleOnto;
   1.161 +   reqData.fnPtr              = fnPtr;
   1.162 +   reqData.initData           = initData;
   1.163 +   reqData.requestingSlv       = creatingSlv;
   1.164 +
   1.165 +   VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv );
   1.166 + }
   1.167 +
   1.168 +inline void
   1.169 +Vthread__dissipate_thread( SlaveVP *procrToDissipate )
   1.170 + {
   1.171 +   VMS_WL__send_dissipate_req( procrToDissipate );
   1.172 + }
   1.173 +
   1.174 +
   1.175 +//===========================================================================
   1.176 +
   1.177 +void *
   1.178 +Vthread__malloc( size_t sizeToMalloc, SlaveVP *animSlv )
   1.179 + { VthdSemReq  reqData;
   1.180 +
   1.181 +   reqData.reqType      = malloc_req;
   1.182 +   reqData.sizeToMalloc = sizeToMalloc;
   1.183 +   reqData.requestingSlv = animSlv;
   1.184 +
   1.185 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.186 +
   1.187 +   return animSlv->dataRetFromReq;
   1.188 + }
   1.189 +
   1.190 +
   1.191 +/*Sends request to Master, which does the work of freeing
   1.192 + */
   1.193 +void
   1.194 +Vthread__free( void *ptrToFree, SlaveVP *animSlv )
   1.195 + { VthdSemReq  reqData;
   1.196 +
   1.197 +   reqData.reqType      = free_req;
   1.198 +   reqData.ptrToFree    = ptrToFree;
   1.199 +   reqData.requestingSlv = animSlv;
   1.200 +
   1.201 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.202 + }
   1.203 +
   1.204 +
   1.205 +//===========================================================================
   1.206 +
   1.207 +inline void
   1.208 +Vthread__set_globals_to( void *globals )
   1.209 + {
   1.210 +   ((VthdSemEnv *)
   1.211 +    (_VMSMasterEnv->semanticEnv))->applicationGlobals = globals;
   1.212 + }
   1.213 +
   1.214 +inline void *
   1.215 +Vthread__give_globals()
   1.216 + {
   1.217 +   return((VthdSemEnv *) (_VMSMasterEnv->semanticEnv))->applicationGlobals;
   1.218 + }
   1.219 +
   1.220 +
   1.221 +//===========================================================================
   1.222 +
   1.223 +inline int32
   1.224 +Vthread__make_mutex( SlaveVP *animSlv )
   1.225 + { VthdSemReq  reqData;
   1.226 +
   1.227 +   reqData.reqType      = make_mutex;
   1.228 +   reqData.requestingSlv = animSlv;
   1.229 +
   1.230 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.231 +
   1.232 +   return (int32)animSlv->dataRetFromReq; //mutexid is 32bit wide
   1.233 + }
   1.234 +
   1.235 +inline void
   1.236 +Vthread__mutex_lock( int32 mutexIdx, SlaveVP *acquiringSlv )
   1.237 + { VthdSemReq  reqData;
   1.238 +
   1.239 +   reqData.reqType      = mutex_lock;
   1.240 +   reqData.mutexIdx     = mutexIdx;
   1.241 +   reqData.requestingSlv = acquiringSlv;
   1.242 +
   1.243 +   VMS_WL__send_sem_request( &reqData, acquiringSlv );
   1.244 + }
   1.245 +
   1.246 +inline void
   1.247 +Vthread__mutex_unlock( int32 mutexIdx, SlaveVP *releasingSlv )
   1.248 + { VthdSemReq  reqData;
   1.249 +
   1.250 +   reqData.reqType      = mutex_unlock;
   1.251 +   reqData.mutexIdx     = mutexIdx;
   1.252 +   reqData.requestingSlv = releasingSlv;
   1.253 +
   1.254 +   VMS_WL__send_sem_request( &reqData, releasingSlv );
   1.255 + }
   1.256 +
   1.257 +
   1.258 +//=======================
   1.259 +inline int32
   1.260 +Vthread__make_cond( int32 ownedMutexIdx, SlaveVP *animSlv)
   1.261 + { VthdSemReq  reqData;
   1.262 +
   1.263 +   reqData.reqType      = make_cond;
   1.264 +   reqData.mutexIdx     = ownedMutexIdx;
   1.265 +   reqData.requestingSlv = animSlv;
   1.266 +
   1.267 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.268 +
   1.269 +   return (int32)animSlv->dataRetFromReq; //condIdx is 32 bit wide
   1.270 + }
   1.271 +
   1.272 +inline void
   1.273 +Vthread__cond_wait( int32 condIdx, SlaveVP *waitingSlv)
   1.274 + { VthdSemReq  reqData;
   1.275 +
   1.276 +   reqData.reqType      = cond_wait;
   1.277 +   reqData.condIdx      = condIdx;
   1.278 +   reqData.requestingSlv = waitingSlv;
   1.279 +
   1.280 +   VMS_WL__send_sem_request( &reqData, waitingSlv );
   1.281 + }
   1.282 +
   1.283 +inline void *
   1.284 +Vthread__cond_signal( int32 condIdx, SlaveVP *signallingSlv )
   1.285 + { VthdSemReq  reqData;
   1.286 +
   1.287 +   reqData.reqType      = cond_signal;
   1.288 +   reqData.condIdx      = condIdx;
   1.289 +   reqData.requestingSlv = signallingSlv;
   1.290 +
   1.291 +   VMS_WL__send_sem_request( &reqData, signallingSlv );
   1.292 + }
   1.293 +
   1.294 +
   1.295 +//===========================================================================
   1.296 +//
   1.297 +/*A function singleton is a function whose body executes exactly once, on a
   1.298 + * single core, no matter how many times the fuction is called and no
   1.299 + * matter how many cores or the timing of cores calling it.
   1.300 + *
   1.301 + *A data singleton is a ticket attached to data.  That ticket can be used
   1.302 + * to get the data through the function exactly once, no matter how many
   1.303 + * times the data is given to the function, and no matter the timing of
   1.304 + * trying to get the data through from different cores.
   1.305 + */
   1.306 +
   1.307 +/*Fn singleton uses ID as index into array of singleton structs held in the
   1.308 + * semantic environment.
   1.309 + */
   1.310 +void
   1.311 +Vthread__start_fn_singleton( int32 singletonID,   SlaveVP *animSlv )
   1.312 + {
   1.313 +   VthdSemReq  reqData;
   1.314 +
   1.315 +      //
   1.316 +   reqData.reqType     = singleton_fn_start;
   1.317 +   reqData.singletonID = singletonID;
   1.318 +
   1.319 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.320 +   if( animSlv->dataRetFromReq != 0 ) //addr of matching end-singleton
   1.321 +    {
   1.322 +      VthdSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); //not protected!
   1.323 +      VMS_int__return_to_addr_in_ptd_to_loc(
   1.324 +                         &((semEnv->fnSingletons[singletonID]).savedRetAddr) );
   1.325 +    }
   1.326 + }
   1.327 +
   1.328 +/*Data singleton hands addr of loc holding a pointer to a singleton struct.
   1.329 + * The start_data_singleton makes the structure and puts its addr into the
   1.330 + * location.
   1.331 + */
   1.332 +void
   1.333 +Vthread__start_data_singleton( VthdSingleton *singleton,  SlaveVP *animSlv )
   1.334 + {
   1.335 +   VthdSemReq  reqData;
   1.336 +
   1.337 +   if( singleton->savedRetAddr && singleton->hasFinished )
   1.338 +      goto JmpToEndSingleton;
   1.339 +      
   1.340 +   reqData.reqType       = singleton_data_start;
   1.341 +   reqData.singleton = singleton;
   1.342 +
   1.343 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.344 +   if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr
   1.345 +    {    
   1.346 +       JmpToEndSingleton:
   1.347 +       VMS_int__return_to_addr_in_ptd_to_loc(&(singleton->savedRetAddr));
   1.348 +    }
   1.349 +   //now, simply return
   1.350 +   //will exit either from the start singleton call or the end-singleton call
   1.351 + }
   1.352 +
   1.353 +/*Uses ID as index into array of flags.  If flag already set, resumes from
   1.354 + * end-label.  Else, sets flag and resumes normally.
   1.355 + *
   1.356 + *Note, this call cannot be inlined because the instr addr at the label
   1.357 + * inside is shared by all invocations of a given singleton ID.
   1.358 + */
   1.359 +void
   1.360 +Vthread__end_fn_singleton( int32 singletonID, SlaveVP *animSlv )
   1.361 + {
   1.362 +   VthdSemReq  reqData;
   1.363 +
   1.364 +   //don't need this addr until after at least one singleton has reached
   1.365 +   // this function
   1.366 +   VthdSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv );
   1.367 +   VMS_int__return_to_addr_in_ptd_to_loc(
   1.368 +                         &((semEnv->fnSingletons[singletonID]).savedRetAddr) );
   1.369 +
   1.370 +   reqData.reqType     = singleton_fn_end;
   1.371 +   reqData.singletonID = singletonID;
   1.372 +
   1.373 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.374 + }
   1.375 +
   1.376 +void
   1.377 +Vthread__end_data_singleton( VthdSingleton *singleton, SlaveVP *animSlv )
   1.378 + {
   1.379 +   VthdSemReq  reqData;
   1.380 +
   1.381 +      //don't need this addr until after singleton struct has reached
   1.382 +      // this function for first time
   1.383 +      //do assembly that saves the return addr of this fn call into the
   1.384 +      // data singleton -- that data-singleton can only be given to exactly
   1.385 +      // one instance in the code of this function.  However, can use this
   1.386 +      // function in different places for different data-singletons.
   1.387 +
   1.388 +   VMS_int__save_return_into_ptd_to_loc_then_do_ret(&(singleton->savedRetAddr));
   1.389 +
   1.390 +   reqData.reqType    = singleton_data_end;
   1.391 +   reqData.singleton  = singleton;
   1.392 +
   1.393 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.394 + }
   1.395 +
   1.396 +
   1.397 +/*This executes the function in the masterVP, so it executes in isolation
   1.398 + * from any other copies -- only one copy of the function can ever execute
   1.399 + * at a time.
   1.400 + *
   1.401 + *It suspends to the master, and the request handler takes the function
   1.402 + * pointer out of the request and calls it, then resumes the Slv.
   1.403 + *Only very short functions should be called this way -- for longer-running
   1.404 + * isolation, use transaction-start and transaction-end, which run the code
   1.405 + * between as work-code.
   1.406 + */
   1.407 +void
   1.408 +Vthread__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
   1.409 +                                    void *data, SlaveVP *animSlv )
   1.410 + {
   1.411 +   VthdSemReq  reqData;
   1.412 +
   1.413 +      //
   1.414 +   reqData.reqType          = atomic;
   1.415 +   reqData.fnToExecInMaster = ptrToFnToExecInMaster;
   1.416 +   reqData.dataForFn        = data;
   1.417 +
   1.418 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.419 + }
   1.420 +
   1.421 +
   1.422 +/*This suspends to the master.
   1.423 + *First, it looks at the Slv's data, to see the highest transactionID that Slv
   1.424 + * already has entered.  If the current ID is not larger, it throws an
   1.425 + * exception stating a bug in the code.  Otherwise it puts the current ID
   1.426 + * there, and adds the ID to a linked list of IDs entered -- the list is
   1.427 + * used to check that exits are properly ordered.
   1.428 + *Next it is uses transactionID as index into an array of transaction
   1.429 + * structures.
   1.430 + *If the "Slv_currently_executing" field is non-null, then put requesting Slv
   1.431 + * into queue in the struct.  (At some point a holder will request
   1.432 + * end-transaction, which will take this Slv from the queue and resume it.)
   1.433 + *If NULL, then write requesting into the field and resume.
   1.434 + */
   1.435 +void
   1.436 +Vthread__start_transaction( int32 transactionID, SlaveVP *animSlv )
   1.437 + {
   1.438 +   VthdSemReq  reqData;
   1.439 +
   1.440 +      //
   1.441 +   reqData.reqType     = trans_start;
   1.442 +   reqData.transID     = transactionID;
   1.443 +
   1.444 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.445 + }
   1.446 +
   1.447 +/*This suspends to the master, then uses transactionID as index into an
   1.448 + * array of transaction structures.
   1.449 + *It looks at Slv_currently_executing to be sure it's same as requesting Slv.
   1.450 + * If different, throws an exception, stating there's a bug in the code.
   1.451 + *Next it looks at the queue in the structure.
   1.452 + *If it's empty, it sets Slv_currently_executing field to NULL and resumes.
   1.453 + *If something in, gets it, sets Slv_currently_executing to that Slv, then
   1.454 + * resumes both.
   1.455 + */
   1.456 +void
   1.457 +Vthread__end_transaction( int32 transactionID, SlaveVP *animSlv )
   1.458 + {
   1.459 +   VthdSemReq  reqData;
   1.460 +
   1.461 +      //
   1.462 +   reqData.reqType     = trans_end;
   1.463 +   reqData.transID     = transactionID;
   1.464 +
   1.465 +   VMS_WL__send_sem_request( &reqData, animSlv );
   1.466 + }
   1.467 +//===========================================================================