diff VMS.c @ 50:8f7141a9272e

Added VMS__malloc and probes, and major re-factoring to separate mallocs
author Me
date Sat, 30 Oct 2010 20:54:36 -0700
parents cf3e9238aeb0
children f59cfa31a579
line diff
     1.1 --- a/VMS.c	Thu Oct 14 17:07:23 2010 -0700
     1.2 +++ b/VMS.c	Sat Oct 30 20:54:36 2010 -0700
     1.3 @@ -6,7 +6,9 @@
     1.4  
     1.5  #include <stdio.h>
     1.6  #include <stdlib.h>
     1.7 +#include <string.h>
     1.8  #include <malloc.h>
     1.9 +#include <sys/time.h>
    1.10  
    1.11  #include "VMS.h"
    1.12  #include "Queue_impl/BlockingQueue.h"
    1.13 @@ -28,6 +30,10 @@
    1.14  void
    1.15  create_the_coreLoop_OS_threads();
    1.16  
    1.17 +MallocProlog *
    1.18 +create_free_list();
    1.19 +
    1.20 +
    1.21  pthread_mutex_t suspendLock = PTHREAD_MUTEX_INITIALIZER;
    1.22  pthread_cond_t  suspend_cond  = PTHREAD_COND_INITIALIZER;
    1.23  
    1.24 @@ -100,67 +106,47 @@
    1.25     allSchedSlots    = malloc( NUM_CORES * sizeof(SchedSlot *) );
    1.26  
    1.27     for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
    1.28 -    {
    1.29 +    {    //running in main thread -- normal malloc inside makeSRSWQ
    1.30        readyToAnimateQs[ coreIdx ] = makeSRSWQ();
    1.31        
    1.32 -         //Q: should give masterVP core-specific into as its init data?
    1.33 -      masterVPs[ coreIdx ] = VMS__create_procr( &masterLoop, masterEnv );
    1.34 +         //Q: should give masterVP core-specific info as its init data?
    1.35 +      masterVPs[ coreIdx ] = VMS_ext__create_procr( &masterLoop, masterEnv );
    1.36        masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx;
    1.37        allSchedSlots[ coreIdx ] = create_sched_slots(); //makes for one core
    1.38 +      _VMSMasterEnv->numMasterInARow[ coreIdx ] = FALSE;
    1.39      }
    1.40     _VMSMasterEnv->readyToAnimateQs = readyToAnimateQs;
    1.41     _VMSMasterEnv->masterVPs        = masterVPs;
    1.42 +   _VMSMasterEnv->masterLock       = UNLOCKED;
    1.43     _VMSMasterEnv->allSchedSlots    = allSchedSlots;
    1.44 -
    1.45 +   _VMSMasterEnv->numProcrsCreated = 0;
    1.46  
    1.47  
    1.48        //Aug 19, 2010:  no longer need to place initial masterVP into queue
    1.49        // because coreLoop now controls -- animates its masterVP when no work
    1.50  
    1.51 +   _VMSMasterEnv->freeListHead        = VMS__create_free_list();
    1.52 +   _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
    1.53  
    1.54 -   //==================== malloc substitute ========================
    1.55 -   //
    1.56 -   //Testing whether malloc is using thread-local storage and therefore
    1.57 -   // causing unreliable behavior.
    1.58 -   //Just allocate a massive chunk of memory and roll own malloc/free and
    1.59 -   // make app use VMS__malloc_to, which will suspend and perform malloc
    1.60 -   // in the master, taking from this massive chunk.
    1.61 +   //============================= MEASUREMENT STUFF ========================
    1.62 +   #ifdef STATS__TURN_ON_PROBES
    1.63 +      //creates intervalProbes array and sets pointer to it in masterEnv too
    1.64 +   _VMSMasterEnv->dynIntervalProbesInfo =
    1.65 +                  makeDynArrayOfSize( &(_VMSMasterEnv->intervalProbes), 20 );
    1.66  
    1.67 -//   initFreeList();
    1.68 +   _VMSMasterEnv->probeNameHashTbl = makeHashTable( 1000, NULL );
    1.69 +   _VMSMasterEnv->masterCreateProbeID =
    1.70 +       VMS_ext__record_time_point_into_new_probe( "masterCreateProbe" );
    1.71 +      //Also put creation time directly into master env, for fast retrieval
    1.72 +   struct timeval timeStamp;
    1.73 +   gettimeofday( &(timeStamp), NULL);
    1.74 +   _VMSMasterEnv->createPtInSecs =
    1.75 +                           timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0);
    1.76 +   #endif
    1.77 +   //========================================================================
    1.78  
    1.79   }
    1.80  
    1.81 -/*
    1.82 -void
    1.83 -initMasterMalloc()
    1.84 - {
    1.85 -   _VMSMasterEnv->mallocChunk = malloc( MASSIVE_MALLOC_SIZE );
    1.86 -
    1.87 -      //The free-list element is the first several locations of an
    1.88 -      // allocated chunk -- the address given to the application is pre-
    1.89 -      // pended with both the ownership structure and the free-list struc.
    1.90 -      //So, write the values of these into the first locations of
    1.91 -      // mallocChunk -- which marks it as free & puts in its size.
    1.92 -   listElem = (FreeListElem *)_VMSMasterEnv->mallocChunk;
    1.93 -   listElem->size = MASSIVE_MALLOC_SIZE - NUM_PREPEND_BYTES
    1.94 -   listElem->next = NULL;
    1.95 - }
    1.96 -
    1.97 -void
    1.98 -dissipateMasterMalloc()
    1.99 - {
   1.100 -      //Just foo code -- to get going -- doing as if free list were link-list
   1.101 -   currElem = _VMSMasterEnv->freeList;
   1.102 -   while( currElem != NULL )
   1.103 -    {
   1.104 -      nextElem = currElem->next;
   1.105 -      masterFree( currElem );
   1.106 -      currElem = nextElem;
   1.107 -    }
   1.108 -   free( _VMSMasterEnv->freeList );
   1.109 - }
   1.110 - */
   1.111 -
   1.112  SchedSlot **
   1.113  create_sched_slots()
   1.114   { SchedSlot  **schedSlots;
   1.115 @@ -213,7 +199,7 @@
   1.116                          thdAttrs,
   1.117                         &coreLoop,
   1.118                 (void *)(coreLoopThdParams[coreIdx]) );
   1.119 -      if(retCode){printf("ERROR creating thread: %d\n", retCode); exit(0);}
   1.120 +      if(retCode){printf("ERROR creating thread: %d\n", retCode); exit(1);}
   1.121      }
   1.122   }
   1.123  
   1.124 @@ -225,12 +211,6 @@
   1.125  VMS__start_the_work_then_wait_until_done()
   1.126   { int coreIdx;
   1.127        //Start the core loops running
   1.128 -//===========================================================================
   1.129 -   TSCount  startCount, endCount;
   1.130 -   unsigned long long count = 0, freq = 0;
   1.131 -   double   runTime;
   1.132 -
   1.133 -      startCount = getTSCount();
   1.134     
   1.135        //tell the core loop threads that setup is complete
   1.136        //get lock, to lock out any threads still starting up -- they'll see
   1.137 @@ -251,14 +231,6 @@
   1.138        //NOTE: do not clean up VMS env here -- semantic layer has to have
   1.139        // a chance to clean up its environment first, then do a call to free
   1.140        // the Master env and rest of VMS locations
   1.141 -
   1.142 -
   1.143 -      endCount = getTSCount();
   1.144 -      count = endCount - startCount;
   1.145 -
   1.146 -      runTime = (double)count / (double)TSCOUNT_FREQ;
   1.147 -
   1.148 -      printf("\n Time startup to shutdown: %f\n", runTime); fflush( stdin );
   1.149   }
   1.150  
   1.151  /*Only difference between version with an OS thread pinned to each core and
   1.152 @@ -285,37 +257,73 @@
   1.153   * animator state to return to --
   1.154   *
   1.155   */
   1.156 -VirtProcr *
   1.157 -VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   1.158 - { VirtProcr *newPr;
   1.159 -   char      *stackLocs, *stackPtr;
   1.160 +inline VirtProcr *
   1.161 +create_procr_helper( VirtProcr *newPr,       VirtProcrFnPtr  fnPtr,
   1.162 +                     void      *initialData, char           *stackLocs )
   1.163 + {
   1.164 +   char  *stackPtr;
   1.165  
   1.166 -   newPr              = malloc( sizeof(VirtProcr) );
   1.167 -   newPr->procrID     = numProcrsCreated++;
   1.168 +   newPr->procrID     = _VMSMasterEnv->numProcrsCreated++;
   1.169     newPr->nextInstrPt = fnPtr;
   1.170     newPr->initialData = initialData;
   1.171     newPr->requests    = NULL;
   1.172     newPr->schedSlot   = NULL;
   1.173 -//   newPr->coreLoopStartPt = _VMSMasterEnv->coreLoopStartPt;
   1.174  
   1.175        //fnPtr takes two params -- void *initData & void *animProcr
   1.176        //alloc stack locations, make stackPtr be the highest addr minus room
   1.177        // for 2 params + return addr.  Return addr (NULL) is in loc pointed to
   1.178        // by stackPtr, initData at stackPtr + 4 bytes, animatingPr just above
   1.179 -   stackLocs = malloc( VIRT_PROCR_STACK_SIZE );
   1.180 -   if(stackLocs == 0)
   1.181 -   {perror("malloc stack"); exit(1);}
   1.182 -   newPr->startOfStack = stackLocs;
   1.183     stackPtr = ( (char *)stackLocs + VIRT_PROCR_STACK_SIZE - 0x10 );
   1.184 +   
   1.185        //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp
   1.186     *( (int *)stackPtr + 2 ) = (int) newPr; //rightmost param -- 32bit pointer
   1.187     *( (int *)stackPtr + 1 ) = (int) initialData;  //next  param to left
   1.188     newPr->stackPtr = stackPtr; //core loop will switch to this, then
   1.189     newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr
   1.190  
   1.191 +   //============================= MEASUREMENT STUFF ========================
   1.192 +   #ifdef STATS__TURN_ON_PROBES
   1.193 +   struct timeval timeStamp;
   1.194 +   gettimeofday( &(timeStamp), NULL);
   1.195 +   newPr->createPtInSecs = timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0);
   1.196 +   #endif
   1.197 +   //========================================================================
   1.198 +
   1.199     return newPr;
   1.200   }
   1.201  
   1.202 +inline VirtProcr *
   1.203 +VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   1.204 + { VirtProcr *newPr;
   1.205 +   char      *stackLocs;
   1.206 +
   1.207 +   newPr      = VMS__malloc( sizeof(VirtProcr) );
   1.208 +   stackLocs  = VMS__malloc( VIRT_PROCR_STACK_SIZE );
   1.209 +   if( stackLocs == 0 )
   1.210 +    { perror("VMS__malloc stack"); exit(1); }
   1.211 +   newPr->startOfStack = stackLocs;
   1.212 +
   1.213 +   return create_procr_helper( newPr, fnPtr, initialData, stackLocs );
   1.214 + }
   1.215 +
   1.216 +/* "ext" designates that it's for use outside the VMS system -- should only
   1.217 + * be called from main thread or other thread -- never from code animated by
   1.218 + * a VMS virtual processor.
   1.219 + */
   1.220 +inline VirtProcr *
   1.221 +VMS_ext__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   1.222 + { VirtProcr *newPr;
   1.223 +   char      *stackLocs;
   1.224 +
   1.225 +   newPr      = malloc( sizeof(VirtProcr) );
   1.226 +   stackLocs  = malloc( VIRT_PROCR_STACK_SIZE );
   1.227 +   if( stackLocs == 0 )
   1.228 +    { perror("malloc stack"); exit(1); }
   1.229 +   newPr->startOfStack = stackLocs;
   1.230 +
   1.231 +   return create_procr_helper( newPr, fnPtr, initialData, stackLocs );
   1.232 + }
   1.233 +
   1.234  
   1.235  /*there is a label inside this function -- save the addr of this label in
   1.236   * the callingPr struc, as the pick-up point from which to start the next
   1.237 @@ -339,7 +347,6 @@
   1.238  
   1.239        //return ownership of the virt procr and sched slot to Master virt pr
   1.240     animatingPr->schedSlot->workIsDone = TRUE;
   1.241 -//   coreIdx = callingPr->coreAnimatedBy;
   1.242  
   1.243     stackPtrAddr      = &(animatingPr->stackPtr);
   1.244     framePtrAddr      = &(animatingPr->framePtr);
   1.245 @@ -390,6 +397,31 @@
   1.246  
   1.247  
   1.248  
   1.249 +/*For this implementation of VMS, it may not make much sense to have the
   1.250 + * system of requests for creating a new processor done this way.. but over
   1.251 + * the scope of single-master, multi-master, mult-tasking, OS-implementing,
   1.252 + * distributed-memory, and so on, this gives VMS implementation a chance to
   1.253 + * do stuff before suspend, in the AppVP, and in the Master before the plugin
   1.254 + * is called, as well as in the lang-lib before this is called, and in the
   1.255 + * plugin.  So, this gives both VMS and language implementations a chance to
   1.256 + * intercept at various points and do order-dependent stuff.
   1.257 + *Having a standard VMSNewPrReqData struc allows the language to create and
   1.258 + * free the struc, while VMS knows how to get the newPr if it wants it, and
   1.259 + * it lets the lang have lang-specific data related to creation transported
   1.260 + * to the plugin.
   1.261 + */
   1.262 +void
   1.263 +VMS__send_create_procr_req( void *semReqData, VirtProcr *reqstingPr )
   1.264 + { VMSReqst req;
   1.265 +
   1.266 +   req.reqType          = createReq;
   1.267 +   req.semReqData       = semReqData;
   1.268 +   req.nextReqst        = reqstingPr->requests;
   1.269 +   reqstingPr->requests = &req;
   1.270 +
   1.271 +   VMS__suspend_procr( reqstingPr );
   1.272 + }
   1.273 +
   1.274  
   1.275  /*
   1.276   *This adds a request to dissipate, then suspends the processor so that the
   1.277 @@ -414,80 +446,93 @@
   1.278   */
   1.279  void
   1.280  VMS__dissipate_procr( VirtProcr *procrToDissipate )
   1.281 - { VMSReqst *req;
   1.282 + { VMSReqst req;
   1.283  
   1.284 -   req = malloc( sizeof(VMSReqst) );
   1.285 -//   req->virtProcrFrom      = callingPr;
   1.286 -   req->reqType               = dissipate;
   1.287 -   req->nextReqst             = procrToDissipate->requests;
   1.288 -   procrToDissipate->requests = req;
   1.289 -   
   1.290 +   req.reqType                = dissipate;
   1.291 +   req.nextReqst              = procrToDissipate->requests;
   1.292 +   procrToDissipate->requests = &req;
   1.293 +
   1.294     VMS__suspend_procr( procrToDissipate );
   1.295 -}
   1.296 + }
   1.297 +
   1.298 +
   1.299 +/* "ext" designates that it's for use outside the VMS system -- should only
   1.300 + * be called from main thread or other thread -- never from code animated by
   1.301 + * a VMS virtual processor.
   1.302 + *
   1.303 + *Use this version to dissipate VPs created outside the VMS system.
   1.304 + */
   1.305 +void
   1.306 +VMS_ext__dissipate_procr( VirtProcr *procrToDissipate )
   1.307 + {
   1.308 +      //NOTE: initialData was given to the processor, so should either have
   1.309 +      // been alloc'd with VMS__malloc, or freed by the level above animPr.
   1.310 +      //So, all that's left to free here is the stack and the VirtProcr struc
   1.311 +      // itself
   1.312 +      //Note, should not stack-allocate initial data -- no guarantee, in
   1.313 +      // general that creating processor will outlive ones it creates.
   1.314 +   free( procrToDissipate->startOfStack );
   1.315 +   free( procrToDissipate );
   1.316 + }
   1.317 +
   1.318  
   1.319  
   1.320  /*This inserts the semantic-layer's request data into standard VMS carrier
   1.321 + * request data-struct is allocated on stack of this call & ptr to it sent
   1.322 + * to plugin
   1.323   */
   1.324  inline void
   1.325  VMS__add_sem_request( void *semReqData, VirtProcr *callingPr )
   1.326 - { VMSReqst *req;
   1.327 + { VMSReqst req;
   1.328  
   1.329 -   req = malloc( sizeof(VMSReqst) );
   1.330 -//   req->virtProcrFrom      = callingPr;
   1.331 -   req->reqType        = semantic;
   1.332 -   req->semReqData     = semReqData;
   1.333 -   req->nextReqst      = callingPr->requests;
   1.334 -   callingPr->requests = req;
   1.335 +   req.reqType         = semantic;
   1.336 +   req.semReqData      = semReqData;
   1.337 +   req.nextReqst       = callingPr->requests;
   1.338 +   callingPr->requests = &req;
   1.339   }
   1.340  
   1.341 +/*This inserts the semantic-layer's request data into standard VMS carrier
   1.342 + * request data-struct is allocated on stack of this call & ptr to it sent
   1.343 + * to plugin
   1.344 + *Then it does suspend, to cause request to be sent.
   1.345 + */
   1.346 +inline void
   1.347 +VMS__send_sem_request( void *semReqData, VirtProcr *callingPr )
   1.348 + { VMSReqst req;
   1.349  
   1.350 -/*Use this to get first request before starting request handler's loop
   1.351 +   req.reqType         = semantic;
   1.352 +   req.semReqData      = semReqData;
   1.353 +   req.nextReqst       = callingPr->requests;
   1.354 +   callingPr->requests = &req;
   1.355 +   
   1.356 +   VMS__suspend_procr( callingPr );
   1.357 + }
   1.358 +
   1.359 +
   1.360 +inline void
   1.361 +VMS__send_VMSSem_request( void *semReqData, VirtProcr *callingPr )
   1.362 + { VMSReqst req;
   1.363 +
   1.364 +   req.reqType         = VMSSemantic;
   1.365 +   req.semReqData      = semReqData;
   1.366 +   req.nextReqst       = callingPr->requests; //gab any other preceeding 
   1.367 +   callingPr->requests = &req;
   1.368 +
   1.369 +   VMS__suspend_procr( callingPr );
   1.370 + }
   1.371 +
   1.372 +
   1.373 +/*
   1.374   */
   1.375  VMSReqst *
   1.376 -VMS__take_top_request_from( VirtProcr *procrWithReq )
   1.377 - { VMSReqst *req;
   1.378 -
   1.379 -   req = procrWithReq->requests;
   1.380 -   if( req == NULL ) return req;
   1.381 -
   1.382 -   procrWithReq->requests = procrWithReq->requests->nextReqst;
   1.383 -   return req;
   1.384 - }
   1.385 -
   1.386 -/*A subtle bug due to freeing then accessing "next" after freed caused this
   1.387 - * form of call to be put in -- so call this at end of request handler loop
   1.388 - * that iterates through the requests.
   1.389 - */
   1.390 -VMSReqst *
   1.391 -VMS__free_top_and_give_next_request_from( VirtProcr *procrWithReq )
   1.392 +VMS__take_next_request_out_of( VirtProcr *procrWithReq )
   1.393   { VMSReqst *req;
   1.394  
   1.395     req = procrWithReq->requests;
   1.396     if( req == NULL ) return NULL;
   1.397  
   1.398     procrWithReq->requests = procrWithReq->requests->nextReqst;
   1.399 -   VMS__free_request( req );
   1.400 -   return procrWithReq->requests;
   1.401 - }
   1.402 -
   1.403 -
   1.404 -//TODO: add a semantic-layer supplied "freer" for the semantic-data portion
   1.405 -// of a request -- IE call with both a virt procr and a fn-ptr to request
   1.406 -// freer (also maybe put sem request freer as a field in virt procr?)
   1.407 -//MeasVMS relies right now on this only freeing VMS layer of request -- the
   1.408 -// semantic portion of request is alloc'd and freed by request handler
   1.409 -void
   1.410 -VMS__free_request( VMSReqst *req )
   1.411 - {
   1.412 -   free( req );
   1.413 - }
   1.414 -
   1.415 -
   1.416 -
   1.417 -inline int
   1.418 -VMS__isSemanticReqst( VMSReqst *req )
   1.419 - {
   1.420 -   return ( req->reqType == semantic );
   1.421 +   return req;
   1.422   }
   1.423  
   1.424  
   1.425 @@ -497,36 +542,44 @@
   1.426     return req->semReqData;
   1.427   }
   1.428  
   1.429 -inline int
   1.430 -VMS__isDissipateReqst( VMSReqst *req )
   1.431 - {
   1.432 -   return ( req->reqType == dissipate );
   1.433 - }
   1.434  
   1.435 -inline int
   1.436 -VMS__isCreateReqst( VMSReqst *req )
   1.437 - {
   1.438 -   return ( req->reqType == regCreated );
   1.439 - }
   1.440  
   1.441 -void
   1.442 -VMS__send_req_to_register_new_procr(VirtProcr *newPr, VirtProcr *reqstingPr)
   1.443 - { VMSReqst *req;
   1.444 +/* This is for OS requests and VMS infrastructure requests, such as to create
   1.445 + *  a probe -- a probe is inside the heart of VMS-core, it's not part of any
   1.446 + *  language -- but it's also a semantic thing that's triggered from and used
   1.447 + *  in the application.. so it crosses abstractions..  so, need some special
   1.448 + *  pattern here for handling such requests.
   1.449 + * This is called from the language's request handler when it sees a request
   1.450 + *  of type VMSSemReq
   1.451 + */
   1.452 +void inline
   1.453 +VMS__handle_VMSSemReq( VMSReqst *req, VirtProcr *requestingPr, void *semEnv,
   1.454 +                       ResumePrFnPtr resumePrFnPtr )
   1.455 + { VMSSemReq     *semReq;
   1.456 +   IntervalProbe *newProbe;
   1.457 +   int32          nameLen;
   1.458  
   1.459 -   req                  = malloc( sizeof(VMSReqst) );
   1.460 -   req->reqType         = regCreated;
   1.461 -   req->semReqData      = newPr;
   1.462 -   req->nextReqst       = reqstingPr->requests;
   1.463 -   reqstingPr->requests = req;
   1.464 +   semReq = req->semReqData;
   1.465  
   1.466 -   VMS__suspend_procr( reqstingPr );
   1.467 +   newProbe          = VMS__malloc( sizeof(IntervalProbe) );
   1.468 +   nameLen = strlen( semReq->nameStr );
   1.469 +   newProbe->nameStr = VMS__malloc( nameLen );
   1.470 +   memcpy( newProbe->nameStr, semReq->nameStr, nameLen );
   1.471 +   newProbe->hist    = NULL;
   1.472 +   newProbe->schedChoiceWasRecorded = FALSE;
   1.473 +   newProbe->probeID =
   1.474 +             addToDynArray( newProbe, _VMSMasterEnv->dynIntervalProbesInfo );
   1.475 +
   1.476 +   requestingPr->dataReturnedFromReq = newProbe;
   1.477 +
   1.478 +   (*resumePrFnPtr)( requestingPr, semEnv );
   1.479   }
   1.480  
   1.481  
   1.482  
   1.483  /*This must be called by the request handler plugin -- it cannot be called
   1.484   * from the semantic library "dissipate processor" function -- instead, the
   1.485 - * semantic layer has to generate a request for the plug-in to call this
   1.486 + * semantic layer has to generate a request, and the plug-in calls this
   1.487   * function.
   1.488   *The reason is that this frees the virtual processor's stack -- which is
   1.489   * still in use inside semantic library calls!
   1.490 @@ -548,15 +601,15 @@
   1.491        // any locations that it is (was) sole owner of
   1.492  //TODO: implement VMS__malloc system, including "give up ownership"
   1.493  
   1.494 -      //The dissipate request might still be attached, so remove and free it
   1.495 -   VMS__free_top_and_give_next_request_from( animatingPr );
   1.496  
   1.497        //NOTE: initialData was given to the processor, so should either have
   1.498        // been alloc'd with VMS__malloc, or freed by the level above animPr.
   1.499        //So, all that's left to free here is the stack and the VirtProcr struc
   1.500        // itself
   1.501 -   free( animatingPr->startOfStack );
   1.502 -   free( animatingPr );
   1.503 +      //Note, should not stack-allocate initial data -- no guarantee, in
   1.504 +      // general that creating processor will outlive ones it creates.
   1.505 +   VMS__free( animatingPr->startOfStack );
   1.506 +   VMS__free( animatingPr );
   1.507   }
   1.508  
   1.509  
   1.510 @@ -603,7 +656,7 @@
   1.511        //create the shutdown processors, one for each core loop -- put them
   1.512        // directly into the Q -- each core will die when gets one
   1.513     for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
   1.514 -    {
   1.515 +    {    //Note, this is running in the master
   1.516        shutDownPr = VMS__create_procr( &endOSThreadFn, NULL );
   1.517        writeSRSWQ( shutDownPr, _VMSMasterEnv->readyToAnimateQs[coreIdx] );
   1.518      }
   1.519 @@ -664,8 +717,8 @@
   1.520     for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   1.521      {
   1.522        freeSRSWQ( readyToAnimateQs[ coreIdx ] );
   1.523 -
   1.524 -      VMS__handle_dissipate_reqst( masterVPs[ coreIdx ] );
   1.525 +         //master VPs were created external to VMS, so use external free
   1.526 +      VMS_ext__dissipate_procr( masterVPs[ coreIdx ] );
   1.527        
   1.528        freeSchedSlots( allSchedSlots[ coreIdx ] );
   1.529      }
   1.530 @@ -673,20 +726,15 @@
   1.531     free( _VMSMasterEnv->readyToAnimateQs );
   1.532     free( _VMSMasterEnv->masterVPs );
   1.533     free( _VMSMasterEnv->allSchedSlots );
   1.534 +   
   1.535 +   VMS_ext__free_free_list( _VMSMasterEnv->freeListHead );
   1.536 +
   1.537 +   //============================= MEASUREMENT STUFF ========================
   1.538 +   #ifdef STATS__TURN_ON_PROBES
   1.539 +   freeDynArrayDeep( _VMSMasterEnv->dynIntervalProbesInfo, &free );
   1.540 +   #endif
   1.541 +   //========================================================================
   1.542  
   1.543     free( _VMSMasterEnv );
   1.544   }
   1.545  
   1.546 -
   1.547 -//===========================================================================
   1.548 -
   1.549 -inline TSCount getTSCount()
   1.550 - { unsigned int low, high;
   1.551 -   TSCount  out;
   1.552 -
   1.553 -   saveTimeStampCountInto( low, high );
   1.554 -   out = high;
   1.555 -   out = (out << 32) + low;
   1.556 -   return out;
   1.557 - }
   1.558 -