diff AnimationMaster.c @ 261:dafae55597ce

Getting closer -- added PRServ as built-in langlet (but still just copy) about to rework a lot of the Master code.. possibly eliminate core controller
author Sean Halle <seanhalle@yahoo.com>
date Tue, 23 Oct 2012 23:46:17 -0700
parents 999f2966a3e5
children a5fa1e087c7e
line diff
     1.1 --- a/AnimationMaster.c	Wed Sep 19 23:12:44 2012 -0700
     1.2 +++ b/AnimationMaster.c	Tue Oct 23 23:46:17 2012 -0700
     1.3 @@ -10,7 +10,10 @@
     1.4  #include <stddef.h>
     1.5  
     1.6  #include "PR.h"
     1.7 +#include "VSs_impl/VSs.h"
     1.8  
     1.9 +inline void
    1.10 +replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv );
    1.11  
    1.12  
    1.13  /*The animationMaster embodies most of the animator of the language.  The
    1.14 @@ -37,7 +40,7 @@
    1.15   *
    1.16   */
    1.17  
    1.18 -
    1.19 +        
    1.20  //=====================  The versions of the Animation Master  =================
    1.21  //
    1.22  //==============================================================================
    1.23 @@ -105,11 +108,11 @@
    1.24   *There is a separate masterVP for each core, but a single semantic
    1.25   * environment shared by all cores.  Each core also has its own scheduling
    1.26   * slots, which are used to communicate slaves between animationMaster and
    1.27 - * coreController.  There is only one global variable, _PRMasterEnv, which
    1.28 + * coreController.  There is only one global variable, _PRTopEnv, which
    1.29   * holds the semantic env and other things shared by the different
    1.30   * masterVPs.  The request handler and Assigner are registered with
    1.31   * the animationMaster by the language's init function, and a pointer to
    1.32 - * each is in the _PRMasterEnv. (There are also some pthread related global
    1.33 + * each is in the _PRTopEnv. (There are also some pthread related global
    1.34   * vars, but they're only used during init of PR).
    1.35   *PR gains control over the cores by essentially "turning off" the OS's
    1.36   * scheduler, using pthread pin-to-core commands.
    1.37 @@ -122,7 +125,7 @@
    1.38   * based application.
    1.39   *The masterVPs share a single system-wide master-lock, so only one
    1.40   * masterVP may be animated at a time.
    1.41 - *The core controllers access _PRMasterEnv to get the masterVP, and when
    1.42 + *The core controllers access _PRTopEnv to get the masterVP, and when
    1.43   * they start, the slots are all empty, so they run their associated core's
    1.44   * masterVP.  The first of those to get the master lock sees the seed slave
    1.45   * in the shared semantic environment, so when it runs the Assigner, that
    1.46 @@ -160,7 +163,7 @@
    1.47     int32           thisCoresIdx;
    1.48    
    1.49     //======================== Initializations ========================
    1.50 -   masterEnv        = (MasterEnv*)_VMSMasterEnv;
    1.51 +   masterEnv        = (MasterEnv*)_PRTopEnv;
    1.52     
    1.53     thisCoresIdx     = masterVP->coreAnimatedBy;
    1.54     animSlots       = masterEnv->allAnimSlots[thisCoresIdx];
    1.55 @@ -196,12 +199,12 @@
    1.56              SlaveVP *currSlave = currSlot->slaveAssignedToSlot;
    1.57              
    1.58  	justAddedReqHdlrChg();
    1.59 -			//handle the request, either by VMS or by the language
    1.60 +			//handle the request, either by PR or by the language
    1.61              if( currSlave->requests->reqType != LangReq )
    1.62 -             {    //The request is a standard VMS one, not one defined by the
    1.63 -                  // language, so VMS handles it, then queues slave to be assigned
    1.64 -               handleReqInVMS( currSlave );
    1.65 -               writePrivQ( currSlave, VMSReadyQ ); //Q slave to be assigned below
    1.66 +             {    //The request is a standard PR one, not one defined by the
    1.67 +                  // language, so PR handles it, then queues slave to be assigned
    1.68 +               handleReqInPR( currSlave );
    1.69 +               writePrivQ( currSlave, PRReadyQ ); //Q slave to be assigned below
    1.70               }
    1.71              else
    1.72               {       MEAS__startReqHdlr;
    1.73 @@ -272,7 +275,7 @@
    1.74     //#endif
    1.75     
    1.76     //======================== Initializations ========================
    1.77 -   masterEnv        = (MasterEnv*)_PRMasterEnv;
    1.78 +   masterEnv        = (MasterEnv*)_PRTopEnv;
    1.79     
    1.80     thisCoresIdx     = masterVP->coreAnimatedBy;
    1.81     animSlots        = masterEnv->allAnimSlots[thisCoresIdx];
    1.82 @@ -498,7 +501,7 @@
    1.83     //#endif
    1.84     
    1.85     //======================== Initializations ========================
    1.86 -   masterEnv        = (MasterEnv*)_PRMasterEnv;
    1.87 +   masterEnv        = (MasterEnv*)_PRTopEnv;
    1.88     
    1.89     thisCoresIdx     = masterVP->coreAnimatedBy;
    1.90     animSlots        = masterEnv->allAnimSlots[thisCoresIdx];
    1.91 @@ -614,37 +617,22 @@
    1.92  //#ifdef MODE__MULTI_PROCESS
    1.93  void animationMaster( void *initData, SlaveVP *masterVP )
    1.94   { 
    1.95 +   int32           slotIdx;
    1.96 +//   int32           numSlotsFilled;
    1.97 +   AnimSlot       *currSlot;
    1.98        //Used while scanning and filling animation slots
    1.99 -   int32           slotIdx, numSlotsFilled;
   1.100 -   AnimSlot       *currSlot, **animSlots;
   1.101 -   SlaveVP        *assignedSlaveVP;  //the slave chosen by the assigner
   1.102 +   AnimSlot      **animSlots;
   1.103     
   1.104        //Local copies, for performance
   1.105     MasterEnv      *masterEnv;
   1.106 -   SlaveAssigner   slaveAssigner;
   1.107 -   RequestHandler  requestHandler;
   1.108 -   PRSemEnv       *semanticEnv;
   1.109     int32           thisCoresIdx;
   1.110 -
   1.111 -   SlaveVP        *slave;
   1.112 -   PRProcess      *process;
   1.113 -   PRConstrEnvHolder *constrEnvHolder;
   1.114 -   int32           langMagicNumber;
   1.115     
   1.116     //======================== Initializations ========================
   1.117 -   masterEnv        = (MasterEnv*)_PRMasterEnv;
   1.118 +   masterEnv        = (MasterEnv*)_PRTopEnv;
   1.119     
   1.120     thisCoresIdx     = masterVP->coreAnimatedBy;
   1.121     animSlots        = masterEnv->allAnimSlots[thisCoresIdx];
   1.122 -
   1.123 -   requestHandler   = masterEnv->requestHandler;
   1.124 -   slaveAssigner    = masterEnv->slaveAssigner;
   1.125 -   semanticEnv      = masterEnv->semanticEnv;
   1.126 -   
   1.127 -      //initialize, for non-multi-lang, non multi-proc case
   1.128 -      // default handler gets put into master env by a registration call by lang
   1.129 -   endTaskHandler   = masterEnv->defaultTaskHandler;
   1.130 -   
   1.131 +      
   1.132        HOLISTIC__Insert_Master_Global_Vars;
   1.133     
   1.134     //======================== animationMaster ========================
   1.135 @@ -653,15 +641,36 @@
   1.136     //Having two cases makes this logic complex.. can be finishing either, and 
   1.137     // then the next available work may be either.. so really have two distinct
   1.138     // loops that are inter-twined.. 
   1.139 -   while(1){
   1.140 -       
   1.141 -      MEAS__Capture_Pre_Master_Point
   1.142 +   while(1)
   1.143 +    {  
   1.144 +            MEAS__Capture_Pre_Master_Point
   1.145 +      
   1.146 +      for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
   1.147 +       {
   1.148 +         currSlot = animSlots[ slotIdx ];
   1.149  
   1.150 -      //Scan the animation slots
   1.151 -   numSlotsFilled = 0;
   1.152 -   for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
   1.153 -    {
   1.154 -      currSlot = animSlots[ slotIdx ];
   1.155 +         masterFunction_multiLang( currSlot );
   1.156 +       }
   1.157 +            
   1.158 +            MEAS__Capture_Post_Master_Point;
   1.159 +    
   1.160 +      masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
   1.161 +      flushRegisters();
   1.162 +    } 
   1.163 + }
   1.164 +#endif  //MODE__MULTI_LANG
   1.165 +#endif  //MODE__MULTI_PROCESS
   1.166 +
   1.167 +inline
   1.168 +void
   1.169 +masterFunction_multiLang( AnimSlot  *currSlot )
   1.170 + {    //Scan the animation slots
   1.171 +   int32           magicNumber;
   1.172 +   SlaveVP        *slave;
   1.173 +   SlaveVP        *assignedSlaveVP;
   1.174 +   PRSemEnv       *semanticEnv;
   1.175 +   PRReqst        *req;
   1.176 +   RequestHandler  requestHandler;
   1.177  
   1.178           //Check if newly-done slave in slot, which will need request handled
   1.179        if( currSlot->workIsDone )
   1.180 @@ -674,34 +683,71 @@
   1.181              //process the request made by the slave (held inside slave struc)
   1.182           slave = currSlot->slaveAssignedToSlot;
   1.183           
   1.184 -            //check if the completed work was a task..
   1.185 -         if( slave->taskMetaInfo->isATask )
   1.186 -          {
   1.187 -             if( slave->reqst->type == TaskEnd ) 
   1.188 -              {    //do task end handler, which is registered separately
   1.189 -                   //note, end hdlr may use semantic data from reqst..
   1.190 -                   //get end-task handler
   1.191 -                //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
   1.192 -                taskEndHandler = slave->taskMetaInfo->endTaskHandler;
   1.193 -                
   1.194 -                (*taskEndHandler)( slave, semanticEnv );
   1.195 -                
   1.196 -                goto AssignWork;
   1.197 -              }
   1.198 -             else  //is a task, and just suspended
   1.199 -              {    //turn slot slave into free task slave & make replacement
   1.200 -                if( slave->typeOfVP == TaskSlotSlv ) changeSlvType();
   1.201 -                
   1.202 -                //goto normal slave request handling
   1.203 -                goto SlaveReqHandling; 
   1.204 -              }
   1.205 +            //check if the slave was doing a task..
   1.206 +         //Action depends on both on the request type, and whether it's on
   1.207 +         // a generic slave vs a suspended task
   1.208 +         if( slave->metaTask->taskType == AtomicTask ||
   1.209 +             slave->metaTask->taskType == SuspendedTask )
   1.210 +          { 
   1.211 +            switch( slave->request->reqType )
   1.212 +             { case TaskEnd: 
   1.213 +                { PRHandle_EndTask( slave ); //if free task slave, update count, put into recycle Q -- do handler before lang's handler
   1.214 +
   1.215 +                     //do task end handler, which is registered separately
   1.216 +                     //note, end hdlr may use semantic data from reqst..
   1.217 +                     //get end-task handler
   1.218 +
   1.219 +                  RequestHandler
   1.220 +                  taskEndHandler = slave->metaTask->reqHandler;
   1.221 +                  semanticEnv = PR_int__give_sem_env_for_slave( slave, 
   1.222 +                                              slave->request->langMagicNumber );
   1.223 +                  (*taskEndHandler)( slave, semanticEnv );
   1.224 +
   1.225 +                  goto AssignWork;
   1.226 +                }
   1.227 +               case TaskCreate:
   1.228 +                { PRHandle_CreateTask( slave );
   1.229 +                  justCopied_check;
   1.230 +                  RequestHandler
   1.231 +                  taskCreateHandler = slave->metaTask->reqHandler;
   1.232 +                  semanticEnv = PR_int__give_sem_env_for_slave( slave, 
   1.233 +                                              slave->request->langMagicNumber );
   1.234 +                  (*taskCreateHandler)( slave, semanticEnv );
   1.235 +
   1.236 +                  want_to_resume_creating_slave;
   1.237 +                  goto AssignWork;
   1.238 +                }
   1.239 +               default:  
   1.240 +                {    //is a task, and just suspended, so tied to a free task slave
   1.241 +                     //First turn slot slave into free task slave & make replacement
   1.242 +                  if( slave->typeOfVP == TaskSlotSlv )
   1.243 +                     replaceWithNewSlotSlv( slave, slave->processSlaveIsIn->processEnv );
   1.244 +
   1.245 +                  //goto normal slave request handling
   1.246 +                  goto SlaveReqHandling; 
   1.247 +                }
   1.248 +             }
   1.249            }
   1.250           else //is a slave that suspended
   1.251            {
   1.252               
   1.253            SlaveReqHandling:
   1.254 -            (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
   1.255 -         
   1.256 +               //Q: put the switch in inline call, to clean up code?
   1.257 +            req = slave->request;
   1.258 +            switch( req->reqType )
   1.259 +             { case SlvCreate:    PRHandle_CreateSlave( slave );    break;
   1.260 +               case SlvDissipate: PRHandle_Dissipate( slave ); break;
   1.261 +               case Service:      PR_int__handle_PRServiceReq( slave );  break; //resume into PR's own semantic env
   1.262 +               case Hardware: //for future expansion
   1.263 +               case IO:       //for future expansion
   1.264 +               case OSCall:   //for future expansion
   1.265 +               case Language: //normal sem request
   1.266 +                  magicNumber = slave->request->langMagicNumber;
   1.267 +                  semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber );
   1.268 +                  requestHandler = semanticEnv->requestHdlr;
   1.269 +                  (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
   1.270 +             }
   1.271 +            
   1.272                 HOLISTIC__Record_AppResponder_end;
   1.273                 MEAS__endReqHdlr;
   1.274                 
   1.275 @@ -709,14 +755,14 @@
   1.276            }
   1.277         } //if has suspended slave that needs handling
   1.278        
   1.279 -         //if slot empty, hand to Assigner to fill with a slave
   1.280 +         //End up here when the slot did not have ended work in it (no req)
   1.281 +         //So, here, if slot empty, look for work to fill the slot
   1.282        if( currSlot->needsSlaveAssigned )
   1.283 -       {    //Scan sem environs, looking for one with ready work.
   1.284 -            // call the Assigner for that sem Env, to give slot a new slave
   1.285 -               HOLISTIC__Record_Assigner_start;
   1.286 +       {       HOLISTIC__Record_Assigner_start;
   1.287                 
   1.288         AssignWork:
   1.289 -     
   1.290 +            //Scan sem environs, looking for semEnv with ready work.
   1.291 +            // call the Assigner for that sem Env, to get a slave for the slot
   1.292           assignedSlaveVP = assignWork( semanticEnv, currSlot );
   1.293         
   1.294              //put the chosen slave into slot, and adjust flags and state
   1.295 @@ -724,185 +770,245 @@
   1.296            { currSlot->slaveAssignedToSlot = assignedSlaveVP;
   1.297              assignedSlaveVP->animSlotAssignedTo = currSlot;
   1.298              currSlot->needsSlaveAssigned  = FALSE;
   1.299 -            numSlotsFilled               += 1;
   1.300            }
   1.301           else
   1.302 -          {
   1.303 -            currSlot->needsSlaveAssigned  = TRUE; //local write
   1.304 +          { currSlot->needsSlaveAssigned  = TRUE; //local write
   1.305            }
   1.306                 HOLISTIC__Record_Assigner_end;
   1.307         }//if slot needs slave assigned
   1.308 -    }//for( slotIdx..
   1.309 + }
   1.310  
   1.311 -         MEAS__Capture_Post_Master_Point;
   1.312 +//==========================================================================
   1.313 +/*When a task in a slot slave suspends, the slot slave has to be changed to
   1.314 + * a free task slave, then the slot slave replaced.  The replacement can be
   1.315 + * either a recycled free task slave that finished it's task and has been
   1.316 + * idle in the recycle queue, or else create a new slave to be the slot slave.
   1.317 + *The master only calls this with a slot slave that needs to be replaced.
   1.318 + */
   1.319 +inline void
   1.320 +replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv )
   1.321 + { SlaveVP *newSlotSlv;
   1.322 +   VSsSemData *semData;
   1.323 +
   1.324 +   fixMe__still_VSs_stuff_in_here;
   1.325 +      //get a new slave to be the slot slave
   1.326 +   newSlotSlv     = readPrivQ( processEnv->freeTaskSlvRecycleQ );
   1.327 +   if( newSlotSlv == NULL )
   1.328 +    { newSlotSlv  = PR_int__create_slaveVP( &idle_fn, NULL, processEnv, 0);
   1.329 +         //just made a new free task slave, so count it
   1.330 +      processEnv->numLiveFreeTaskSlvs += 1;
   1.331 +    }
   1.332     
   1.333 -   masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
   1.334 -   flushRegisters();
   1.335 -   }//while(1) 
   1.336 +      //set slave values to make it the slot slave
   1.337 +   newSlotSlv->metaTask              = NULL;
   1.338 +   newSlotSlv->typeOfVP              = TaskSlotSlv;
   1.339 +   newSlotSlv->needsTaskAssigned     = TRUE;
   1.340 +   
   1.341 +      //a slot slave is pinned to a particular slot on a particular core
   1.342 +      //Note, this happens before the request is seen by handler, so nothing
   1.343 +      // has had a chance to change the coreAnimatedBy or anything else..
   1.344 +   newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo;
   1.345 +   newSlotSlv->coreAnimatedBy     = requestingSlv->coreAnimatedBy;
   1.346 +    
   1.347 +      //put it into the slot slave matrix
   1.348 +   int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx;
   1.349 +   int32 coreNum = requestingSlv->coreAnimatedBy;
   1.350 +   processEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv;
   1.351 +
   1.352 +      //Fix up requester, to be an extra slave now (but not an ended one)
   1.353 +      // because it's active, doesn't go into freeTaskSlvRecycleQ
   1.354 +   requestingSlv->typeOfVP = FreeTaskSlv;
   1.355   }
   1.356 -#endif  //MODE__MULTI_LANG
   1.357 -#endif  //MODE__MULTI_PROCESS
   1.358  
   1.359  
   1.360 -/*This does three things:
   1.361 - * 1) ask for a slave ready to resume
   1.362 - * 2) if none, then ask for a task, and assign to the slot slave
   1.363 - * 3) if none, then prune former task slaves waiting to be recycled.
   1.364 - *
   1.365 -   //Have two separate assigners in each semantic env,
   1.366 -   // which keeps its own work in its own structures.. the master, here, 
   1.367 -   // searches through the semantic environs, takes the first that has work
   1.368 -   // available, and whatever it returns is assigned to the slot..
   1.369 -   //However, also have an override assigner.. because static analysis tools know
   1.370 -   // which languages are grouped together.. and the override enables them to
   1.371 -   // generate a custom assigner that uses info from all the languages in a 
   1.372 -   // unified way..  Don't really expect this to happen, but making it possible.
   1.373 +
   1.374 +/*This does:
   1.375 + * 1) searches the semantic environments for one with work ready
   1.376 + *    if finds one, asks its assigner to return work
   1.377 + * 2) checks what kind of work: new task, resuming task, resuming slave
   1.378 + *    if new task, gets the slot slave and assigns task to it and returns slave
   1.379 + *    else, gets the slave attached to the metaTask and returns that.
   1.380 + * 3) if no work found, then prune former task slaves waiting to be recycled.
   1.381 + *    If no work and no slaves to prune, check for shutdown conditions.
   1.382 + * 
   1.383 + * Semantic env keeps its own work in its own structures, and has its own
   1.384 + *  assigner.  It chooses 
   1.385 + * However, include a switch that switches-in an override assigner, which
   1.386 + *  sees all the work in all the semantic env's.  This is most likely  
   1.387 + *  generated by static tools and included in the executable.  That means it
   1.388 + *  has to be called via a registered pointer from here.  The idea is that
   1.389 + *  the static tools know which languages are grouped together.. and the
   1.390 + *  override enables them to generate a custom assigner that uses info from
   1.391 + *  all the languages in a unified way..  Don't really expect this to happen,
   1.392 + *  but am making it possible.
   1.393   */
   1.394  inline SlaveVP *
   1.395 -assignWork( PRProcessEnv *processEnv, AnimSlot *slot )
   1.396 - { SlaveVP     *returnSlv;
   1.397 -   //VSsSemEnv   *semEnv;
   1.398 -   //VSsSemData  *semData;
   1.399 -   int32        coreNum, slotNum;
   1.400 -   PRTaskMetaInfo *newTaskStub;
   1.401 -   SlaveVP     *freeTaskSlv;
   1.402 +assignWork( PRProcess *process, AnimSlot *slot )
   1.403 + { SlaveVP        *returnSlv;
   1.404 +   //VSsSemEnv      *semEnv;
   1.405 +   //VSsSemData     *semData;
   1.406 +   int32           coreNum, slotNum;
   1.407 +   PRMetaTask     *newMetaTask, *assignedMetaTask;
   1.408 +   SlaveVP        *freeTaskSlv;
   1.409  
   1.410 +   coreNum = slot->coreSlotIsOn;
   1.411     
   1.412 -      //master has to handle slot slaves.. so either assigner returns
   1.413 -      // taskMetaInfo or else two assigners, one for slaves, other for tasks..     
   1.414 -   semEnvs = processEnv->semEnvs;
   1.415 -   numEnvs = processEnv->numSemEnvs;
   1.416 -   for( envIdx = 0; envIdx < numEnvs; envIdx++ )
   1.417 +   if( _PRTopEnv->overrideAssigner != NULL )
   1.418 +    { assignedMetaTask = (*_PRTopEnv->overrideAssigner)( process, slot );
   1.419 +      if( assignedMetaTask != NULL )
   1.420 +       {
   1.421 +            //have work, so reset Done flag (caused by work generated on other core)
   1.422 +         if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
   1.423 +            process->coreIsDone[coreNum] = FALSE;   //don't just write always
   1.424 +         
   1.425 +         switch( assignedMetaTask->taskType )
   1.426 +          { case GenericSlave: goto AssignSlave;
   1.427 +            case ResumedTask:  goto AssignSlave;
   1.428 +            case NewTask:      goto AssignNewTask;
   1.429 +            case default:      PR_int__throw_exception( "unknown task type ret by assigner" );
   1.430 +          }
   1.431 +       }
   1.432 +      else
   1.433 +         goto NoWork;
   1.434 +    }
   1.435 +   
   1.436 +      //If here, then no override assigner, so search semantic envs for work
   1.437 +   int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner;
   1.438 +   semEnvs = process->semEnvs;
   1.439 +   numEnvs = process->numSemEnvs;
   1.440 +   for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash AND array
   1.441      { semEnv = semEnvs[envIdx];
   1.442        if( semEnv->hasWork )
   1.443         { assigner = semEnv->assigner; 
   1.444 -         retTaskMetaInfo = (*assigner)( semEnv, slot );
   1.445 +         assignedMetaTask = (*assigner)( semEnv, slot );
   1.446           
   1.447 -         return retTaskMetaInfo; //quit, have work
   1.448 +            //have work, so reset Done flag (caused by work generated on other core)
   1.449 +         if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
   1.450 +            process->coreIsDone[coreNum] = FALSE;   //don't just write always
   1.451 +         
   1.452 +         switch( assignedMetaTask->taskType )
   1.453 +          { case GenericSlave: goto AssignSlave;
   1.454 +            case ResumedTask:  goto AssignSlave;
   1.455 +            case NewTask:      goto AssignNewTask;
   1.456 +            case default:      PR_int__throw_exception( "unknown task type ret by assigner" );
   1.457 +          }
   1.458         }
   1.459      }
   1.460     
   1.461 -   coreNum = slot->coreSlotIsOn;
   1.462 -   slotNum = slot->slotIdx;
   1.463 - 
   1.464 -      //first try to get a ready slave
   1.465 -   returnSlv = getReadySlave();
   1.466 + NoWork:
   1.467 +      //No work, if reach here..
   1.468 +      //no task, so prune the recycle pool of free task slaves
   1.469 +   freeTaskSlv = readPrivQ( process->freeTaskSlvRecycleQ );
   1.470 +   if( freeTaskSlv != NULL )
   1.471 +    {    //delete, so that bound the num extras, and deliver shutdown cond
   1.472 +      deleteExtraneousFreeTaskSlv( freeTaskSlv, process );
   1.473 +         //then return NULL
   1.474 +      returnSlv = NULL;
   1.475 +         
   1.476 +      goto ReturnTheSlv;
   1.477 +    }
   1.478 +   else
   1.479 +    { //candidate for shutdown.. all extras dissipated, and no tasks
   1.480 +      // and no ready to resume slaves, so no way to generate
   1.481 +      // more work (on this core -- other core might have work still)
   1.482 +      if( process->numLiveFreeTaskSlvs == 0 && 
   1.483 +          process->numLiveGenericSlvs == 0 )
   1.484 +       { //This core sees no way to generate more tasks, so say it
   1.485 +         if( process->coreIsDone[coreNum] == FALSE )
   1.486 +          { process->numCoresDone += 1;
   1.487 +            process->coreIsDone[coreNum] = TRUE;
   1.488 +            #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
   1.489 +            process->shutdownInitiated = TRUE;
   1.490 +            
   1.491 +            #else
   1.492 +            if( process->numCoresDone == NUM_CORES )
   1.493 +             { //means no cores have work, and none can generate more
   1.494 +               process->shutdownInitiated = TRUE;
   1.495 +             }
   1.496 +            #endif
   1.497 +          }
   1.498 +       }
   1.499 +         //check if shutdown has been initiated by this or other core
   1.500 +      if( process->shutdownInitiated )
   1.501 +       { returnSlv = PR_SS__create_shutdown_slave();
   1.502 +       }
   1.503 +      else
   1.504 +         returnSlv = NULL;
   1.505  
   1.506 -   if( returnSlv != NULL )
   1.507 -    { returnSlv->coreAnimatedBy   = coreNum;
   1.508 -    
   1.509 -         //have work, so reset Done flag (when work generated on other core)
   1.510 -      if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf
   1.511 -         processEnv->coreIsDone[coreNum] = FALSE;   //don't just write always
   1.512 +      goto ReturnTheSlv;
   1.513 +    } //if( freeTaskSlv != NULL )
   1.514 +
   1.515 +
   1.516 + AssignSlave:
   1.517 +    {    //get slave pointed to by meta task.
   1.518 +      returnSlv = assignedMetaTask->slaveAssignedTo;
   1.519 +
   1.520 +      returnSlv->coreAnimatedBy   = coreNum;
   1.521      
   1.522        goto ReturnTheSlv;
   1.523      }
   1.524 -   
   1.525 -      //were no slaves, so try to get a ready task.. 
   1.526 -   newTaskStub = getTaskStub();
   1.527 -   
   1.528 -   if( newTaskStub != NULL )
   1.529 + 
   1.530 + AssignNewTask:
   1.531      { 
   1.532           //get the slot slave to assign the task to..
   1.533 -      returnSlv = processEnv->slotTaskSlvs[coreNum][slotNum];
   1.534 +      coreNum = slot->coreSlotIsOn;
   1.535 +      slotNum = slot->slotIdx;
   1.536 +      returnSlv = process->slotTaskSlvs[coreNum][slotNum];
   1.537  
   1.538           //point slave to task's function, and mark slave as having task
   1.539        PR_int__reset_slaveVP_to_TopLvlFn( returnSlv, 
   1.540 -                          newTaskStub->taskType->fn, newTaskStub->args );
   1.541 -      returnSlv->taskStub          = newTaskStub;
   1.542 -      newTaskStub->slaveAssignedTo = returnSlv;
   1.543 +                       assignedMetaTask->topLevelFn, assignedMetaTask->initData );
   1.544 +      returnSlv->metaTask          = assignedMetaTask;
   1.545 +      assignedMetaTask->slaveAssignedTo = returnSlv;
   1.546        returnSlv->needsTaskAssigned = FALSE;  //slot slave is a "Task" slave type
   1.547        
   1.548           //have work, so reset Done flag, if was set
   1.549 -      if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf
   1.550 -         processEnv->coreIsDone[coreNum] = FALSE;   //don't just write always
   1.551 +      if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
   1.552 +         process->coreIsDone[coreNum] = FALSE;   //don't just write always
   1.553        
   1.554        goto ReturnTheSlv;
   1.555      }
   1.556 -   else
   1.557 -    {    //no task, so prune the recycle pool of free task slaves
   1.558 -      freeTaskSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ );
   1.559 -      if( freeTaskSlv != NULL )
   1.560 -       {    //delete to bound the num extras, and deliver shutdown cond
   1.561 -         handleDissipate( freeTaskSlv, processEnv );
   1.562 -            //then return NULL
   1.563 -         returnSlv = NULL;
   1.564 -         
   1.565 -         goto ReturnTheSlv;
   1.566 -       }
   1.567 -      else
   1.568 -       { //candidate for shutdown.. if all extras dissipated, and no tasks
   1.569 -         // and no ready to resume slaves, then no way to generate
   1.570 -         // more tasks (on this core -- other core might have task still)
   1.571 -         if( processEnv->numLiveExtraTaskSlvs == 0 && 
   1.572 -             processEnv->numLiveThreadSlvs == 0 )
   1.573 -          { //This core sees no way to generate more tasks, so say it
   1.574 -            if( processEnv->coreIsDone[coreNum] == FALSE )
   1.575 -             { processEnv->numCoresDone += 1;
   1.576 -               processEnv->coreIsDone[coreNum] = TRUE;
   1.577 -               #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
   1.578 -               processEnv->shutdownInitiated = TRUE;
   1.579 -               
   1.580 -               #else
   1.581 -               if( processEnv->numCoresDone == NUM_CORES )
   1.582 -                { //means no cores have work, and none can generate more
   1.583 -                  processEnv->shutdownInitiated = TRUE;
   1.584 -                }
   1.585 -               #endif
   1.586 -             }
   1.587 -          }
   1.588 -            //check if shutdown has been initiated by this or other core
   1.589 -         if(processEnv->shutdownInitiated) 
   1.590 -          { returnSlv = PR_SS__create_shutdown_slave();
   1.591 -          }
   1.592 -         else
   1.593 -            returnSlv = NULL;
   1.594 -
   1.595 -         goto ReturnTheSlv; //don't need, but completes pattern
   1.596 -       } //if( freeTaskSlv != NULL )
   1.597 -    } //if( newTaskStub == NULL )
   1.598 -   //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL
   1.599   
   1.600  
   1.601   ReturnTheSlv:  //All paths goto here.. to provide single point for holistic..
   1.602  
   1.603     #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   1.604     if( returnSlv == NULL )
   1.605 -    { returnSlv = processEnv->idleSlv[coreNum][slotNum]; 
   1.606 +    { returnSlv = process->idleSlv[coreNum][slotNum]; 
   1.607      
   1.608           //things that would normally happen in resume(), but idle VPs
   1.609           // never go there
   1.610 -      returnSlv->assignCount++; //gives each idle unit a unique ID
   1.611 +      returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
   1.612        Unit newU;
   1.613        newU.vp = returnSlv->slaveID;
   1.614 -      newU.task = returnSlv->assignCount;
   1.615 -      addToListOfArrays(Unit,newU,processEnv->unitList);
   1.616 +      newU.task = returnSlv->numTimesAssignedToASlot;
   1.617 +      addToListOfArrays(Unit,newU,process->unitList);
   1.618  
   1.619 -      if (returnSlv->assignCount > 1) //make a dependency from prev idle unit
   1.620 +      if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
   1.621         { Dependency newD;             // to this one
   1.622           newD.from_vp = returnSlv->slaveID;
   1.623 -         newD.from_task = returnSlv->assignCount - 1;
   1.624 +         newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
   1.625           newD.to_vp = returnSlv->slaveID;
   1.626 -         newD.to_task = returnSlv->assignCount;
   1.627 -         addToListOfArrays(Dependency, newD ,processEnv->ctlDependenciesList);  
   1.628 +         newD.to_task = returnSlv->numTimesAssignedToASlot;
   1.629 +         addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);  
   1.630         }
   1.631      }
   1.632     else //have a slave will be assigned to the slot
   1.633      { //assignSlv->numTimesAssigned++;
   1.634           //get previous occupant of the slot
   1.635        Unit prev_in_slot = 
   1.636 -         processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
   1.637 +         process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
   1.638        if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency
   1.639         { Dependency newD;      // is a hardware dependency
   1.640           newD.from_vp = prev_in_slot.vp;
   1.641           newD.from_task = prev_in_slot.task;
   1.642           newD.to_vp = returnSlv->slaveID;
   1.643 -         newD.to_task = returnSlv->assignCount;
   1.644 -         addToListOfArrays(Dependency,newD,processEnv->hwArcs);   
   1.645 +         newD.to_task = returnSlv->numTimesAssignedToASlot;
   1.646 +         addToListOfArrays(Dependency,newD,process->hwArcs);   
   1.647         }
   1.648        prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous
   1.649 -      prev_in_slot.task = returnSlv->assignCount;
   1.650 -      processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
   1.651 +      prev_in_slot.task = returnSlv->numTimesAssignedToASlot;
   1.652 +      process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
   1.653           prev_in_slot;        
   1.654      }
   1.655     #endif
   1.656 @@ -910,92 +1016,150 @@
   1.657     return( returnSlv );
   1.658   }
   1.659  
   1.660 -      
   1.661 -//=================================================================
   1.662 -         //#else  //is MODE__MULTI_LANG
   1.663 -            //For multi-lang mode, first, get the constraint-env holder out of
   1.664 -            // the process, which is in the slave.
   1.665 -            //Second, get the magic number out of the request, use it to look up
   1.666 -            // the constraint Env within the constraint-env holder.
   1.667 -            //Then get the request handler out of the constr env
   1.668 -         constrEnvHolder = slave->process->constrEnvHolder;
   1.669 -         reqst = slave->request;
   1.670 -         langMagicNumber = reqst->langMagicNumber;
   1.671 -         semanticEnv = lookup( langMagicNumber, constrEnvHolder ); //a macro
   1.672 -         if( slave->reqst->type == taskEnd ) //end-task is special
   1.673 -          {    //need to know what lang's task ended
   1.674 -            taskEndHandler = semanticEnv->taskEndHandler;
   1.675 -            (*taskEndHandler)( slave, reqst, semanticEnv ); //can put semantic data into task end reqst, for continuation, etc
   1.676 -               //this is a slot slave, get a new task for it
   1.677 -            if( !existsOverrideAssigner )//if exists, is set above, before loop
   1.678 -             {    //search for task assigner that has work
   1.679 -               for( a = 0; a < num_assigners; a++ )
   1.680 -                { if( taskAssigners[a]->hasWork )
   1.681 -                   { newTaskAssigner = taskAssigners[a];
   1.682 -                     (*newTaskAssigner)( slave, semanticEnv );
   1.683 -                     goto GotTask;
   1.684 -                   }
   1.685 -                }
   1.686 -               goto NoTasks;
   1.687 -             }
   1.688 -            
   1.689 -           GotTask:
   1.690 -            continue; //have work, so do next iter of loop, don't call slave assigner
   1.691 -          }
   1.692 -         if( slave->typeOfVP == taskSlotSlv ) changeSlvType();//is suspended task
   1.693 -            //now do normal suspended slave request handler
   1.694 -         requestHandler = semanticEnv->requestHandler;
   1.695 -         //#endif
   1.696  
   1.697 -         
   1.698 -       }
   1.699 -         //If make it here, then was no task for this slot
   1.700 -         //slot empty, hand to Assigner to fill with a slave
   1.701 -      if( currSlot->needsSlaveAssigned )
   1.702 -       {    //Call plugin's Assigner to give slot a new slave
   1.703 -               HOLISTIC__Record_Assigner_start;
   1.704 -               
   1.705 -         //#ifdef  MODE__MULTI_LANG
   1.706 -        NoTasks:
   1.707 -            //First, choose an Assigner..
   1.708 -            //There are several Assigners, one for each langlet.. they all
   1.709 -            // indicate whether they have work available.. just pick the first
   1.710 -            // one that has work..  Or, if there's a Unified Assigner, call
   1.711 -            // that one..  So, go down array, checking..
   1.712 -         if( !existsOverrideAssigner ) 
   1.713 -          { for( a = 0; a < num_assigners; a++ )
   1.714 -             { if( assigners[a]->hasWork )
   1.715 -                { slaveAssigner = assigners[a];
   1.716 -                  goto GotAssigner;
   1.717 -                }
   1.718 -             }
   1.719 -            //no work, so just continue to next iter of scan loop
   1.720 -            continue;
   1.721 -          }
   1.722 -         //when exists override, the assigner is set, once, above, so do nothing
   1.723 -        GotAssigner:
   1.724 -         //#endif
   1.725 -        
   1.726 -         assignedSlaveVP =
   1.727 -          (*slaveAssigner)( semanticEnv, currSlot );
   1.728 -         
   1.729 -            //put the chosen slave into slot, and adjust flags and state
   1.730 -         if( assignedSlaveVP != NULL )
   1.731 -          { currSlot->slaveAssignedToSlot = assignedSlaveVP;
   1.732 -            assignedSlaveVP->animSlotAssignedTo = currSlot;
   1.733 -            currSlot->needsSlaveAssigned  = FALSE;
   1.734 -            numSlotsFilled               += 1;
   1.735 -            
   1.736 -            HOLISTIC__Record_Assigner_end;
   1.737 -          }
   1.738 -       }//if slot needs slave assigned
   1.739 -    }//for( slotIdx..
   1.740 -
   1.741 -         MEAS__Capture_Post_Master_Point;
   1.742 +/*In creator, only PR related things happen, and things in the langlet whose
   1.743 + * creator construct was used.
   1.744 + *Other langlet still gets a chance to create semData -- but by registering a
   1.745 + * "createSemData" handler in the semEnv.  When a construct  of the langlet
   1.746 + * calls "PR__give_sem_data()", if there is no semData for that langlet,
   1.747 + * the PR will call the creator in the langlet's semEnv, place whatever it
   1.748 + * makes as the semData in that slave for that langlet, and return that semData
   1.749 + *
   1.750 + *So, as far as counting things, a langlet is only allowed to count creation
   1.751 + * of slaves it creates itself..  may have to change this later.. add a way for
   1.752 + * langlet to register a trigger Fn called each time a slave gets created.. 
   1.753 + * need more experience with what langlets will do at create time..  think Cilk
   1.754 + * has interesting create behavior..  not sure how that will differ in light
   1.755 + * of true tasks and langlet approach.  Look at it after all done and start
   1.756 + * modifying the langs to be langlets..
   1.757 + * 
   1.758 + *PR itself needs to create the slave, then update numLiveSlaves in process,
   1.759 + * copy processID from requestor to newly created
   1.760 + */
   1.761 +PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv )
   1.762 + { SlaveVP *newSlv;
   1.763 +   PRMetaTask metaTask;
   1.764 +   PRProcess *process;
   1.765 + 
   1.766 +   process = requestingSlv->processSlaveIsIn;
   1.767 +   newSlv = PR_int__create_slaveVP();
   1.768 +   newSlv->typeOfVP = GenericSlv;
   1.769 +   newSlv->processSlaveIsIn = process;
   1.770 +   process->numLiveGenericSlaves += 1;
   1.771 +   metaTask = PR_int__create_slave_meta_task();
   1.772 +   metaTask->taskID = req->ID;
   1.773 +   metaTask->taskType = GenericSlave;
   1.774     
   1.775 -   masterSwitchToCoreCtlr( masterVP );
   1.776 -   flushRegisters();
   1.777 -         DEBUG__printf(FALSE,"came back after switch to core -- so lock released!");
   1.778 -   }//while(1) 
   1.779 +   (*req->handler)(newSlv);
   1.780   }
   1.781  
   1.782 +/*The dissipate handler has to update the number of slaves of the type, within
   1.783 + * the process, and call the langlet handler linked into the request,
   1.784 + * and after that returns, then call the PR function that frees the slave state
   1.785 + * (or recycles the slave).
   1.786 + * 
   1.787 + *The PR function that frees the slave state has to also free all of the
   1.788 + * semData in the slave..  or else reset all of the semDatas.. by, say, marking
   1.789 + * them, then in PR__give_semData( magicNum ) call the langlet registered
   1.790 + * "resetSemData" Fn.
   1.791 + */
   1.792 +PRHandle_Dissipate( SlaveVP *slave )
   1.793 + { PRProcess *process;
   1.794 +   void      *semEnv;
   1.795 +   
   1.796 +   process = slave->processSlaveIsIn;
   1.797 +   
   1.798 +      //do the language's dissipate handler
   1.799 +   semEnv = PR_int__give_sem_env_for( slave, slave->request->langMagicNumber );
   1.800 +   (*slave->request->handler)( slave, semEnv );
   1.801 +   
   1.802 +   process->numLiveGenericSlaves -= 1;
   1.803 +   PR_int__dissipate_slaveVP_multilang( slave ); //recycles and resets semDatas
   1.804 +   
   1.805 +      //check End Of Process Condition
   1.806 +   if( process->numLiveTasks == 0 &&
   1.807 +       process->numLiveGenericSlaves == 0 )
   1.808 +      signalEndOfProcess;
   1.809 + }
   1.810 +
   1.811 +/*Create task is a special form, that has PR behavior in addition to plugin
   1.812 + * behavior.  Master calls this first, and this in turn calls the plugin's
   1.813 + * create task handler.
   1.814 + */
   1.815 +inline void
   1.816 +PRHandle_CreateTask( TopLevelFn topLevelFn, void *initData, PRReqst *req, 
   1.817 +                                                        SlaveVP *requestingSlv )
   1.818 + { PRMetaTask    *metaTask;
   1.819 +   PRProcess     *process;
   1.820 +   void          *semEnv, _langMetaTask;
   1.821 +   PRLangMetaTask *langMetaTask;
   1.822 +                    
   1.823 +   process = requestingSlv->processSlaveIsIn;
   1.824 +
   1.825 +   metaTask         = PR_int__create_meta_task( req );
   1.826 +   metaTask->taskID = req->ID; //may be NULL
   1.827 +   metaTask->topLevelFn = topLevelFn;
   1.828 +   metaTask->initData   = initData;
   1.829 +           
   1.830 +   process->numLiveTasks += 1;
   1.831 +      
   1.832 +      //plugin tracks tasks ready, and has its own assigner, so task doesn't
   1.833 +      // come back from lang's handler -- it's consumed and stays in semEnv.
   1.834 +      //But handler gives back the language-specific meta-task it creates, and
   1.835 +      // then hook that into the PR meta-task
   1.836 +      //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size
   1.837 +      // of the lang's metaTask, and alloc's that plus the prolog and returns
   1.838 +      // ptr to position just above the prolog)
   1.839 +   semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req
   1.840 +   _langMetaTask = (*requestingSlv->request->handler)(req, semEnv);
   1.841 +   langMetaTask  = (PRLangMetaTask *)_langMetaTask;
   1.842 +   metaTask->langMetaTask      = langMetaTask;
   1.843 +   langMetaTask->protoMetaTask = metaTask;
   1.844 +   
   1.845 +   return;
   1.846 + }
   1.847 +
   1.848 +/*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
   1.849 + * suspended at some point in its code.
   1.850 + *For 1, just decr count of live tasks (and check for end condition) -- the
   1.851 + * master loop will decide what goes into the slot freed up by this task end,
   1.852 + * so, here, don't worry about assigning a new task to the slot slave.
   1.853 + *For 2, the task's slot slave has been converted to a free task slave, which
   1.854 + * now has nothing more to do, so send it to the recycle Q (which includes
   1.855 + * freeing all the semData and meta task structs alloc'd for it).  Then
   1.856 + * decrement the live task count and check end condition.
   1.857 + * 
   1.858 + *PR has to update count of live tasks, and check end of process condition.
   1.859 + * There are constructs that wait for a process to end, so when end detected,
   1.860 + * have to resume what's waiting..
   1.861 + *Thing is, the wait is used in "main", so it's an OS thread.  That means
   1.862 + * PR internals have to do OS thread signaling.  Want to do that in the
   1.863 + * core controller, which has the original stack of an OS thread.
   1.864 + * 
   1.865 + *So here, when detect process end, signal to the core controller, which will
   1.866 + * then do the condition variable notify to the OS thread that's waiting. 
   1.867 + */
   1.868 +inline void
   1.869 +PRHandle_EndTask( SlaveVP *requestingSlv )
   1.870 + { void *semEnv;
   1.871 +   PRReqst *req;  
   1.872 +   PRMetaTask *metaTask;
   1.873 +   PRProcess  *process;
   1.874 + 
   1.875 +   req = requestingSlv->request;
   1.876 +   semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req
   1.877 +   metaTask = req->metaTask;
   1.878 +      //Want to keep PRMetaTask hidden from plugin, so extract semReq..
   1.879 +   (*req->handler)( metaTask, req->semReq, semEnv );
   1.880 +   
   1.881 +   recycleFreeTaskSlave( requestingSlv );
   1.882 +   
   1.883 +   process->numLiveTasks -= 1;
   1.884 +  
   1.885 +      //check End Of Process Condition
   1.886 +   if( process->numLiveTasks == 0 &&
   1.887 +       process->numLiveGenericSlaves == 0 )
   1.888 +      signalEndOfProcessToCoreCtlr;
   1.889 + }
   1.890 +
   1.891 + 
   1.892 \ No newline at end of file