Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > SSR_impls > SSR__MC_shared_impl
comparison SSR.c @ 64:bd5ab695145c
MEAS__ macros for language added, and renamed a few things
| author | Some Random Person <seanhalle@yahoo.com> |
|---|---|
| date | Tue, 13 Mar 2012 18:30:05 -0700 |
| parents | |
| children | ce95c4d84fcd b5b5323b4177 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:c0ecedfe9a17 |
|---|---|
| 1 /* | |
| 2 * Copyright 2010 OpenSourceCodeStewardshipFoundation | |
| 3 * | |
| 4 * Licensed under BSD | |
| 5 */ | |
| 6 | |
| 7 #include <stdio.h> | |
| 8 #include <stdlib.h> | |
| 9 #include <malloc.h> | |
| 10 | |
| 11 #include "Queue_impl/PrivateQueue.h" | |
| 12 #include "Hash_impl/PrivateHash.h" | |
| 13 | |
| 14 #include "SSR.h" | |
| 15 #include "SSR_Counter_Recording.h" | |
| 16 | |
| 17 //========================================================================== | |
| 18 | |
| 19 void | |
| 20 SSR__init(); | |
| 21 | |
| 22 void | |
| 23 SSR__init_Helper(); | |
| 24 //========================================================================== | |
| 25 | |
| 26 | |
| 27 /*TODO: Q: dealing with library f()s and DKU vs WT vs FoR | |
| 28 * (still want to do FoR, with time-lines as syntax, could be super cool) | |
| 29 * A: thinking pin the coreCtlrs for all of BLIS -- let Master arbitrate | |
| 30 * among library, DKU, WT, FoR -- all the patterns in terms of virtual | |
| 31 * processors (or equivalently work-units), so Master picks which virt procr | |
| 32 * from which portions of app (DKU, WT, FoR) onto which sched slots | |
| 33 *Might even do hierarchy of masters -- group of sched slots for each core | |
| 34 * has its own master, that keeps generated work local | |
| 35 * single-reader-single-writer sync everywhere -- no atomic primitives | |
| 36 * Might have the different assigners talk to each other, to negotiate | |
| 37 * larger-grain sharing of resources, according to predicted critical | |
| 38 * path, and expansion of work | |
| 39 */ | |
| 40 | |
| 41 | |
| 42 | |
| 43 //=========================================================================== | |
| 44 | |
| 45 | |
| 46 /*These are the library functions *called in the application* | |
| 47 * | |
| 48 *There's a pattern for the outside sequential code to interact with the | |
| 49 * VMS_HW code. | |
| 50 *The VMS_HW system is inside a boundary.. every SSR system is in its | |
| 51 * own directory that contains the functions for each of the processor types. | |
| 52 * One of the processor types is the "seed" processor that starts the | |
| 53 * cascade of creating all the processors that do the work. | |
| 54 *So, in the directory is a file called "EntryPoint.c" that contains the | |
| 55 * function, named appropriately to the work performed, that the outside | |
| 56 * sequential code calls. This function follows a pattern: | |
| 57 *1) it calls SSR__init() | |
| 58 *2) it creates the initial data for the seed processor, which is passed | |
| 59 * in to the function | |
| 60 *3) it creates the seed SSR processor, with the data to start it with. | |
| 61 *4) it calls startSSRThenWaitUntilWorkDone | |
| 62 *5) it gets the returnValue from the transfer struc and returns that | |
| 63 * from the function | |
| 64 * | |
| 65 *For now, a new SSR system has to be created via SSR__init every | |
| 66 * time an entry point function is called -- later, might add letting the | |
| 67 * SSR system be created once, and let all the entry points just reuse | |
| 68 * it -- want to be as simple as possible now, and see by using what makes | |
| 69 * sense for later.. | |
| 70 */ | |
| 71 | |
| 72 | |
| 73 | |
| 74 //=========================================================================== | |
| 75 | |
| 76 /*This is the "border crossing" function -- the thing that crosses from the | |
| 77 * outside world, into the VMS_HW world. It initializes and starts up the | |
| 78 * VMS system, then creates one processor from the specified function and | |
| 79 * puts it into the readyQ. From that point, that one function is resp. | |
| 80 * for creating all the other processors, that then create others, and so | |
| 81 * forth. | |
| 82 *When all the processors, including the seed, have dissipated, then this | |
| 83 * function returns. The results will have been written by side-effect via | |
| 84 * pointers read from, or written into initData. | |
| 85 * | |
| 86 *NOTE: no Threads should exist in the outside program that might touch | |
| 87 * any of the data reachable from initData passed in to here | |
| 88 */ | |
| 89 void | |
| 90 SSR__create_seed_procr_and_do_work( TopLevelFnPtr fnPtr, void *initData ) | |
| 91 { SSRSemEnv *semEnv; | |
| 92 SlaveVP *seedPr; | |
| 93 | |
| 94 SSR__init(); //normal multi-thd | |
| 95 | |
| 96 semEnv = _VMSMasterEnv->semanticEnv; | |
| 97 | |
| 98 //SSR starts with one processor, which is put into initial environ, | |
| 99 // and which then calls create() to create more, thereby expanding work | |
| 100 seedPr = SSR__create_procr_helper( fnPtr, initData, | |
| 101 semEnv, semEnv->nextCoreToGetNewPr++ ); | |
| 102 | |
| 103 resume_slaveVP( seedPr, semEnv ); | |
| 104 | |
| 105 VMS_SS__start_the_work_then_wait_until_done(); //normal multi-thd | |
| 106 | |
| 107 SSR__cleanup_after_shutdown(); | |
| 108 } | |
| 109 | |
| 110 | |
| 111 int32 | |
| 112 SSR__giveMinWorkUnitCycles( float32 percentOverhead ) | |
| 113 { | |
| 114 return MIN_WORK_UNIT_CYCLES; | |
| 115 } | |
| 116 | |
| 117 int32 | |
| 118 SSR__giveIdealNumWorkUnits() | |
| 119 { | |
| 120 return NUM_SCHED_SLOTS * NUM_CORES; | |
| 121 } | |
| 122 | |
| 123 int32 | |
| 124 SSR__give_number_of_cores_to_schedule_onto() | |
| 125 { | |
| 126 return NUM_CORES; | |
| 127 } | |
| 128 | |
| 129 /*For now, use TSC -- later, make these two macros with assembly that first | |
| 130 * saves jump point, and second jumps back several times to get reliable time | |
| 131 */ | |
| 132 void | |
| 133 SSR__start_primitive() | |
| 134 { saveLowTimeStampCountInto( ((SSRSemEnv *)(_VMSMasterEnv->semanticEnv))-> | |
| 135 primitiveStartTime ); | |
| 136 } | |
| 137 | |
| 138 /*Just quick and dirty for now -- make reliable later | |
| 139 * will want this to jump back several times -- to be sure cache is warm | |
| 140 * because don't want comm time included in calc-time measurement -- and | |
| 141 * also to throw out any "weird" values due to OS interrupt or TSC rollover | |
| 142 */ | |
| 143 int32 | |
| 144 SSR__end_primitive_and_give_cycles() | |
| 145 { int32 endTime, startTime; | |
| 146 //TODO: fix by repeating time-measurement | |
| 147 saveLowTimeStampCountInto( endTime ); | |
| 148 startTime =((SSRSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime; | |
| 149 return (endTime - startTime); | |
| 150 } | |
| 151 | |
| 152 //=========================================================================== | |
| 153 | |
| 154 /*Initializes all the data-structures for a SSR system -- but doesn't | |
| 155 * start it running yet! | |
| 156 * | |
| 157 *This runs in the main thread -- before VMS starts up | |
| 158 * | |
| 159 *This sets up the semantic layer over the VMS system | |
| 160 * | |
| 161 *First, calls VMS_Setup, then creates own environment, making it ready | |
| 162 * for creating the seed processor and then starting the work. | |
| 163 */ | |
| 164 void | |
| 165 SSR__init() | |
| 166 { | |
| 167 VMS_SS__init(); | |
| 168 //masterEnv, a global var, now is partially set up by init_VMS | |
| 169 // after this, have VMS_int__malloc and VMS_int__free available | |
| 170 | |
| 171 SSR__init_Helper(); | |
| 172 } | |
| 173 | |
| 174 | |
| 175 void idle_fn(void* data, SlaveVP *animatingSlv){ | |
| 176 while(1){ | |
| 177 VMS_int__suspend_slaveVP_and_send_req(animatingSlv); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 void | |
| 182 SSR__init_Helper() | |
| 183 { SSRSemEnv *semanticEnv; | |
| 184 PrivQueueStruc **readyVPQs; | |
| 185 int coreIdx, i, j; | |
| 186 | |
| 187 //Hook up the semantic layer's plug-ins to the Master virt procr | |
| 188 _VMSMasterEnv->requestHandler = &SSR__Request_Handler; | |
| 189 _VMSMasterEnv->slaveAssigner = &SSR__assign_slaveVP; | |
| 190 #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS | |
| 191 _VMSMasterEnv->counterHandler = &SSR__counter_handler; | |
| 192 #endif | |
| 193 | |
| 194 //create the semantic layer's environment (all its data) and add to | |
| 195 // the master environment | |
| 196 semanticEnv = VMS_int__malloc( sizeof( SSRSemEnv ) ); | |
| 197 _VMSMasterEnv->semanticEnv = semanticEnv; | |
| 198 | |
| 199 #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS | |
| 200 SSR__init_counter_data_structs(); | |
| 201 #endif | |
| 202 for(i=0;i<NUM_CORES;++i){ | |
| 203 for(j=0;j<NUM_SCHED_SLOTS;++j){ | |
| 204 semanticEnv->idlePr[i][j] = VMS_int__create_slaveVP(&idle_fn,NULL); | |
| 205 semanticEnv->idlePr[i][j]->coreAnimatedBy = i; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC | |
| 210 semanticEnv->unitList = makeListOfArrays(sizeof(Unit),128); | |
| 211 semanticEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); | |
| 212 semanticEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); | |
| 213 semanticEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); | |
| 214 semanticEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semanticEnv->ntonGroups),8); | |
| 215 | |
| 216 semanticEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); | |
| 217 memset(semanticEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_SCHED_SLOTS * sizeof(Unit))); | |
| 218 #endif | |
| 219 | |
| 220 //create the ready queue, hash tables used for pairing send to receive | |
| 221 // and so forth | |
| 222 //TODO: add hash tables for pairing sends with receives, and | |
| 223 // initialize the data ownership system | |
| 224 readyVPQs = VMS_int__malloc( NUM_CORES * sizeof(PrivQueueStruc *) ); | |
| 225 | |
| 226 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) | |
| 227 { | |
| 228 readyVPQs[ coreIdx ] = makeVMSQ(); | |
| 229 } | |
| 230 | |
| 231 semanticEnv->readyVPQs = readyVPQs; | |
| 232 | |
| 233 semanticEnv->nextCoreToGetNewPr = 0; | |
| 234 semanticEnv->numSlaveVP = 0; | |
| 235 | |
| 236 semanticEnv->commHashTbl = makeHashTable( 1<<16, &VMS_int__free );//start big | |
| 237 | |
| 238 //TODO: bug -- turn these arrays into dyn arrays to eliminate limit | |
| 239 //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); | |
| 240 //semanticEnv->transactionStrucs = makeDynArrayInfo( ); | |
| 241 for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) | |
| 242 { | |
| 243 semanticEnv->fnSingletons[i].endInstrAddr = NULL; | |
| 244 semanticEnv->fnSingletons[i].hasBeenStarted = FALSE; | |
| 245 semanticEnv->fnSingletons[i].hasFinished = FALSE; | |
| 246 semanticEnv->fnSingletons[i].waitQ = makeVMSQ(); | |
| 247 semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSQ(); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 | |
| 252 /*Frees any memory allocated by SSR__init() then calls VMS_int__shutdown | |
| 253 */ | |
| 254 void | |
| 255 SSR__cleanup_after_shutdown() | |
| 256 { SSRSemEnv *semanticEnv; | |
| 257 | |
| 258 semanticEnv = _VMSMasterEnv->semanticEnv; | |
| 259 | |
| 260 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC | |
| 261 //UCC | |
| 262 FILE* output; | |
| 263 int n; | |
| 264 char filename[255]; | |
| 265 for(n=0;n<255;n++) | |
| 266 { | |
| 267 sprintf(filename, "./counters/UCC.%d",n); | |
| 268 output = fopen(filename,"r"); | |
| 269 if(output) | |
| 270 { | |
| 271 fclose(output); | |
| 272 }else{ | |
| 273 break; | |
| 274 } | |
| 275 } | |
| 276 if(n<255){ | |
| 277 printf("Saving UCC to File: %s ...\n", filename); | |
| 278 output = fopen(filename,"w+"); | |
| 279 if(output!=NULL){ | |
| 280 set_dependency_file(output); | |
| 281 //fprintf(output,"digraph Dependencies {\n"); | |
| 282 //set_dot_file(output); | |
| 283 //FIXME: first line still depends on counters being enabled, replace w/ unit struct! | |
| 284 //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); | |
| 285 forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file); | |
| 286 forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); | |
| 287 forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); | |
| 288 forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file); | |
| 289 //fprintf(output,"}\n"); | |
| 290 fflush(output); | |
| 291 | |
| 292 } else | |
| 293 printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); | |
| 294 } else { | |
| 295 printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); | |
| 296 } | |
| 297 //Loop Graph | |
| 298 for(n=0;n<255;n++) | |
| 299 { | |
| 300 sprintf(filename, "./counters/LoopGraph.%d",n); | |
| 301 output = fopen(filename,"r"); | |
| 302 if(output) | |
| 303 { | |
| 304 fclose(output); | |
| 305 }else{ | |
| 306 break; | |
| 307 } | |
| 308 } | |
| 309 if(n<255){ | |
| 310 printf("Saving LoopGraph to File: %s ...\n", filename); | |
| 311 output = fopen(filename,"w+"); | |
| 312 if(output!=NULL){ | |
| 313 set_dependency_file(output); | |
| 314 //fprintf(output,"digraph Dependencies {\n"); | |
| 315 //set_dot_file(output); | |
| 316 //FIXME: first line still depends on counters being enabled, replace w/ unit struct! | |
| 317 //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); | |
| 318 forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file ); | |
| 319 forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); | |
| 320 forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); | |
| 321 forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file ); | |
| 322 forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file ); | |
| 323 //fprintf(output,"}\n"); | |
| 324 fflush(output); | |
| 325 | |
| 326 } else | |
| 327 printf("Opening LoopGraph file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); | |
| 328 } else { | |
| 329 printf("Could not open LoopGraph file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); | |
| 330 } | |
| 331 | |
| 332 | |
| 333 freeListOfArrays(semanticEnv->unitList); | |
| 334 freeListOfArrays(semanticEnv->commDependenciesList); | |
| 335 freeListOfArrays(semanticEnv->ctlDependenciesList); | |
| 336 freeListOfArrays(semanticEnv->dynDependenciesList); | |
| 337 | |
| 338 #endif | |
| 339 #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS | |
| 340 for(n=0;n<255;n++) | |
| 341 { | |
| 342 sprintf(filename, "./counters/Counters.%d.csv",n); | |
| 343 output = fopen(filename,"r"); | |
| 344 if(output) | |
| 345 { | |
| 346 fclose(output); | |
| 347 }else{ | |
| 348 break; | |
| 349 } | |
| 350 } | |
| 351 if(n<255){ | |
| 352 printf("Saving Counter measurements to File: %s ...\n", filename); | |
| 353 output = fopen(filename,"w+"); | |
| 354 if(output!=NULL){ | |
| 355 set_counter_file(output); | |
| 356 int i; | |
| 357 for(i=0;i<NUM_CORES;i++){ | |
| 358 forAllInListOfArraysDo( semanticEnv->counterList[i], &print_counter_events_to_file ); | |
| 359 fflush(output); | |
| 360 } | |
| 361 | |
| 362 } else | |
| 363 printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); | |
| 364 } else { | |
| 365 printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); | |
| 366 } | |
| 367 | |
| 368 #endif | |
| 369 /* It's all allocated inside VMS's big chunk -- that's about to be freed, so | |
| 370 * nothing to do here | |
| 371 | |
| 372 | |
| 373 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) | |
| 374 { | |
| 375 VMS_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); | |
| 376 VMS_int__free( semanticEnv->readyVPQs[coreIdx] ); | |
| 377 } | |
| 378 VMS_int__free( semanticEnv->readyVPQs ); | |
| 379 | |
| 380 freeHashTable( semanticEnv->commHashTbl ); | |
| 381 VMS_int__free( _VMSMasterEnv->semanticEnv ); | |
| 382 */ | |
| 383 VMS_SS__cleanup_at_end_of_shutdown(); | |
| 384 } | |
| 385 | |
| 386 | |
| 387 //=========================================================================== | |
| 388 | |
| 389 /* | |
| 390 */ | |
| 391 SlaveVP * | |
| 392 SSR__create_procr_with( TopLevelFnPtr fnPtr, void *initData, | |
| 393 SlaveVP *creatingPr ) | |
| 394 { SSRSemReq reqData; | |
| 395 | |
| 396 //the semantic request data is on the stack and disappears when this | |
| 397 // call returns -- it's guaranteed to remain in the VP's stack for as | |
| 398 // long as the VP is suspended. | |
| 399 reqData.reqType = 0; //know type because in a VMS create req | |
| 400 reqData.coreToAssignOnto = -1; //means round-robin assign | |
| 401 reqData.fnPtr = fnPtr; | |
| 402 reqData.initData = initData; | |
| 403 reqData.sendPr = creatingPr; | |
| 404 | |
| 405 VMS_WL__send_create_slaveVP_req( &reqData, creatingPr ); | |
| 406 | |
| 407 return creatingPr->dataRetFromReq; | |
| 408 } | |
| 409 | |
| 410 SlaveVP * | |
| 411 SSR__create_procr_with_affinity( TopLevelFnPtr fnPtr, void *initData, | |
| 412 SlaveVP *creatingPr, int32 coreToAssignOnto ) | |
| 413 { SSRSemReq reqData; | |
| 414 | |
| 415 //the semantic request data is on the stack and disappears when this | |
| 416 // call returns -- it's guaranteed to remain in the VP's stack for as | |
| 417 // long as the VP is suspended. | |
| 418 reqData.reqType = 0; //know type because in a VMS create req | |
| 419 reqData.coreToAssignOnto = coreToAssignOnto; | |
| 420 reqData.fnPtr = fnPtr; | |
| 421 reqData.initData = initData; | |
| 422 reqData.sendPr = creatingPr; | |
| 423 | |
| 424 VMS_WL__send_create_slaveVP_req( &reqData, creatingPr ); | |
| 425 | |
| 426 return creatingPr->dataRetFromReq; | |
| 427 } | |
| 428 | |
| 429 | |
| 430 void | |
| 431 SSR__dissipate_procr( SlaveVP *procrToDissipate ) | |
| 432 { | |
| 433 VMS_WL__send_dissipate_req( procrToDissipate ); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 //=========================================================================== | |
| 438 | |
| 439 void * | |
| 440 SSR__malloc_to( int32 sizeToMalloc, SlaveVP *owningPr ) | |
| 441 { SSRSemReq reqData; | |
| 442 | |
| 443 reqData.reqType = malloc_req; | |
| 444 reqData.sendPr = owningPr; | |
| 445 reqData.sizeToMalloc = sizeToMalloc; | |
| 446 | |
| 447 VMS_WL__send_sem_request( &reqData, owningPr ); | |
| 448 | |
| 449 return owningPr->dataRetFromReq; | |
| 450 } | |
| 451 | |
| 452 | |
| 453 /*Sends request to Master, which does the work of freeing | |
| 454 */ | |
| 455 void | |
| 456 SSR__free( void *ptrToFree, SlaveVP *owningPr ) | |
| 457 { SSRSemReq reqData; | |
| 458 | |
| 459 reqData.reqType = free_req; | |
| 460 reqData.sendPr = owningPr; | |
| 461 reqData.ptrToFree = ptrToFree; | |
| 462 | |
| 463 VMS_WL__send_sem_request( &reqData, owningPr ); | |
| 464 } | |
| 465 | |
| 466 | |
| 467 void | |
| 468 SSR__transfer_ownership_of_from_to( void *data, SlaveVP *oldOwnerSlv, | |
| 469 SlaveVP *newOwnerPr ) | |
| 470 { | |
| 471 //TODO: put in the ownership system that automatically frees when no | |
| 472 // owners of data left -- will need keeper for keeping data around when | |
| 473 // future created processors might need it but don't exist yet | |
| 474 } | |
| 475 | |
| 476 | |
| 477 void | |
| 478 SSR__add_ownership_by_to( SlaveVP *newOwnerSlv, void *data ) | |
| 479 { | |
| 480 | |
| 481 } | |
| 482 | |
| 483 | |
| 484 void | |
| 485 SSR__remove_ownership_by_from( SlaveVP *loserSlv, void *dataLosing ) | |
| 486 { | |
| 487 | |
| 488 } | |
| 489 | |
| 490 | |
| 491 /*Causes the SSR system to remove internal ownership, so data won't be | |
| 492 * freed when SSR shuts down, and will persist in the external program. | |
| 493 * | |
| 494 *Must be called from the processor that currently owns the data. | |
| 495 * | |
| 496 *IMPL: Transferring ownership touches two different virtual processor's | |
| 497 * state -- which means it has to be done carefully -- the VMS rules for | |
| 498 * semantic layers say that a work-unit is only allowed to touch the | |
| 499 * virtual processor it is part of, and that only a single work-unit per | |
| 500 * virtual processor be assigned to a slave at a time. So, this has to | |
| 501 * modify the virtual processor that owns the work-unit that called this | |
| 502 * function, then create a request to have the other processor modified. | |
| 503 *However, in this case, the TO processor is the outside, and transfers | |
| 504 * are only allowed to be called by the giver-upper, so can mark caller of | |
| 505 * this function as no longer owner, and return -- done. | |
| 506 */ | |
| 507 void | |
| 508 SSR__transfer_ownership_to_outside( void *data ) | |
| 509 { | |
| 510 //TODO: removeAllOwnersFrom( data ); | |
| 511 } | |
| 512 | |
| 513 | |
| 514 //=========================================================================== | |
| 515 | |
| 516 void | |
| 517 SSR__send_of_type_to( SlaveVP *sendPr, void *msg, const int type, | |
| 518 SlaveVP *receivePr) | |
| 519 { SSRSemReq reqData; | |
| 520 | |
| 521 reqData.receivePr = receivePr; | |
| 522 reqData.sendPr = sendPr; | |
| 523 reqData.reqType = send_type; | |
| 524 reqData.msgType = type; | |
| 525 reqData.msg = msg; | |
| 526 reqData.nextReqInHashEntry = NULL; | |
| 527 | |
| 528 //On ownership -- remove inside the send and let ownership sit in limbo | |
| 529 // as a potential in an entry in the hash table, when this receive msg | |
| 530 // gets paired to a send, the ownership gets added to the receivePr -- | |
| 531 // the next work-unit in the receivePr's trace will have ownership. | |
| 532 VMS_WL__send_sem_request( &reqData, sendPr ); | |
| 533 | |
| 534 //When come back from suspend, no longer own data reachable from msg | |
| 535 //TODO: release ownership here | |
| 536 } | |
| 537 | |
| 538 void | |
| 539 SSR__send_from_to( void *msg, SlaveVP *sendPr, SlaveVP *receivePr ) | |
| 540 { SSRSemReq reqData; | |
| 541 | |
| 542 //hash on the receiver, 'cause always know it, but sometimes want to | |
| 543 // receive from anonymous sender | |
| 544 | |
| 545 reqData.receivePr = receivePr; | |
| 546 reqData.sendPr = sendPr; | |
| 547 reqData.reqType = send_from_to; | |
| 548 reqData.msg = msg; | |
| 549 reqData.nextReqInHashEntry = NULL; | |
| 550 | |
| 551 VMS_WL__send_sem_request( &reqData, sendPr ); | |
| 552 } | |
| 553 | |
| 554 | |
| 555 //=========================================================================== | |
| 556 | |
| 557 void * | |
| 558 SSR__receive_any_to( SlaveVP *receivePr ) | |
| 559 { | |
| 560 | |
| 561 } | |
| 562 | |
| 563 void * | |
| 564 SSR__receive_type_to( const int type, SlaveVP *receivePr ) | |
| 565 { | |
| 566 SSRSemReq reqData; | |
| 567 | |
| 568 reqData.receivePr = receivePr; | |
| 569 reqData.reqType = receive_type; | |
| 570 reqData.msgType = type; | |
| 571 reqData.nextReqInHashEntry = NULL; | |
| 572 | |
| 573 VMS_WL__send_sem_request( &reqData, receivePr ); | |
| 574 | |
| 575 return receivePr->dataRetFromReq; | |
| 576 } | |
| 577 | |
| 578 | |
| 579 | |
| 580 /*Call this at point receiving virt pr wants in-coming data. | |
| 581 * | |
| 582 *The reason receivePr must call this is that it modifies the receivPr | |
| 583 * loc structure directly -- and the VMS rules state a virtual processor | |
| 584 * loc structure can only be modified by itself. | |
| 585 */ | |
| 586 void * | |
| 587 SSR__receive_from_to( SlaveVP *sendPr, SlaveVP *receivePr ) | |
| 588 { SSRSemReq reqData; | |
| 589 | |
| 590 //hash on the receiver, 'cause always know it, but sometimes want to | |
| 591 // receive from anonymous sender | |
| 592 | |
| 593 reqData.receivePr = receivePr; | |
| 594 reqData.sendPr = sendPr; | |
| 595 reqData.reqType = receive_from_to; | |
| 596 reqData.nextReqInHashEntry = NULL; | |
| 597 | |
| 598 VMS_WL__send_sem_request( &reqData, receivePr ); | |
| 599 | |
| 600 return receivePr->dataRetFromReq; | |
| 601 } | |
| 602 | |
| 603 | |
| 604 //=========================================================================== | |
| 605 // | |
| 606 /*A function singleton is a function whose body executes exactly once, on a | |
| 607 * single core, no matter how many times the fuction is called and no | |
| 608 * matter how many cores or the timing of cores calling it. | |
| 609 * | |
| 610 *A data singleton is a ticket attached to data. That ticket can be used | |
| 611 * to get the data through the function exactly once, no matter how many | |
| 612 * times the data is given to the function, and no matter the timing of | |
| 613 * trying to get the data through from different cores. | |
| 614 */ | |
| 615 | |
| 616 /*asm function declarations*/ | |
| 617 void asm_save_ret_to_singleton(SSRSingleton *singletonPtrAddr); | |
| 618 void asm_write_ret_from_singleton(SSRSingleton *singletonPtrAddr); | |
| 619 | |
| 620 /*Fn singleton uses ID as index into array of singleton structs held in the | |
| 621 * semantic environment. | |
| 622 */ | |
| 623 void | |
| 624 SSR__start_fn_singleton( int32 singletonID, SlaveVP *animPr ) | |
| 625 { | |
| 626 SSRSemReq reqData; | |
| 627 | |
| 628 // | |
| 629 reqData.reqType = singleton_fn_start; | |
| 630 reqData.singletonID = singletonID; | |
| 631 | |
| 632 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 633 if( animPr->dataRetFromReq ) //will be 0 or addr of label in end singleton | |
| 634 { | |
| 635 SSRSemEnv *semEnv = VMS_int__give_sem_env_for( animPr ); | |
| 636 asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 /*Data singleton hands addr of loc holding a pointer to a singleton struct. | |
| 641 * The start_data_singleton makes the structure and puts its addr into the | |
| 642 * location. | |
| 643 */ | |
| 644 void | |
| 645 SSR__start_data_singleton( SSRSingleton **singletonAddr, SlaveVP *animPr ) | |
| 646 { | |
| 647 SSRSemReq reqData; | |
| 648 | |
| 649 if( *singletonAddr && (*singletonAddr)->hasFinished ) | |
| 650 goto JmpToEndSingleton; | |
| 651 | |
| 652 reqData.reqType = singleton_data_start; | |
| 653 reqData.singletonPtrAddr = singletonAddr; | |
| 654 | |
| 655 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 656 if( animPr->dataRetFromReq ) //either 0 or end singleton's return addr | |
| 657 { //Assembly code changes the return addr on the stack to the one | |
| 658 // saved into the singleton by the end-singleton-fn | |
| 659 //The return addr is at 0x4(%%ebp) | |
| 660 JmpToEndSingleton: | |
| 661 asm_write_ret_from_singleton(*singletonAddr); | |
| 662 } | |
| 663 //now, simply return | |
| 664 //will exit either from the start singleton call or the end-singleton call | |
| 665 } | |
| 666 | |
| 667 /*Uses ID as index into array of flags. If flag already set, resumes from | |
| 668 * end-label. Else, sets flag and resumes normally. | |
| 669 * | |
| 670 *Note, this call cannot be inlined because the instr addr at the label | |
| 671 * inside is shared by all invocations of a given singleton ID. | |
| 672 */ | |
| 673 void | |
| 674 SSR__end_fn_singleton( int32 singletonID, SlaveVP *animPr ) | |
| 675 { | |
| 676 SSRSemReq reqData; | |
| 677 | |
| 678 //don't need this addr until after at least one singleton has reached | |
| 679 // this function | |
| 680 SSRSemEnv *semEnv = VMS_int__give_sem_env_for( animPr ); | |
| 681 asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); | |
| 682 | |
| 683 reqData.reqType = singleton_fn_end; | |
| 684 reqData.singletonID = singletonID; | |
| 685 | |
| 686 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 687 | |
| 688 EndSingletonInstrAddr: | |
| 689 return; | |
| 690 } | |
| 691 | |
| 692 void | |
| 693 SSR__end_data_singleton( SSRSingleton **singletonPtrAddr, SlaveVP *animPr ) | |
| 694 { | |
| 695 SSRSemReq reqData; | |
| 696 | |
| 697 //don't need this addr until after singleton struct has reached | |
| 698 // this function for first time | |
| 699 //do assembly that saves the return addr of this fn call into the | |
| 700 // data singleton -- that data-singleton can only be given to exactly | |
| 701 // one instance in the code of this function. However, can use this | |
| 702 // function in different places for different data-singletons. | |
| 703 // (*(singletonAddr))->endInstrAddr = &&EndDataSingletonInstrAddr; | |
| 704 | |
| 705 | |
| 706 asm_save_ret_to_singleton(*singletonPtrAddr); | |
| 707 | |
| 708 reqData.reqType = singleton_data_end; | |
| 709 reqData.singletonPtrAddr = singletonPtrAddr; | |
| 710 | |
| 711 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 712 } | |
| 713 | |
| 714 /*This executes the function in the masterVP, so it executes in isolation | |
| 715 * from any other copies -- only one copy of the function can ever execute | |
| 716 * at a time. | |
| 717 * | |
| 718 *It suspends to the master, and the request handler takes the function | |
| 719 * pointer out of the request and calls it, then resumes the VP. | |
| 720 *Only very short functions should be called this way -- for longer-running | |
| 721 * isolation, use transaction-start and transaction-end, which run the code | |
| 722 * between as work-code. | |
| 723 */ | |
| 724 void | |
| 725 SSR__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, | |
| 726 void *data, SlaveVP *animPr ) | |
| 727 { | |
| 728 SSRSemReq reqData; | |
| 729 | |
| 730 // | |
| 731 reqData.reqType = atomic; | |
| 732 reqData.fnToExecInMaster = ptrToFnToExecInMaster; | |
| 733 reqData.dataForFn = data; | |
| 734 | |
| 735 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 736 } | |
| 737 | |
| 738 | |
| 739 /*This suspends to the master. | |
| 740 *First, it looks at the VP's data, to see the highest transactionID that VP | |
| 741 * already has entered. If the current ID is not larger, it throws an | |
| 742 * exception stating a bug in the code. Otherwise it puts the current ID | |
| 743 * there, and adds the ID to a linked list of IDs entered -- the list is | |
| 744 * used to check that exits are properly ordered. | |
| 745 *Next it is uses transactionID as index into an array of transaction | |
| 746 * structures. | |
| 747 *If the "VP_currently_executing" field is non-null, then put requesting VP | |
| 748 * into queue in the struct. (At some point a holder will request | |
| 749 * end-transaction, which will take this VP from the queue and resume it.) | |
| 750 *If NULL, then write requesting into the field and resume. | |
| 751 */ | |
| 752 void | |
| 753 SSR__start_transaction( int32 transactionID, SlaveVP *animPr ) | |
| 754 { | |
| 755 SSRSemReq reqData; | |
| 756 | |
| 757 // | |
| 758 reqData.sendPr = animPr; | |
| 759 reqData.reqType = trans_start; | |
| 760 reqData.transID = transactionID; | |
| 761 | |
| 762 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 763 } | |
| 764 | |
| 765 /*This suspends to the master, then uses transactionID as index into an | |
| 766 * array of transaction structures. | |
| 767 *It looks at VP_currently_executing to be sure it's same as requesting VP. | |
| 768 * If different, throws an exception, stating there's a bug in the code. | |
| 769 *Next it looks at the queue in the structure. | |
| 770 *If it's empty, it sets VP_currently_executing field to NULL and resumes. | |
| 771 *If something in, gets it, sets VP_currently_executing to that VP, then | |
| 772 * resumes both. | |
| 773 */ | |
| 774 void | |
| 775 SSR__end_transaction( int32 transactionID, SlaveVP *animPr ) | |
| 776 { | |
| 777 SSRSemReq reqData; | |
| 778 | |
| 779 // | |
| 780 reqData.sendPr = animPr; | |
| 781 reqData.reqType = trans_end; | |
| 782 reqData.transID = transactionID; | |
| 783 | |
| 784 VMS_WL__send_sem_request( &reqData, animPr ); | |
| 785 } |
