Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > Vthread_impls > Vthread_MC_shared_impl
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 +//===========================================================================
