Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > Vthread_impls > Vthread_MC_shared_impl
comparison 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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:5344d3e0235f |
|---|---|
| 1 /* | |
| 2 * Copyright 2010 OpenSourceCodeStewardshipFoundation | |
| 3 * | |
| 4 * Licensed under BSD | |
| 5 */ | |
| 6 | |
| 7 #include <stdio.h> | |
| 8 #include <stdlib.h> | |
| 9 | |
| 10 #include "VMS_impl/VMS.h" | |
| 11 #include "Vthread.h" | |
| 12 #include "Vthread_helper.h" | |
| 13 #include "C_Libraries/Queue_impl/PrivateQueue.h" | |
| 14 #include "C_Libraries/Hash_impl/PrivateHash.h" | |
| 15 | |
| 16 | |
| 17 //========================================================================== | |
| 18 | |
| 19 void | |
| 20 Vthread__init(); | |
| 21 | |
| 22 void | |
| 23 Vthread__init_Seq(); | |
| 24 | |
| 25 void | |
| 26 Vthread__init_Helper(); | |
| 27 | |
| 28 | |
| 29 //=========================================================================== | |
| 30 | |
| 31 /*These are the library functions *called in the application* | |
| 32 * | |
| 33 */ | |
| 34 | |
| 35 | |
| 36 | |
| 37 //=========================================================================== | |
| 38 | |
| 39 inline int32 | |
| 40 Vthread__giveMinWorkUnitCycles( float32 percentOverhead ) | |
| 41 { | |
| 42 return MIN_WORK_UNIT_CYCLES; | |
| 43 } | |
| 44 | |
| 45 inline int32 | |
| 46 Vthread__giveIdealNumWorkUnits() | |
| 47 { | |
| 48 return NUM_SCHED_SLOTS * NUM_CORES; | |
| 49 } | |
| 50 | |
| 51 inline int32 | |
| 52 Vthread__give_number_of_cores_to_schedule_onto() | |
| 53 { | |
| 54 return NUM_CORES; | |
| 55 } | |
| 56 | |
| 57 /*For now, use TSC -- later, make these two macros with assembly that first | |
| 58 * saves jump point, and second jumps back several times to get reliable time | |
| 59 */ | |
| 60 inline void | |
| 61 Vthread__start_primitive() | |
| 62 { saveLowTimeStampCountInto( ((VthdSemEnv *)(_VMSMasterEnv->semanticEnv))-> | |
| 63 primitiveStartTime ); | |
| 64 } | |
| 65 | |
| 66 /*Just quick and dirty for now -- make reliable later | |
| 67 * will want this to jump back several times -- to be sure cache is warm | |
| 68 * because don't want comm time included in calc-time measurement -- and | |
| 69 * also to throw out any "weird" values due to OS interrupt or TSC rollover | |
| 70 */ | |
| 71 inline int32 | |
| 72 Vthread__end_primitive_and_give_cycles() | |
| 73 { int32 endTime, startTime; | |
| 74 //TODO: fix by repeating time-measurement | |
| 75 saveLowTimeStampCountInto( endTime ); | |
| 76 startTime=((VthdSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime; | |
| 77 return (endTime - startTime); | |
| 78 } | |
| 79 | |
| 80 | |
| 81 | |
| 82 //=========================================================================== | |
| 83 | |
| 84 /*Re-use this in the entry-point fn | |
| 85 */ | |
| 86 inline SlaveVP * | |
| 87 Vthread__create_slaveVP_helper( TopLevelFnPtr fnPtr, void *initData, | |
| 88 VthdSemEnv *semEnv, int32 coreToScheduleOnto ) | |
| 89 { SlaveVP *newSlv; | |
| 90 VthdSemData *semData; | |
| 91 | |
| 92 //This is running in master, so use internal version | |
| 93 newSlv = VMS_WL__create_slaveVP( fnPtr, initData ); | |
| 94 | |
| 95 semData = VMS_WL__malloc( sizeof(VthdSemData) ); | |
| 96 semData->highestTransEntered = -1; | |
| 97 semData->lastTransEntered = NULL; | |
| 98 | |
| 99 newSlv->semanticData = semData; | |
| 100 | |
| 101 //=================== Assign new processor to a core ===================== | |
| 102 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE | |
| 103 newSlv->coreAnimatedBy = 0; | |
| 104 | |
| 105 #else | |
| 106 | |
| 107 if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES ) | |
| 108 { //out-of-range, so round-robin assignment | |
| 109 newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv; | |
| 110 | |
| 111 if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 ) | |
| 112 semEnv->nextCoreToGetNewSlv = 0; | |
| 113 else | |
| 114 semEnv->nextCoreToGetNewSlv += 1; | |
| 115 } | |
| 116 else //core num in-range, so use it | |
| 117 { newSlv->coreAnimatedBy = coreToScheduleOnto; | |
| 118 } | |
| 119 #endif | |
| 120 //======================================================================== | |
| 121 | |
| 122 return newSlv; | |
| 123 } | |
| 124 | |
| 125 | |
| 126 /* | |
| 127 */ | |
| 128 inline SlaveVP * | |
| 129 Vthread__create_thread( TopLevelFnPtr fnPtr, void *initData, | |
| 130 SlaveVP *creatingSlv ) | |
| 131 { VthdSemReq reqData; | |
| 132 | |
| 133 //the semantic request data is on the stack and disappears when this | |
| 134 // call returns -- it's guaranteed to remain in the Slv's stack for as | |
| 135 // long as the Slv is suspended. | |
| 136 reqData.reqType = 0; //know the type because is a VMS create req | |
| 137 reqData.coreToScheduleOnto = -1; //means round-robin schedule | |
| 138 reqData.fnPtr = fnPtr; | |
| 139 reqData.initData = initData; | |
| 140 reqData.requestingSlv = creatingSlv; | |
| 141 | |
| 142 VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv ); | |
| 143 | |
| 144 return creatingSlv->dataRetFromReq; | |
| 145 } | |
| 146 | |
| 147 | |
| 148 inline SlaveVP * | |
| 149 Vthread__create_thread_with_affinity( TopLevelFnPtr fnPtr, void *initData, | |
| 150 SlaveVP *creatingSlv, int32 coreToScheduleOnto ) | |
| 151 { VthdSemReq reqData; | |
| 152 | |
| 153 //the semantic request data is on the stack and disappears when this | |
| 154 // call returns -- it's guaranteed to remain in the Slv's stack for as | |
| 155 // long as the Slv is suspended. | |
| 156 reqData.reqType = 0; //know type because in a VMS create req | |
| 157 reqData.coreToScheduleOnto = coreToScheduleOnto; | |
| 158 reqData.fnPtr = fnPtr; | |
| 159 reqData.initData = initData; | |
| 160 reqData.requestingSlv = creatingSlv; | |
| 161 | |
| 162 VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv ); | |
| 163 } | |
| 164 | |
| 165 inline void | |
| 166 Vthread__dissipate_thread( SlaveVP *procrToDissipate ) | |
| 167 { | |
| 168 VMS_WL__send_dissipate_req( procrToDissipate ); | |
| 169 } | |
| 170 | |
| 171 | |
| 172 //=========================================================================== | |
| 173 | |
| 174 void * | |
| 175 Vthread__malloc( size_t sizeToMalloc, SlaveVP *animSlv ) | |
| 176 { VthdSemReq reqData; | |
| 177 | |
| 178 reqData.reqType = malloc_req; | |
| 179 reqData.sizeToMalloc = sizeToMalloc; | |
| 180 reqData.requestingSlv = animSlv; | |
| 181 | |
| 182 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 183 | |
| 184 return animSlv->dataRetFromReq; | |
| 185 } | |
| 186 | |
| 187 | |
| 188 /*Sends request to Master, which does the work of freeing | |
| 189 */ | |
| 190 void | |
| 191 Vthread__free( void *ptrToFree, SlaveVP *animSlv ) | |
| 192 { VthdSemReq reqData; | |
| 193 | |
| 194 reqData.reqType = free_req; | |
| 195 reqData.ptrToFree = ptrToFree; | |
| 196 reqData.requestingSlv = animSlv; | |
| 197 | |
| 198 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 199 } | |
| 200 | |
| 201 | |
| 202 //=========================================================================== | |
| 203 | |
| 204 inline void | |
| 205 Vthread__set_globals_to( void *globals ) | |
| 206 { | |
| 207 ((VthdSemEnv *) | |
| 208 (_VMSMasterEnv->semanticEnv))->applicationGlobals = globals; | |
| 209 } | |
| 210 | |
| 211 inline void * | |
| 212 Vthread__give_globals() | |
| 213 { | |
| 214 return((VthdSemEnv *) (_VMSMasterEnv->semanticEnv))->applicationGlobals; | |
| 215 } | |
| 216 | |
| 217 | |
| 218 //=========================================================================== | |
| 219 | |
| 220 inline int32 | |
| 221 Vthread__make_mutex( SlaveVP *animSlv ) | |
| 222 { VthdSemReq reqData; | |
| 223 | |
| 224 reqData.reqType = make_mutex; | |
| 225 reqData.requestingSlv = animSlv; | |
| 226 | |
| 227 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 228 | |
| 229 return (int32)animSlv->dataRetFromReq; //mutexid is 32bit wide | |
| 230 } | |
| 231 | |
| 232 inline void | |
| 233 Vthread__mutex_lock( int32 mutexIdx, SlaveVP *acquiringSlv ) | |
| 234 { VthdSemReq reqData; | |
| 235 | |
| 236 reqData.reqType = mutex_lock; | |
| 237 reqData.mutexIdx = mutexIdx; | |
| 238 reqData.requestingSlv = acquiringSlv; | |
| 239 | |
| 240 VMS_WL__send_sem_request( &reqData, acquiringSlv ); | |
| 241 } | |
| 242 | |
| 243 inline void | |
| 244 Vthread__mutex_unlock( int32 mutexIdx, SlaveVP *releasingSlv ) | |
| 245 { VthdSemReq reqData; | |
| 246 | |
| 247 reqData.reqType = mutex_unlock; | |
| 248 reqData.mutexIdx = mutexIdx; | |
| 249 reqData.requestingSlv = releasingSlv; | |
| 250 | |
| 251 VMS_WL__send_sem_request( &reqData, releasingSlv ); | |
| 252 } | |
| 253 | |
| 254 | |
| 255 //======================= | |
| 256 inline int32 | |
| 257 Vthread__make_cond( int32 ownedMutexIdx, SlaveVP *animSlv) | |
| 258 { VthdSemReq reqData; | |
| 259 | |
| 260 reqData.reqType = make_cond; | |
| 261 reqData.mutexIdx = ownedMutexIdx; | |
| 262 reqData.requestingSlv = animSlv; | |
| 263 | |
| 264 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 265 | |
| 266 return (int32)animSlv->dataRetFromReq; //condIdx is 32 bit wide | |
| 267 } | |
| 268 | |
| 269 inline void | |
| 270 Vthread__cond_wait( int32 condIdx, SlaveVP *waitingSlv) | |
| 271 { VthdSemReq reqData; | |
| 272 | |
| 273 reqData.reqType = cond_wait; | |
| 274 reqData.condIdx = condIdx; | |
| 275 reqData.requestingSlv = waitingSlv; | |
| 276 | |
| 277 VMS_WL__send_sem_request( &reqData, waitingSlv ); | |
| 278 } | |
| 279 | |
| 280 inline void * | |
| 281 Vthread__cond_signal( int32 condIdx, SlaveVP *signallingSlv ) | |
| 282 { VthdSemReq reqData; | |
| 283 | |
| 284 reqData.reqType = cond_signal; | |
| 285 reqData.condIdx = condIdx; | |
| 286 reqData.requestingSlv = signallingSlv; | |
| 287 | |
| 288 VMS_WL__send_sem_request( &reqData, signallingSlv ); | |
| 289 } | |
| 290 | |
| 291 | |
| 292 //=========================================================================== | |
| 293 // | |
| 294 /*A function singleton is a function whose body executes exactly once, on a | |
| 295 * single core, no matter how many times the fuction is called and no | |
| 296 * matter how many cores or the timing of cores calling it. | |
| 297 * | |
| 298 *A data singleton is a ticket attached to data. That ticket can be used | |
| 299 * to get the data through the function exactly once, no matter how many | |
| 300 * times the data is given to the function, and no matter the timing of | |
| 301 * trying to get the data through from different cores. | |
| 302 */ | |
| 303 | |
| 304 /*Fn singleton uses ID as index into array of singleton structs held in the | |
| 305 * semantic environment. | |
| 306 */ | |
| 307 void | |
| 308 Vthread__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ) | |
| 309 { | |
| 310 VthdSemReq reqData; | |
| 311 | |
| 312 // | |
| 313 reqData.reqType = singleton_fn_start; | |
| 314 reqData.singletonID = singletonID; | |
| 315 | |
| 316 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 317 if( animSlv->dataRetFromReq != 0 ) //addr of matching end-singleton | |
| 318 { | |
| 319 VthdSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); //not protected! | |
| 320 VMS_int__return_to_addr_in_ptd_to_loc( | |
| 321 &((semEnv->fnSingletons[singletonID]).savedRetAddr) ); | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 /*Data singleton hands addr of loc holding a pointer to a singleton struct. | |
| 326 * The start_data_singleton makes the structure and puts its addr into the | |
| 327 * location. | |
| 328 */ | |
| 329 void | |
| 330 Vthread__start_data_singleton( VthdSingleton *singleton, SlaveVP *animSlv ) | |
| 331 { | |
| 332 VthdSemReq reqData; | |
| 333 | |
| 334 if( singleton->savedRetAddr && singleton->hasFinished ) | |
| 335 goto JmpToEndSingleton; | |
| 336 | |
| 337 reqData.reqType = singleton_data_start; | |
| 338 reqData.singleton = singleton; | |
| 339 | |
| 340 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 341 if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr | |
| 342 { | |
| 343 JmpToEndSingleton: | |
| 344 VMS_int__return_to_addr_in_ptd_to_loc(&(singleton->savedRetAddr)); | |
| 345 } | |
| 346 //now, simply return | |
| 347 //will exit either from the start singleton call or the end-singleton call | |
| 348 } | |
| 349 | |
| 350 /*Uses ID as index into array of flags. If flag already set, resumes from | |
| 351 * end-label. Else, sets flag and resumes normally. | |
| 352 * | |
| 353 *Note, this call cannot be inlined because the instr addr at the label | |
| 354 * inside is shared by all invocations of a given singleton ID. | |
| 355 */ | |
| 356 void | |
| 357 Vthread__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ) | |
| 358 { | |
| 359 VthdSemReq reqData; | |
| 360 | |
| 361 //don't need this addr until after at least one singleton has reached | |
| 362 // this function | |
| 363 VthdSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); | |
| 364 VMS_int__return_to_addr_in_ptd_to_loc( | |
| 365 &((semEnv->fnSingletons[singletonID]).savedRetAddr) ); | |
| 366 | |
| 367 reqData.reqType = singleton_fn_end; | |
| 368 reqData.singletonID = singletonID; | |
| 369 | |
| 370 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 371 } | |
| 372 | |
| 373 void | |
| 374 Vthread__end_data_singleton( VthdSingleton *singleton, SlaveVP *animSlv ) | |
| 375 { | |
| 376 VthdSemReq reqData; | |
| 377 | |
| 378 //don't need this addr until after singleton struct has reached | |
| 379 // this function for first time | |
| 380 //do assembly that saves the return addr of this fn call into the | |
| 381 // data singleton -- that data-singleton can only be given to exactly | |
| 382 // one instance in the code of this function. However, can use this | |
| 383 // function in different places for different data-singletons. | |
| 384 | |
| 385 VMS_int__save_return_into_ptd_to_loc_then_do_ret(&(singleton->savedRetAddr)); | |
| 386 | |
| 387 reqData.reqType = singleton_data_end; | |
| 388 reqData.singleton = singleton; | |
| 389 | |
| 390 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 391 } | |
| 392 | |
| 393 | |
| 394 /*This executes the function in the masterVP, so it executes in isolation | |
| 395 * from any other copies -- only one copy of the function can ever execute | |
| 396 * at a time. | |
| 397 * | |
| 398 *It suspends to the master, and the request handler takes the function | |
| 399 * pointer out of the request and calls it, then resumes the Slv. | |
| 400 *Only very short functions should be called this way -- for longer-running | |
| 401 * isolation, use transaction-start and transaction-end, which run the code | |
| 402 * between as work-code. | |
| 403 */ | |
| 404 void | |
| 405 Vthread__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, | |
| 406 void *data, SlaveVP *animSlv ) | |
| 407 { | |
| 408 VthdSemReq reqData; | |
| 409 | |
| 410 // | |
| 411 reqData.reqType = atomic; | |
| 412 reqData.fnToExecInMaster = ptrToFnToExecInMaster; | |
| 413 reqData.dataForFn = data; | |
| 414 | |
| 415 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 416 } | |
| 417 | |
| 418 | |
| 419 /*This suspends to the master. | |
| 420 *First, it looks at the Slv's data, to see the highest transactionID that Slv | |
| 421 * already has entered. If the current ID is not larger, it throws an | |
| 422 * exception stating a bug in the code. Otherwise it puts the current ID | |
| 423 * there, and adds the ID to a linked list of IDs entered -- the list is | |
| 424 * used to check that exits are properly ordered. | |
| 425 *Next it is uses transactionID as index into an array of transaction | |
| 426 * structures. | |
| 427 *If the "Slv_currently_executing" field is non-null, then put requesting Slv | |
| 428 * into queue in the struct. (At some point a holder will request | |
| 429 * end-transaction, which will take this Slv from the queue and resume it.) | |
| 430 *If NULL, then write requesting into the field and resume. | |
| 431 */ | |
| 432 void | |
| 433 Vthread__start_transaction( int32 transactionID, SlaveVP *animSlv ) | |
| 434 { | |
| 435 VthdSemReq reqData; | |
| 436 | |
| 437 // | |
| 438 reqData.reqType = trans_start; | |
| 439 reqData.transID = transactionID; | |
| 440 | |
| 441 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 442 } | |
| 443 | |
| 444 /*This suspends to the master, then uses transactionID as index into an | |
| 445 * array of transaction structures. | |
| 446 *It looks at Slv_currently_executing to be sure it's same as requesting Slv. | |
| 447 * If different, throws an exception, stating there's a bug in the code. | |
| 448 *Next it looks at the queue in the structure. | |
| 449 *If it's empty, it sets Slv_currently_executing field to NULL and resumes. | |
| 450 *If something in, gets it, sets Slv_currently_executing to that Slv, then | |
| 451 * resumes both. | |
| 452 */ | |
| 453 void | |
| 454 Vthread__end_transaction( int32 transactionID, SlaveVP *animSlv ) | |
| 455 { | |
| 456 VthdSemReq reqData; | |
| 457 | |
| 458 // | |
| 459 reqData.reqType = trans_end; | |
| 460 reqData.transID = transactionID; | |
| 461 | |
| 462 VMS_WL__send_sem_request( &reqData, animSlv ); | |
| 463 } | |
| 464 //=========================================================================== |
