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