annotate VMS.c @ 135:0b49fd35afc1

distributed free working -app sends a VMSSemReqst to his Master which send a request to a different Master -Master send the request directly -The request structure is freed by the sender, when the request was handled There are still problems on shutdown. The shutdownVPs are all allocated by one Master which is likly to be terminated
author Merten Sach <msach@mailbox.tu-berlin.de>
date Fri, 16 Sep 2011 20:08:28 +0200
parents a9b72021f053
children f1374d5dbb98
rev   line source
Me@0 1 /*
Me@38 2 * Copyright 2010 OpenSourceStewardshipFoundation
Me@0 3 *
Me@0 4 * Licensed under BSD
Me@0 5 */
Me@0 6
Me@0 7 #include <stdio.h>
Me@0 8 #include <stdlib.h>
Me@50 9 #include <string.h>
Me@0 10 #include <malloc.h>
msach@76 11 #include <inttypes.h>
Me@50 12 #include <sys/time.h>
Me@0 13
Me@0 14 #include "VMS.h"
msach@77 15 #include "ProcrContext.h"
msach@134 16 #include "scheduling.h"
Me@0 17 #include "Queue_impl/BlockingQueue.h"
Me@38 18 #include "Histogram/Histogram.h"
Me@0 19
Me@0 20
Me@26 21 #define thdAttrs NULL
Me@26 22
Me@22 23 //===========================================================================
Me@22 24 void
Me@22 25 shutdownFn( void *dummy, VirtProcr *dummy2 );
Me@22 26
Me@31 27 SchedSlot **
Me@31 28 create_sched_slots();
Me@22 29
Me@28 30 void
Me@28 31 create_masterEnv();
Me@28 32
Me@28 33 void
Me@28 34 create_the_coreLoop_OS_threads();
Me@28 35
Me@50 36 MallocProlog *
Me@50 37 create_free_list();
Me@50 38
Me@53 39 void
Me@53 40 endOSThreadFn( void *initData, VirtProcr *animatingPr );
Me@50 41
Me@26 42 pthread_mutex_t suspendLock = PTHREAD_MUTEX_INITIALIZER;
Me@26 43 pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
Me@26 44
Me@22 45 //===========================================================================
Me@22 46
Me@0 47 /*Setup has two phases:
Me@0 48 * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts
Me@8 49 * the master virt procr into the work-queue, ready for first "call"
Me@8 50 * 2) Semantic layer then does its own init, which creates the seed virt
Me@8 51 * procr inside the semantic layer, ready to schedule it when
Me@0 52 * asked by the first run of the masterLoop.
Me@0 53 *
Me@0 54 *This part is bit weird because VMS really wants to be "always there", and
Me@0 55 * have applications attach and detach.. for now, this VMS is part of
Me@0 56 * the app, so the VMS system starts up as part of running the app.
Me@0 57 *
Me@8 58 *The semantic layer is isolated from the VMS internals by making the
Me@8 59 * semantic layer do setup to a state that it's ready with its
Me@8 60 * initial virt procrs, ready to schedule them to slots when the masterLoop
Me@0 61 * asks. Without this pattern, the semantic layer's setup would
Me@8 62 * have to modify slots directly to assign the initial virt-procrs, and put
Me@31 63 * them into the readyToAnimateQ itself, breaking the isolation completely.
Me@0 64 *
Me@0 65 *
Me@8 66 *The semantic layer creates the initial virt procr(s), and adds its
Me@8 67 * own environment to masterEnv, and fills in the pointers to
Me@0 68 * the requestHandler and slaveScheduler plug-in functions
Me@8 69 */
Me@8 70
Me@8 71 /*This allocates VMS data structures, populates the master VMSProc,
Me@0 72 * and master environment, and returns the master environment to the semantic
Me@0 73 * layer.
Me@0 74 */
Me@8 75 void
Me@8 76 VMS__init()
Me@28 77 {
Me@28 78 create_masterEnv();
Me@28 79 create_the_coreLoop_OS_threads();
Me@28 80 }
Me@28 81
msach@71 82 #ifdef SEQUENTIAL
msach@71 83
Me@28 84 /*To initialize the sequential version, just don't create the threads
Me@28 85 */
Me@28 86 void
Me@28 87 VMS__init_Seq()
Me@28 88 {
Me@28 89 create_masterEnv();
Me@28 90 }
Me@28 91
msach@71 92 #endif
msach@71 93
Me@28 94 void
Me@28 95 create_masterEnv()
Me@31 96 { MasterEnv *masterEnv;
Me@55 97 VMSQueueStruc **readyToAnimateQs;
Me@31 98 int coreIdx;
Me@31 99 VirtProcr **masterVPs;
Me@31 100 SchedSlot ***allSchedSlots; //ptr to array of ptrs
Me@53 101
Me@53 102
Me@31 103 //Make the master env, which holds everything else
Me@1 104 _VMSMasterEnv = malloc( sizeof(MasterEnv) );
Me@53 105
Me@53 106 //Very first thing put into the master env is the free-list, seeded
Me@53 107 // with a massive initial chunk of memory.
Me@53 108 //After this, all other mallocs are VMS__malloc.
msach@132 109 int i;
msach@132 110 for(i=0; i<NUM_CORES; i++)
msach@132 111 {
msach@132 112 _VMSMasterEnv->freeListHead[i] = VMS_ext__create_free_list();
msach@134 113 _VMSMasterEnv->interMasterRequestsFor[i] = NULL;
msach@135 114 _VMSMasterEnv->interMasterRequestsSentBy[i] = NULL;
msach@132 115 }
msach@134 116 _VMSMasterEnv->currentMasterProcrID = 0;
Me@53 117
Me@65 118
Me@65 119 //============================= MEASUREMENT STUFF ========================
Me@65 120 #ifdef MEAS__TIME_MALLOC
msach@84 121 _VMSMasterEnv->mallocTimeHist = makeFixedBinHistExt( 100, 0, 100,
msach@79 122 "malloc_time_hist");
msach@84 123 _VMSMasterEnv->freeTimeHist = makeFixedBinHistExt( 80, 0, 100,
msach@79 124 "free_time_hist");
Me@65 125 #endif
Me@68 126 #ifdef MEAS__TIME_PLUGIN
msach@84 127 _VMSMasterEnv->reqHdlrLowTimeHist = makeFixedBinHistExt( 1000, 0, 100,
msach@79 128 "plugin_low_time_hist");
msach@84 129 _VMSMasterEnv->reqHdlrHighTimeHist = makeFixedBinHistExt( 1000, 0, 100,
msach@79 130 "plugin_high_time_hist");
Me@68 131 #endif
Me@65 132 //========================================================================
Me@65 133
Me@53 134 //===================== Only VMS__malloc after this ====================
msach@69 135 masterEnv = (MasterEnv*)_VMSMasterEnv;
Me@31 136
Me@31 137 //Make a readyToAnimateQ for each core loop
Me@55 138 readyToAnimateQs = VMS__malloc( NUM_CORES * sizeof(VMSQueueStruc *) );
Me@53 139 masterVPs = VMS__malloc( NUM_CORES * sizeof(VirtProcr *) );
Me@0 140
Me@31 141 //One array for each core, 3 in array, core's masterVP scheds all
Me@53 142 allSchedSlots = VMS__malloc( NUM_CORES * sizeof(SchedSlot *) );
Me@0 143
Me@53 144 _VMSMasterEnv->numProcrsCreated = 0; //used by create procr
Me@31 145 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
Me@53 146 {
Me@55 147 readyToAnimateQs[ coreIdx ] = makeVMSQ();
Me@31 148
Me@50 149 //Q: should give masterVP core-specific info as its init data?
msach@76 150 masterVPs[ coreIdx ] = VMS__create_procr( (VirtProcrFnPtr)&masterLoop, (void*)masterEnv );
Me@31 151 masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx;
Me@31 152 allSchedSlots[ coreIdx ] = create_sched_slots(); //makes for one core
Me@53 153 _VMSMasterEnv->numMasterInARow[ coreIdx ] = 0;
Me@55 154 _VMSMasterEnv->workStealingGates[ coreIdx ] = NULL;
Me@31 155 }
Me@31 156 _VMSMasterEnv->readyToAnimateQs = readyToAnimateQs;
Me@31 157 _VMSMasterEnv->masterVPs = masterVPs;
Me@50 158 _VMSMasterEnv->masterLock = UNLOCKED;
Me@31 159 _VMSMasterEnv->allSchedSlots = allSchedSlots;
Me@55 160 _VMSMasterEnv->workStealingLock = UNLOCKED;
Me@28 161
Me@12 162
Me@31 163 //Aug 19, 2010: no longer need to place initial masterVP into queue
Me@31 164 // because coreLoop now controls -- animates its masterVP when no work
Me@31 165
Me@30 166
Me@50 167 //============================= MEASUREMENT STUFF ========================
Me@50 168 #ifdef STATS__TURN_ON_PROBES
Me@50 169 _VMSMasterEnv->dynIntervalProbesInfo =
msach@69 170 makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->intervalProbes), 200);
Me@30 171
Me@53 172 _VMSMasterEnv->probeNameHashTbl = makeHashTable( 1000, &VMS__free );
Me@53 173
Me@53 174 //put creation time directly into master env, for fast retrieval
Me@50 175 struct timeval timeStamp;
Me@50 176 gettimeofday( &(timeStamp), NULL);
Me@50 177 _VMSMasterEnv->createPtInSecs =
Me@50 178 timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0);
Me@50 179 #endif
Me@65 180 #ifdef MEAS__TIME_MASTER_LOCK
Me@65 181 _VMSMasterEnv->masterLockLowTimeHist = makeFixedBinHist( 50, 0, 2,
Me@65 182 "master lock low time hist");
Me@68 183 _VMSMasterEnv->masterLockHighTimeHist = makeFixedBinHist( 50, 0, 100,
Me@65 184 "master lock high time hist");
Me@65 185 #endif
Me@68 186
msach@76 187 MakeTheMeasHists();
Me@50 188 //========================================================================
Me@38 189
Me@0 190 }
Me@0 191
Me@31 192 SchedSlot **
Me@31 193 create_sched_slots()
Me@31 194 { SchedSlot **schedSlots;
Me@0 195 int i;
Me@0 196
Me@53 197 schedSlots = VMS__malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) );
Me@8 198
Me@1 199 for( i = 0; i < NUM_SCHED_SLOTS; i++ )
Me@0 200 {
Me@53 201 schedSlots[i] = VMS__malloc( sizeof(SchedSlot) );
Me@8 202
Me@1 203 //Set state to mean "handling requests done, slot needs filling"
Me@8 204 schedSlots[i]->workIsDone = FALSE;
Me@8 205 schedSlots[i]->needsProcrAssigned = TRUE;
Me@0 206 }
Me@31 207 return schedSlots;
Me@31 208 }
Me@31 209
Me@31 210
Me@31 211 void
Me@31 212 freeSchedSlots( SchedSlot **schedSlots )
Me@31 213 { int i;
Me@31 214 for( i = 0; i < NUM_SCHED_SLOTS; i++ )
Me@31 215 {
Me@53 216 VMS__free( schedSlots[i] );
Me@31 217 }
Me@53 218 VMS__free( schedSlots );
Me@0 219 }
Me@0 220
Me@8 221
Me@28 222 void
Me@28 223 create_the_coreLoop_OS_threads()
Me@28 224 {
Me@28 225 //========================================================================
Me@28 226 // Create the Threads
Me@28 227 int coreIdx, retCode;
Me@28 228
Me@28 229 //Need the threads to be created suspended, and wait for a signal
Me@28 230 // before proceeding -- gives time after creating to initialize other
Me@28 231 // stuff before the coreLoops set off.
Me@28 232 _VMSMasterEnv->setupComplete = 0;
Me@28 233
Me@28 234 //Make the threads that animate the core loops
Me@28 235 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
Me@53 236 { coreLoopThdParams[coreIdx] = VMS__malloc( sizeof(ThdParams) );
Me@28 237 coreLoopThdParams[coreIdx]->coreNum = coreIdx;
Me@28 238
Me@28 239 retCode =
Me@28 240 pthread_create( &(coreLoopThdHandles[coreIdx]),
Me@28 241 thdAttrs,
Me@28 242 &coreLoop,
Me@28 243 (void *)(coreLoopThdParams[coreIdx]) );
Me@50 244 if(retCode){printf("ERROR creating thread: %d\n", retCode); exit(1);}
Me@28 245 }
Me@28 246 }
Me@28 247
Me@0 248 /*Semantic layer calls this when it want the system to start running..
Me@0 249 *
Me@24 250 *This starts the core loops running then waits for them to exit.
Me@0 251 */
Me@12 252 void
Me@24 253 VMS__start_the_work_then_wait_until_done()
Me@12 254 { int coreIdx;
Me@24 255 //Start the core loops running
Me@25 256
Me@25 257 //tell the core loop threads that setup is complete
Me@25 258 //get lock, to lock out any threads still starting up -- they'll see
Me@25 259 // that setupComplete is true before entering while loop, and so never
Me@25 260 // wait on the condition
Me@26 261 pthread_mutex_lock( &suspendLock );
Me@25 262 _VMSMasterEnv->setupComplete = 1;
Me@26 263 pthread_mutex_unlock( &suspendLock );
Me@26 264 pthread_cond_broadcast( &suspend_cond );
Me@25 265
Me@25 266
Me@24 267 //wait for all to complete
Me@8 268 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
Me@8 269 {
Me@25 270 pthread_join( coreLoopThdHandles[coreIdx], NULL );
Me@24 271 }
Me@25 272
Me@24 273 //NOTE: do not clean up VMS env here -- semantic layer has to have
Me@24 274 // a chance to clean up its environment first, then do a call to free
Me@24 275 // the Master env and rest of VMS locations
Me@8 276 }
Me@0 277
msach@70 278 #ifdef SEQUENTIAL
Me@28 279 /*Only difference between version with an OS thread pinned to each core and
Me@28 280 * the sequential version of VMS is VMS__init_Seq, this, and coreLoop_Seq.
Me@28 281 */
Me@28 282 void
Me@28 283 VMS__start_the_work_then_wait_until_done_Seq()
Me@28 284 {
Me@28 285 //Instead of un-suspending threads, just call the one and only
Me@28 286 // core loop (sequential version), in the main thread.
Me@28 287 coreLoop_Seq( NULL );
msach@75 288 flushRegisters();
Me@28 289
Me@28 290 }
msach@70 291 #endif
Me@28 292
Me@50 293 inline VirtProcr *
Me@50 294 VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
Me@50 295 { VirtProcr *newPr;
msach@76 296 void *stackLocs;
Me@50 297
Me@50 298 newPr = VMS__malloc( sizeof(VirtProcr) );
Me@50 299 stackLocs = VMS__malloc( VIRT_PROCR_STACK_SIZE );
Me@50 300 if( stackLocs == 0 )
Me@50 301 { perror("VMS__malloc stack"); exit(1); }
Me@50 302
msach@69 303 return create_procr_helper( newPr, fnPtr, initialData, stackLocs );
Me@50 304 }
Me@50 305
Me@50 306 /* "ext" designates that it's for use outside the VMS system -- should only
Me@50 307 * be called from main thread or other thread -- never from code animated by
Me@50 308 * a VMS virtual processor.
Me@50 309 */
Me@50 310 inline VirtProcr *
Me@50 311 VMS_ext__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
Me@50 312 { VirtProcr *newPr;
Me@50 313 char *stackLocs;
Me@50 314
Me@50 315 newPr = malloc( sizeof(VirtProcr) );
Me@50 316 stackLocs = malloc( VIRT_PROCR_STACK_SIZE );
Me@50 317 if( stackLocs == 0 )
Me@50 318 { perror("malloc stack"); exit(1); }
Me@50 319
msach@69 320 return create_procr_helper( newPr, fnPtr, initialData, stackLocs );
Me@50 321 }
Me@50 322
Me@8 323
Me@64 324 /*Anticipating multi-tasking
Me@64 325 */
Me@64 326 void *
Me@64 327 VMS__give_sem_env_for( VirtProcr *animPr )
Me@64 328 {
Me@64 329 return _VMSMasterEnv->semanticEnv;
Me@64 330 }
Me@64 331 //===========================================================================
Me@26 332 /*there is a label inside this function -- save the addr of this label in
Me@0 333 * the callingPr struc, as the pick-up point from which to start the next
Me@0 334 * work-unit for that procr. If turns out have to save registers, then
Me@0 335 * save them in the procr struc too. Then do assembly jump to the CoreLoop's
Me@0 336 * "done with work-unit" label. The procr struc is in the request in the
Me@0 337 * slave that animated the just-ended work-unit, so all the state is saved
Me@0 338 * there, and will get passed along, inside the request handler, to the
Me@0 339 * next work-unit for that procr.
Me@0 340 */
Me@8 341 void
Me@38 342 VMS__suspend_procr( VirtProcr *animatingPr )
Me@55 343 {
Me@30 344
Me@30 345 //The request to master will cause this suspended virt procr to get
Me@30 346 // scheduled again at some future point -- to resume, core loop jumps
Me@30 347 // to the resume point (below), which causes restore of saved regs and
Me@30 348 // "return" from this call.
msach@71 349 //animatingPr->nextInstrPt = &&ResumePt;
Me@30 350
Me@30 351 //return ownership of the virt procr and sched slot to Master virt pr
Me@38 352 animatingPr->schedSlot->workIsDone = TRUE;
Me@1 353
Me@41 354 //=========================== Measurement stuff ========================
Me@38 355 #ifdef MEAS__TIME_STAMP_SUSP
Me@41 356 //record time stamp: compare to time-stamp recorded below
Me@38 357 saveLowTimeStampCountInto( animatingPr->preSuspTSCLow );
Me@38 358 #endif
Me@41 359 //=======================================================================
Me@30 360
msach@71 361 switchToCoreLoop(animatingPr);
msach@71 362 flushRegisters();
Me@55 363
Me@55 364 //=======================================================================
Me@30 365
Me@38 366 #ifdef MEAS__TIME_STAMP_SUSP
Me@41 367 //NOTE: only take low part of count -- do sanity check when take diff
Me@38 368 saveLowTimeStampCountInto( animatingPr->postSuspTSCLow );
Me@38 369 #endif
Me@30 370
Me@0 371 return;
Me@0 372 }
Me@0 373
Me@22 374
Me@22 375
Me@50 376 /*For this implementation of VMS, it may not make much sense to have the
Me@50 377 * system of requests for creating a new processor done this way.. but over
Me@50 378 * the scope of single-master, multi-master, mult-tasking, OS-implementing,
Me@50 379 * distributed-memory, and so on, this gives VMS implementation a chance to
Me@50 380 * do stuff before suspend, in the AppVP, and in the Master before the plugin
Me@50 381 * is called, as well as in the lang-lib before this is called, and in the
Me@50 382 * plugin. So, this gives both VMS and language implementations a chance to
Me@50 383 * intercept at various points and do order-dependent stuff.
Me@50 384 *Having a standard VMSNewPrReqData struc allows the language to create and
Me@50 385 * free the struc, while VMS knows how to get the newPr if it wants it, and
Me@50 386 * it lets the lang have lang-specific data related to creation transported
Me@50 387 * to the plugin.
Me@50 388 */
Me@50 389 void
Me@50 390 VMS__send_create_procr_req( void *semReqData, VirtProcr *reqstingPr )
Me@50 391 { VMSReqst req;
Me@50 392
Me@50 393 req.reqType = createReq;
Me@50 394 req.semReqData = semReqData;
Me@50 395 req.nextReqst = reqstingPr->requests;
Me@50 396 reqstingPr->requests = &req;
Me@50 397
Me@50 398 VMS__suspend_procr( reqstingPr );
Me@50 399 }
Me@50 400
Me@22 401
Me@38 402 /*
Me@22 403 *This adds a request to dissipate, then suspends the processor so that the
Me@22 404 * request handler will receive the request. The request handler is what
Me@22 405 * does the work of freeing memory and removing the processor from the
Me@22 406 * semantic environment's data structures.
Me@22 407 *The request handler also is what figures out when to shutdown the VMS
Me@22 408 * system -- which causes all the core loop threads to die, and returns from
Me@22 409 * the call that started up VMS to perform the work.
Me@22 410 *
Me@22 411 *This form is a bit misleading to understand if one is trying to figure out
Me@22 412 * how VMS works -- it looks like a normal function call, but inside it
Me@22 413 * sends a request to the request handler and suspends the processor, which
Me@22 414 * jumps out of the VMS__dissipate_procr function, and out of all nestings
Me@22 415 * above it, transferring the work of dissipating to the request handler,
Me@22 416 * which then does the actual work -- causing the processor that animated
Me@22 417 * the call of this function to disappear and the "hanging" state of this
Me@22 418 * function to just poof into thin air -- the virtual processor's trace
Me@22 419 * never returns from this call, but instead the virtual processor's trace
Me@22 420 * gets suspended in this call and all the virt processor's state disap-
Me@22 421 * pears -- making that suspend the last thing in the virt procr's trace.
Me@8 422 */
Me@8 423 void
Me@53 424 VMS__send_dissipate_req( VirtProcr *procrToDissipate )
Me@50 425 { VMSReqst req;
Me@22 426
Me@50 427 req.reqType = dissipate;
Me@50 428 req.nextReqst = procrToDissipate->requests;
Me@50 429 procrToDissipate->requests = &req;
Me@50 430
Me@22 431 VMS__suspend_procr( procrToDissipate );
Me@50 432 }
Me@50 433
Me@50 434
Me@50 435 /* "ext" designates that it's for use outside the VMS system -- should only
Me@50 436 * be called from main thread or other thread -- never from code animated by
Me@50 437 * a VMS virtual processor.
Me@50 438 *
Me@50 439 *Use this version to dissipate VPs created outside the VMS system.
Me@50 440 */
Me@50 441 void
Me@50 442 VMS_ext__dissipate_procr( VirtProcr *procrToDissipate )
Me@50 443 {
Me@50 444 //NOTE: initialData was given to the processor, so should either have
Me@50 445 // been alloc'd with VMS__malloc, or freed by the level above animPr.
Me@50 446 //So, all that's left to free here is the stack and the VirtProcr struc
Me@50 447 // itself
Me@50 448 //Note, should not stack-allocate initial data -- no guarantee, in
Me@50 449 // general that creating processor will outlive ones it creates.
Me@50 450 free( procrToDissipate->startOfStack );
Me@50 451 free( procrToDissipate );
Me@50 452 }
Me@50 453
Me@22 454
Me@22 455
Me@53 456 /*This call's name indicates that request is malloc'd -- so req handler
Me@53 457 * has to free any extra requests tacked on before a send, using this.
Me@53 458 *
Me@53 459 * This inserts the semantic-layer's request data into standard VMS carrier
Me@53 460 * request data-struct that is mallocd. The sem request doesn't need to
Me@53 461 * be malloc'd if this is called inside the same call chain before the
Me@53 462 * send of the last request is called.
Me@53 463 *
Me@53 464 *The request handler has to call VMS__free_VMSReq for any of these
Me@22 465 */
Me@22 466 inline void
Me@53 467 VMS__add_sem_request_in_mallocd_VMSReqst( void *semReqData,
Me@53 468 VirtProcr *callingPr )
Me@53 469 { VMSReqst *req;
Me@22 470
Me@53 471 req = VMS__malloc( sizeof(VMSReqst) );
Me@53 472 req->reqType = semantic;
Me@53 473 req->semReqData = semReqData;
Me@53 474 req->nextReqst = callingPr->requests;
Me@53 475 callingPr->requests = req;
Me@22 476 }
Me@22 477
Me@50 478 /*This inserts the semantic-layer's request data into standard VMS carrier
Me@50 479 * request data-struct is allocated on stack of this call & ptr to it sent
Me@50 480 * to plugin
Me@50 481 *Then it does suspend, to cause request to be sent.
Me@50 482 */
Me@50 483 inline void
Me@50 484 VMS__send_sem_request( void *semReqData, VirtProcr *callingPr )
Me@50 485 { VMSReqst req;
Me@22 486
Me@50 487 req.reqType = semantic;
Me@50 488 req.semReqData = semReqData;
Me@50 489 req.nextReqst = callingPr->requests;
Me@50 490 callingPr->requests = &req;
Me@50 491
Me@50 492 VMS__suspend_procr( callingPr );
Me@50 493 }
Me@50 494
Me@50 495
Me@50 496 inline void
Me@50 497 VMS__send_VMSSem_request( void *semReqData, VirtProcr *callingPr )
Me@50 498 { VMSReqst req;
Me@50 499
Me@50 500 req.reqType = VMSSemantic;
Me@50 501 req.semReqData = semReqData;
Me@50 502 req.nextReqst = callingPr->requests; //gab any other preceeding
Me@50 503 callingPr->requests = &req;
Me@50 504
Me@50 505 VMS__suspend_procr( callingPr );
Me@50 506 }
Me@50 507
Me@120 508 void inline
Me@120 509 VMS__send_inter_plugin_req( void *reqData, int32 targetMaster,
Me@120 510 VirtProcr *requestingMaster )
Me@120 511 { _VMSMasterEnv->interMasterRequestsFor[targetMaster] =
Me@120 512 (InterMasterReqst *) reqData;
Me@120 513 }
Me@120 514
Me@120 515 void inline
Me@120 516 VMS__send_inter_VMSCore_req( InterVMSCoreReqst *reqData,
Me@120 517 int32 targetMaster, VirtProcr *requestingMaster )
Me@120 518 { _VMSMasterEnv->interMasterRequestsFor[targetMaster] =
Me@120 519 (InterMasterReqst *) reqData;
Me@120 520 }
Me@50 521
Me@50 522 /*
Me@38 523 */
Me@24 524 VMSReqst *
Me@50 525 VMS__take_next_request_out_of( VirtProcr *procrWithReq )
Me@31 526 { VMSReqst *req;
Me@31 527
Me@31 528 req = procrWithReq->requests;
Me@38 529 if( req == NULL ) return NULL;
Me@31 530
Me@31 531 procrWithReq->requests = procrWithReq->requests->nextReqst;
Me@50 532 return req;
Me@24 533 }
Me@22 534
Me@24 535
Me@24 536 inline void *
Me@24 537 VMS__take_sem_reqst_from( VMSReqst *req )
Me@24 538 {
Me@24 539 return req->semReqData;
Me@24 540 }
Me@24 541
Me@24 542
Me@24 543
Me@50 544 /* This is for OS requests and VMS infrastructure requests, such as to create
Me@50 545 * a probe -- a probe is inside the heart of VMS-core, it's not part of any
Me@50 546 * language -- but it's also a semantic thing that's triggered from and used
Me@50 547 * in the application.. so it crosses abstractions.. so, need some special
Me@50 548 * pattern here for handling such requests.
Me@52 549 * Doing this just like it were a second language sharing VMS-core.
Me@52 550 *
Me@50 551 * This is called from the language's request handler when it sees a request
Me@50 552 * of type VMSSemReq
Me@52 553 *
Me@52 554 * TODO: Later change this, to give probes their own separate plugin & have
Me@52 555 * VMS-core steer the request to appropriate plugin
Me@52 556 * Do the same for OS calls -- look later at it..
Me@50 557 */
Me@50 558 void inline
Me@50 559 VMS__handle_VMSSemReq( VMSReqst *req, VirtProcr *requestingPr, void *semEnv,
Me@50 560 ResumePrFnPtr resumePrFnPtr )
Me@50 561 { VMSSemReq *semReq;
Me@50 562 IntervalProbe *newProbe;
Me@24 563
Me@50 564 semReq = req->semReqData;
Me@24 565
msach@135 566 switch(semReq->reqType){
msach@135 567 case createProbe:
msach@135 568 newProbe = VMS__malloc( sizeof(IntervalProbe) );
msach@135 569 newProbe->nameStr = VMS__strDup( (char*)semReq->data );
msach@135 570 newProbe->hist = NULL;
msach@135 571 newProbe->schedChoiceWasRecorded = FALSE;
Me@53 572
msach@135 573 //This runs in masterVP, so no race-condition worries
msach@135 574 newProbe->probeID =
msach@135 575 addToDynArray( newProbe, _VMSMasterEnv->dynIntervalProbesInfo );
msach@135 576 requestingPr->dataRetFromReq = newProbe;
msach@135 577 break;
msach@135 578 case interMasterReqst:
msach@135 579 sendInterMasterReqst(semReq->receiverID,
msach@135 580 (InterMasterReqst*)semReq->data);
msach@135 581 break;
msach@135 582 default:
msach@135 583 break;
msach@135 584 }
msach@135 585
msach@135 586 resumePrFnPtr( requestingPr, semEnv );
Me@22 587 }
Me@22 588
Me@22 589
Me@22 590
Me@24 591 /*This must be called by the request handler plugin -- it cannot be called
Me@24 592 * from the semantic library "dissipate processor" function -- instead, the
Me@50 593 * semantic layer has to generate a request, and the plug-in calls this
Me@24 594 * function.
Me@24 595 *The reason is that this frees the virtual processor's stack -- which is
Me@24 596 * still in use inside semantic library calls!
Me@24 597 *
Me@24 598 *This frees or recycles all the state owned by and comprising the VMS
Me@24 599 * portion of the animating virtual procr. The request handler must first
Me@24 600 * free any semantic data created for the processor that didn't use the
Me@24 601 * VMS_malloc mechanism. Then it calls this, which first asks the malloc
Me@24 602 * system to disown any state that did use VMS_malloc, and then frees the
Me@24 603 * statck and the processor-struct itself.
Me@24 604 *If the dissipated processor is the sole (remaining) owner of VMS__malloc'd
Me@24 605 * state, then that state gets freed (or sent to recycling) as a side-effect
Me@24 606 * of dis-owning it.
Me@24 607 */
Me@24 608 void
Me@53 609 VMS__dissipate_procr( VirtProcr *animatingPr )
Me@24 610 {
Me@24 611 //dis-own all locations owned by this processor, causing to be freed
Me@24 612 // any locations that it is (was) sole owner of
Me@29 613 //TODO: implement VMS__malloc system, including "give up ownership"
Me@24 614
Me@24 615
Me@24 616 //NOTE: initialData was given to the processor, so should either have
Me@24 617 // been alloc'd with VMS__malloc, or freed by the level above animPr.
Me@24 618 //So, all that's left to free here is the stack and the VirtProcr struc
Me@24 619 // itself
Me@50 620 //Note, should not stack-allocate initial data -- no guarantee, in
Me@50 621 // general that creating processor will outlive ones it creates.
msach@135 622
msach@135 623
msach@135 624 /*
msach@135 625 * call the core specific version, because the creating master can already be dead
msach@135 626 */
msach@135 627 //VMS__free_in_lib( animatingPr->startOfStack, animatingPr );
msach@135 628 //VMS__free_in_lib( animatingPr, animatingPr);
Me@24 629 }
Me@24 630
Me@24 631
Me@53 632 //TODO: look at architecting cleanest separation between request handler
Me@29 633 // and master loop, for dissipate, create, shutdown, and other non-semantic
Me@29 634 // requests. Issue is chain: one removes requests from AppVP, one dispatches
Me@29 635 // on type of request, and one handles each type.. but some types require
Me@29 636 // action from both request handler and master loop -- maybe just give the
Me@29 637 // request handler calls like: VMS__handle_X_request_type
Me@24 638
Me@29 639
Me@29 640 /*This is called by the semantic layer's request handler when it decides its
Me@29 641 * time to shut down the VMS system. Calling this causes the core loop OS
Me@29 642 * threads to exit, which unblocks the entry-point function that started up
Me@29 643 * VMS, and allows it to grab the result and return to the original single-
Me@29 644 * threaded application.
Me@22 645 *
Me@29 646 *The _VMSMasterEnv is needed by this shut down function, so the create-seed-
Me@29 647 * and-wait function has to free a bunch of stuff after it detects the
Me@29 648 * threads have all died: the masterEnv, the thread-related locations,
Me@29 649 * masterVP any AppVPs that might still be allocated and sitting in the
Me@29 650 * semantic environment, or have been orphaned in the _VMSWorkQ.
Me@29 651 *
Me@53 652 *NOTE: the semantic plug-in is expected to use VMS__malloc to get all the
Me@29 653 * locations it needs, and give ownership to masterVP. Then, they will be
Me@53 654 * automatically freed.
Me@22 655 *
Me@29 656 *In here,create one core-loop shut-down processor for each core loop and put
Me@31 657 * them all directly into the readyToAnimateQ.
Me@29 658 *Note, this function can ONLY be called after the semantic environment no
Me@29 659 * longer cares if AppVPs get animated after the point this is called. In
Me@29 660 * other words, this can be used as an abort, or else it should only be
Me@29 661 * called when all AppVPs have finished dissipate requests -- only at that
Me@29 662 * point is it sure that all results have completed.
Me@22 663 */
Me@22 664 void
Me@53 665 VMS__shutdown()
Me@8 666 { int coreIdx;
Me@14 667 VirtProcr *shutDownPr;
Me@22 668
Me@29 669 //create the shutdown processors, one for each core loop -- put them
Me@31 670 // directly into the Q -- each core will die when gets one
Me@8 671 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
Me@50 672 { //Note, this is running in the master
Me@29 673 shutDownPr = VMS__create_procr( &endOSThreadFn, NULL );
Me@55 674 writeVMSQ( shutDownPr, _VMSMasterEnv->readyToAnimateQs[coreIdx] );
Me@8 675 }
Me@22 676
Me@12 677 }
Me@12 678
Me@12 679
Me@29 680 /*Am trying to be cute, avoiding IF statement in coreLoop that checks for
Me@29 681 * a special shutdown procr. Ended up with extra-complex shutdown sequence.
Me@29 682 *This function has the sole purpose of setting the stack and framePtr
Me@29 683 * to the coreLoop's stack and framePtr.. it does that then jumps to the
Me@29 684 * core loop's shutdown point -- might be able to just call Pthread_exit
Me@30 685 * from here, but am going back to the pthread's stack and setting everything
Me@29 686 * up just as if it never jumped out, before calling pthread_exit.
Me@29 687 *The end-point of core loop will free the stack and so forth of the
Me@29 688 * processor that animates this function, (this fn is transfering the
Me@29 689 * animator of the AppVP that is in turn animating this function over
Me@29 690 * to core loop function -- note that this slices out a level of virtual
Me@29 691 * processors).
Me@29 692 */
Me@29 693 void
Me@29 694 endOSThreadFn( void *initData, VirtProcr *animatingPr )
msach@71 695 {
msach@75 696 #ifdef SEQUENTIAL
msach@75 697 asmTerminateCoreLoopSeq(animatingPr);
msach@75 698 #else
msach@71 699 asmTerminateCoreLoop(animatingPr);
msach@75 700 #endif
Me@30 701 }
Me@29 702
Me@29 703
Me@53 704 /*This is called from the startup & shutdown
Me@24 705 */
Me@24 706 void
Me@53 707 VMS__cleanup_at_end_of_shutdown()
Me@31 708 {
msach@78 709 //unused
msach@78 710 //VMSQueueStruc **readyToAnimateQs;
msach@78 711 //int coreIdx;
msach@78 712 //VirtProcr **masterVPs;
msach@78 713 //SchedSlot ***allSchedSlots; //ptr to array of ptrs
Me@31 714
Me@65 715 //Before getting rid of everything, print out any measurements made
msach@69 716 forAllInDynArrayDo( _VMSMasterEnv->measHistsInfo, (DynArrayFnPtr)&printHist );
msach@78 717 forAllInDynArrayDo( _VMSMasterEnv->measHistsInfo, (DynArrayFnPtr)&saveHistToFile);
Me@68 718 //forAllInDynArrayDo( _VMSMasterEnv->measHistsInfo, &freeHistExt );
Me@65 719 #ifdef MEAS__TIME_PLUGIN
Me@68 720 printHist( _VMSMasterEnv->reqHdlrLowTimeHist );
msach@84 721 saveHistToFile( _VMSMasterEnv->reqHdlrLowTimeHist );
Me@68 722 printHist( _VMSMasterEnv->reqHdlrHighTimeHist );
msach@79 723 saveHistToFile( _VMSMasterEnv->reqHdlrHighTimeHist );
Me@68 724 freeHistExt( _VMSMasterEnv->reqHdlrLowTimeHist );
Me@68 725 freeHistExt( _VMSMasterEnv->reqHdlrHighTimeHist );
Me@65 726 #endif
Me@65 727 #ifdef MEAS__TIME_MALLOC
Me@65 728 printHist( _VMSMasterEnv->mallocTimeHist );
msach@79 729 saveHistToFile( _VMSMasterEnv->mallocTimeHist );
Me@65 730 printHist( _VMSMasterEnv->freeTimeHist );
msach@79 731 saveHistToFile( _VMSMasterEnv->freeTimeHist );
Me@65 732 freeHistExt( _VMSMasterEnv->mallocTimeHist );
Me@65 733 freeHistExt( _VMSMasterEnv->freeTimeHist );
Me@65 734 #endif
Me@65 735 #ifdef MEAS__TIME_MASTER_LOCK
Me@65 736 printHist( _VMSMasterEnv->masterLockLowTimeHist );
Me@65 737 printHist( _VMSMasterEnv->masterLockHighTimeHist );
Me@65 738 #endif
Me@65 739 #ifdef MEAS__TIME_MASTER
Me@65 740 printHist( _VMSMasterEnv->pluginTimeHist );
Me@65 741 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
Me@65 742 {
Me@65 743 freeVMSQ( readyToAnimateQs[ coreIdx ] );
Me@65 744 //master VPs were created external to VMS, so use external free
Me@65 745 VMS__dissipate_procr( masterVPs[ coreIdx ] );
Me@65 746
Me@65 747 freeSchedSlots( allSchedSlots[ coreIdx ] );
Me@65 748 }
Me@65 749 #endif
Me@65 750 #ifdef MEAS__TIME_STAMP_SUSP
Me@65 751 printHist( _VMSMasterEnv->pluginTimeHist );
Me@65 752 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
Me@65 753 {
Me@65 754 freeVMSQ( readyToAnimateQs[ coreIdx ] );
Me@65 755 //master VPs were created external to VMS, so use external free
Me@65 756 VMS__dissipate_procr( masterVPs[ coreIdx ] );
Me@65 757
Me@65 758 freeSchedSlots( allSchedSlots[ coreIdx ] );
Me@65 759 }
Me@65 760 #endif
Me@65 761
Me@53 762 //All the environment data has been allocated with VMS__malloc, so just
Me@53 763 // free its internal big-chunk and all inside it disappear.
Me@53 764 /*
Me@31 765 readyToAnimateQs = _VMSMasterEnv->readyToAnimateQs;
Me@31 766 masterVPs = _VMSMasterEnv->masterVPs;
Me@31 767 allSchedSlots = _VMSMasterEnv->allSchedSlots;
Me@31 768
Me@31 769 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
Me@24 770 {
Me@55 771 freeVMSQ( readyToAnimateQs[ coreIdx ] );
Me@50 772 //master VPs were created external to VMS, so use external free
Me@53 773 VMS__dissipate_procr( masterVPs[ coreIdx ] );
Me@31 774
Me@31 775 freeSchedSlots( allSchedSlots[ coreIdx ] );
Me@24 776 }
Me@31 777
Me@53 778 VMS__free( _VMSMasterEnv->readyToAnimateQs );
Me@53 779 VMS__free( _VMSMasterEnv->masterVPs );
Me@53 780 VMS__free( _VMSMasterEnv->allSchedSlots );
Me@50 781
Me@50 782 //============================= MEASUREMENT STUFF ========================
Me@50 783 #ifdef STATS__TURN_ON_PROBES
Me@53 784 freeDynArrayDeep( _VMSMasterEnv->dynIntervalProbesInfo, &VMS__free_probe);
Me@50 785 #endif
Me@50 786 //========================================================================
Me@53 787 */
Me@53 788 //These are the only two that use system free
msach@135 789 int i;
msach@135 790 for(i=0; i<NUM_CORES; i++)
msach@135 791 VMS_ext__free_free_list( _VMSMasterEnv->freeListHead[i]);
Me@53 792 free( (void *)_VMSMasterEnv );
Me@24 793 }
Me@24 794
Me@54 795
Me@54 796 //================================
Me@54 797
Me@54 798
Me@54 799 /*Later, improve this -- for now, just exits the application after printing
Me@54 800 * the error message.
Me@54 801 */
Me@54 802 void
Me@54 803 VMS__throw_exception( char *msgStr, VirtProcr *reqstPr, VMSExcp *excpData )
Me@54 804 {
msach@69 805 printf("%s",msgStr);
Me@54 806 fflush(stdin);
Me@54 807 exit(1);
Me@54 808 }
Me@54 809