changeset 0:9f2a7bd26dd9 tip

Initial add -- code is straight copy of VSs implementation.. to be modified
author Sean Halle <seanhalle@yahoo.com>
date Mon, 27 Aug 2012 02:14:35 -0700
parents
children
files .hgeol .hgignore DKU.c DKU.h DKU_PluginFns.c DKU_Request_Handlers.c DKU_Request_Handlers.h DKU_singleton_asm.s Measurement/DKU_Counter_Recording.c Measurement/DKU_Counter_Recording.h Measurement/DKU_Measurement.h Measurement/dependency.c Measurement/dependency.h __brch__default
diffstat 14 files changed, 3419 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgeol	Mon Aug 27 02:14:35 2012 -0700
     1.3 @@ -0,0 +1,12 @@
     1.4 +
     1.5 +[patterns]
     1.6 +**.py = native
     1.7 +**.txt = native
     1.8 +**.c = native
     1.9 +**.h = native
    1.10 +**.cpp = native
    1.11 +**.java = native
    1.12 +**.sh = native
    1.13 +**.pl = native
    1.14 +**.jpg = bin
    1.15 +**.gif = bin
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/.hgignore	Mon Aug 27 02:14:35 2012 -0700
     2.3 @@ -0,0 +1,3 @@
     2.4 +syntax: glob
     2.5 +
     2.6 +*.o
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/DKU.c	Mon Aug 27 02:14:35 2012 -0700
     3.3 @@ -0,0 +1,853 @@
     3.4 +/*
     3.5 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
     3.6 + *
     3.7 + * Licensed under BSD
     3.8 + */
     3.9 +
    3.10 +#include <stdio.h>
    3.11 +#include <stdlib.h>
    3.12 +#include <malloc.h>
    3.13 +
    3.14 +#include "Queue_impl/PrivateQueue.h"
    3.15 +#include "Hash_impl/PrivateHash.h"
    3.16 +
    3.17 +#include "VSs.h"
    3.18 +#include "Measurement/VSs_Counter_Recording.h"
    3.19 +
    3.20 +//==========================================================================
    3.21 +
    3.22 +void
    3.23 +VSs__init();
    3.24 +
    3.25 +void
    3.26 +VSs__init_Helper();
    3.27 +//==========================================================================
    3.28 +
    3.29 +
    3.30 +
    3.31 +//===========================================================================
    3.32 +
    3.33 +
    3.34 +/*These are the library functions *called in the application*
    3.35 + * 
    3.36 + *There's a pattern for the outside sequential code to interact with the
    3.37 + * VMS_HW code.
    3.38 + *The VMS_HW system is inside a boundary..  every VSs system is in its
    3.39 + * own directory that contains the functions for each of the processor types.
    3.40 + * One of the processor types is the "seed" processor that starts the
    3.41 + * cascade of creating all the processors that do the work.
    3.42 + *So, in the directory is a file called "EntryPoint.c" that contains the
    3.43 + * function, named appropriately to the work performed, that the outside
    3.44 + * sequential code calls.  This function follows a pattern:
    3.45 + *1) it calls VSs__init()
    3.46 + *2) it creates the initial data for the seed processor, which is passed
    3.47 + *    in to the function
    3.48 + *3) it creates the seed VSs processor, with the data to start it with.
    3.49 + *4) it calls startVSsThenWaitUntilWorkDone
    3.50 + *5) it gets the returnValue from the transfer struc and returns that
    3.51 + *    from the function
    3.52 + *
    3.53 + *For now, a new VSs system has to be created via VSs__init every
    3.54 + * time an entry point function is called -- later, might add letting the
    3.55 + * VSs system be created once, and let all the entry points just reuse
    3.56 + * it -- want to be as simple as possible now, and see by using what makes
    3.57 + * sense for later..
    3.58 + */
    3.59 +
    3.60 +
    3.61 +
    3.62 +//===========================================================================
    3.63 +
    3.64 +/*This is the "border crossing" function -- the thing that crosses from the
    3.65 + * outside world, into the VMS_HW world.  It initializes and starts up the
    3.66 + * VMS system, then creates one processor from the specified function and
    3.67 + * puts it into the readyQ.  From that point, that one function is resp.
    3.68 + * for creating all the other processors, that then create others, and so
    3.69 + * forth.
    3.70 + *When all the processors, including the seed, have dissipated, then this
    3.71 + * function returns.  The results will have been written by side-effect via
    3.72 + * pointers read from, or written into initData.
    3.73 + *
    3.74 + *NOTE: no Threads should exist in the outside program that might touch
    3.75 + * any of the data reachable from initData passed in to here
    3.76 + */
    3.77 +void
    3.78 +VSs__create_seed_slave_and_do_work( TopLevelFnPtr fnPtr, void *initData )
    3.79 + { VSsSemEnv   *semEnv;
    3.80 +   SlaveVP     *seedSlv;
    3.81 +   VSsSemData  *semData;
    3.82 +   VSsTaskStub *threadTaskStub, *parentTaskStub;
    3.83 +
    3.84 +   VSs__init();      //normal multi-thd
    3.85 +   
    3.86 +   semEnv = _VMSMasterEnv->semanticEnv;
    3.87 +
    3.88 +      //VSs starts with one processor, which is put into initial environ,
    3.89 +      // and which then calls create() to create more, thereby expanding work
    3.90 +   seedSlv = VSs__create_slave_helper( fnPtr, initData,
    3.91 +                                     semEnv, semEnv->nextCoreToGetNewSlv++ );
    3.92 +   
    3.93 +      //seed slave is a thread slave, so make a thread's task stub for it
    3.94 +      // and then make another to stand for the seed's parent task.  Make
    3.95 +      // the parent be already ended, and have one child (the seed).  This
    3.96 +      // will make the dissipate handler do the right thing when the seed
    3.97 +      // is dissipated.
    3.98 +   threadTaskStub = create_thread_task_stub( initData );
    3.99 +   parentTaskStub = create_thread_task_stub( NULL );
   3.100 +   parentTaskStub->isEnded = TRUE;
   3.101 +   parentTaskStub->numLiveChildThreads = 1; //so dissipate works for seed
   3.102 +   threadTaskStub->parentTaskStub = parentTaskStub;
   3.103 +   
   3.104 +   semData = (VSsSemData *)seedSlv->semanticData;
   3.105 +      //seedVP is a thread, so has a permanent task
   3.106 +   semData->needsTaskAssigned = FALSE;
   3.107 +   semData->taskStub = threadTaskStub;
   3.108 +   semData->slaveType = ThreadSlv;
   3.109 +
   3.110 +   resume_slaveVP( seedSlv, semEnv ); //returns right away, just queues Slv
   3.111 +   
   3.112 +   VMS_SS__start_the_work_then_wait_until_done();      //normal multi-thd
   3.113 +
   3.114 +   VSs__cleanup_after_shutdown();
   3.115 + }
   3.116 +
   3.117 +
   3.118 +int32
   3.119 +VSs__giveMinWorkUnitCycles( float32 percentOverhead )
   3.120 + {
   3.121 +   return MIN_WORK_UNIT_CYCLES;
   3.122 + }
   3.123 +
   3.124 +int32
   3.125 +VSs__giveIdealNumWorkUnits()
   3.126 + {
   3.127 +   return NUM_ANIM_SLOTS * NUM_CORES;
   3.128 + }
   3.129 +
   3.130 +int32
   3.131 +VSs__give_number_of_cores_to_schedule_onto()
   3.132 + {
   3.133 +   return NUM_CORES;
   3.134 + }
   3.135 +
   3.136 +/*For now, use TSC -- later, make these two macros with assembly that first
   3.137 + * saves jump point, and second jumps back several times to get reliable time
   3.138 + */
   3.139 +void
   3.140 +VSs__start_primitive()
   3.141 + { saveLowTimeStampCountInto( ((VSsSemEnv *)(_VMSMasterEnv->semanticEnv))->
   3.142 +                              primitiveStartTime );
   3.143 + }
   3.144 +
   3.145 +/*Just quick and dirty for now -- make reliable later
   3.146 + * will want this to jump back several times -- to be sure cache is warm
   3.147 + * because don't want comm time included in calc-time measurement -- and
   3.148 + * also to throw out any "weird" values due to OS interrupt or TSC rollover
   3.149 + */
   3.150 +int32
   3.151 +VSs__end_primitive_and_give_cycles()
   3.152 + { int32 endTime, startTime;
   3.153 +   //TODO: fix by repeating time-measurement
   3.154 +   saveLowTimeStampCountInto( endTime );
   3.155 +   startTime =((VSsSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime;
   3.156 +   return (endTime - startTime);
   3.157 + }
   3.158 +
   3.159 +//===========================================================================
   3.160 +
   3.161 +/*Initializes all the data-structures for a VSs system -- but doesn't
   3.162 + * start it running yet!
   3.163 + *
   3.164 + *This runs in the main thread -- before VMS starts up
   3.165 + * 
   3.166 + *This sets up the semantic layer over the VMS system
   3.167 + *
   3.168 + *First, calls VMS_Setup, then creates own environment, making it ready
   3.169 + * for creating the seed processor and then starting the work.
   3.170 + */
   3.171 +void
   3.172 +VSs__init()
   3.173 + {
   3.174 +   VMS_SS__init();
   3.175 +      //masterEnv, a global var, now is partially set up by init_VMS
   3.176 +      // after this, have VMS_int__malloc and VMS_int__free available
   3.177 +
   3.178 +   VSs__init_Helper();
   3.179 + }
   3.180 +
   3.181 +
   3.182 +void idle_fn(void* data, SlaveVP *animatingSlv){
   3.183 +    while(1){
   3.184 +        VMS_int__suspend_slaveVP_and_send_req(animatingSlv);
   3.185 +    }
   3.186 +}
   3.187 +
   3.188 +void
   3.189 +VSs__init_Helper()
   3.190 + { VSsSemEnv       *semanticEnv;
   3.191 +   int32            i, coreNum, slotNum;
   3.192 +   VSsSemData      *semData;
   3.193 + 
   3.194 +      //Hook up the semantic layer's plug-ins to the Master virt procr
   3.195 +   _VMSMasterEnv->requestHandler = &VSs__Request_Handler;
   3.196 +   _VMSMasterEnv->slaveAssigner  = &VSs__assign_slaveVP_to_slot;
   3.197 +
   3.198 +      //create the semantic layer's environment (all its data) and add to
   3.199 +      // the master environment
   3.200 +   semanticEnv = VMS_int__malloc( sizeof( VSsSemEnv ) );
   3.201 +   _VMSMasterEnv->semanticEnv = semanticEnv;
   3.202 +   
   3.203 +   #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS
   3.204 +   _VMSMasterEnv->counterHandler = &VSs__counter_handler;
   3.205 +   VSs__init_counter_data_structs();
   3.206 +   #endif
   3.207 +
   3.208 +   semanticEnv->shutdownInitiated = FALSE;
   3.209 +   semanticEnv->coreIsDone = VMS_int__malloc( NUM_CORES * sizeof( bool32 ) );
   3.210 +      //For each animation slot, there is an idle slave, and an initial
   3.211 +      // slave assigned as the current-task-slave.  Create them here.
   3.212 +   SlaveVP *idleSlv, *slotTaskSlv;
   3.213 +   for( coreNum = 0; coreNum < NUM_CORES; coreNum++ )
   3.214 +    { semanticEnv->coreIsDone[coreNum] = FALSE; //use during shutdown
   3.215 +    
   3.216 +      for( slotNum = 0; slotNum < NUM_ANIM_SLOTS; ++slotNum )
   3.217 +       { idleSlv = VSs__create_slave_helper( &idle_fn, NULL, semanticEnv, 0);
   3.218 +         idleSlv->coreAnimatedBy                = coreNum;
   3.219 +         idleSlv->animSlotAssignedTo            =
   3.220 +                               _VMSMasterEnv->allAnimSlots[coreNum][slotNum];
   3.221 +         semanticEnv->idleSlv[coreNum][slotNum] = idleSlv;
   3.222 +         
   3.223 +         slotTaskSlv = VSs__create_slave_helper( &idle_fn, NULL, semanticEnv, 0);
   3.224 +         slotTaskSlv->coreAnimatedBy            = coreNum;
   3.225 +         slotTaskSlv->animSlotAssignedTo        = 
   3.226 +                               _VMSMasterEnv->allAnimSlots[coreNum][slotNum];
   3.227 +         
   3.228 +         semData                    = slotTaskSlv->semanticData;
   3.229 +         semData->needsTaskAssigned = TRUE;
   3.230 +         semData->slaveType         = SlotTaskSlv;
   3.231 +         semanticEnv->slotTaskSlvs[coreNum][slotNum] = slotTaskSlv;
   3.232 +       }
   3.233 +    }
   3.234 +
   3.235 +      //create the ready queues, hash tables used for matching and so forth
   3.236 +   semanticEnv->slavesReadyToResumeQ = makeVMSQ();
   3.237 +   semanticEnv->freeExtraTaskSlvQ    = makeVMSQ();
   3.238 +   semanticEnv->taskReadyQ           = makeVMSQ();
   3.239 +   
   3.240 +   semanticEnv->argPtrHashTbl  = makeHashTable32( 16, &VMS_int__free );
   3.241 +   semanticEnv->commHashTbl    = makeHashTable32( 16, &VMS_int__free );
   3.242 +   
   3.243 +   semanticEnv->nextCoreToGetNewSlv = 0;
   3.244 +   
   3.245 +
   3.246 +   //TODO: bug -- turn these arrays into dyn arrays to eliminate limit
   3.247 +   //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( );
   3.248 +   //semanticEnv->transactionStrucs = makeDynArrayInfo( );
   3.249 +   for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ )
   3.250 +    {
   3.251 +      semanticEnv->fnSingletons[i].endInstrAddr      = NULL;
   3.252 +      semanticEnv->fnSingletons[i].hasBeenStarted    = FALSE;
   3.253 +      semanticEnv->fnSingletons[i].hasFinished       = FALSE;
   3.254 +      semanticEnv->fnSingletons[i].waitQ             = makeVMSQ();
   3.255 +      semanticEnv->transactionStrucs[i].waitingVPQ   = makeVMSQ();
   3.256 +    }
   3.257 +
   3.258 +   semanticEnv->numLiveExtraTaskSlvs   = 0; //must be last
   3.259 +   semanticEnv->numLiveThreadSlvs      = 1; //must be last, counts the seed
   3.260 +
   3.261 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   3.262 +   semanticEnv->unitList = makeListOfArrays(sizeof(Unit),128);
   3.263 +   semanticEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128);
   3.264 +   semanticEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128);
   3.265 +   semanticEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128);
   3.266 +   semanticEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semanticEnv->ntonGroups),8);
   3.267 +   
   3.268 +   semanticEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128);
   3.269 +   memset(semanticEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit)));
   3.270 +   #endif
   3.271 + }
   3.272 +
   3.273 +
   3.274 +/*Frees any memory allocated by VSs__init() then calls VMS_int__shutdown
   3.275 + */
   3.276 +void
   3.277 +VSs__cleanup_after_shutdown()
   3.278 + { VSsSemEnv *semanticEnv;
   3.279 +   
   3.280 +   semanticEnv = _VMSMasterEnv->semanticEnv;
   3.281 +
   3.282 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   3.283 +   //UCC
   3.284 +   FILE* output;
   3.285 +   int n;
   3.286 +   char filename[255];    
   3.287 +    for(n=0;n<255;n++)
   3.288 +    {
   3.289 +        sprintf(filename, "./counters/UCC.%d",n);
   3.290 +        output = fopen(filename,"r");
   3.291 +        if(output)
   3.292 +        {
   3.293 +            fclose(output);
   3.294 +        }else{
   3.295 +            break;
   3.296 +        }
   3.297 +    }
   3.298 +   if(n<255){
   3.299 +    printf("Saving UCC to File: %s ...\n", filename);
   3.300 +    output = fopen(filename,"w+");
   3.301 +    if(output!=NULL){
   3.302 +        set_dependency_file(output);
   3.303 +        //fprintf(output,"digraph Dependencies {\n");
   3.304 +        //set_dot_file(output);
   3.305 +        //FIXME:  first line still depends on counters being enabled, replace w/ unit struct!
   3.306 +        //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info );
   3.307 +        forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file);
   3.308 +        forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file );
   3.309 +        forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file );
   3.310 +        forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file);
   3.311 +        //fprintf(output,"}\n");
   3.312 +        fflush(output);
   3.313 +
   3.314 +    } else
   3.315 +        printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n");
   3.316 +   } else {
   3.317 +       printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n");
   3.318 +   }
   3.319 +   //Loop Graph
   3.320 +   for(n=0;n<255;n++)
   3.321 +    {
   3.322 +        sprintf(filename, "./counters/LoopGraph.%d",n);
   3.323 +        output = fopen(filename,"r");
   3.324 +        if(output)
   3.325 +        {
   3.326 +            fclose(output);
   3.327 +        }else{
   3.328 +            break;
   3.329 +        }
   3.330 +    }
   3.331 +   if(n<255){
   3.332 +    printf("Saving LoopGraph to File: %s ...\n", filename);
   3.333 +    output = fopen(filename,"w+");
   3.334 +    if(output!=NULL){
   3.335 +        set_dependency_file(output);
   3.336 +        //fprintf(output,"digraph Dependencies {\n");
   3.337 +        //set_dot_file(output);
   3.338 +        //FIXME:  first line still depends on counters being enabled, replace w/ unit struct!
   3.339 +        //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info );
   3.340 +        forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file );
   3.341 +        forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file );
   3.342 +        forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file );
   3.343 +        forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file );
   3.344 +        forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file );
   3.345 +        //fprintf(output,"}\n");
   3.346 +        fflush(output);
   3.347 +
   3.348 +    } else
   3.349 +        printf("Opening LoopGraph file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n");
   3.350 +   } else {
   3.351 +       printf("Could not open LoopGraph file, please clean \"counters\" folder. (Must contain less than 255 files.)\n");
   3.352 +   }
   3.353 +   
   3.354 +   
   3.355 +   freeListOfArrays(semanticEnv->unitList);
   3.356 +   freeListOfArrays(semanticEnv->commDependenciesList);
   3.357 +   freeListOfArrays(semanticEnv->ctlDependenciesList);
   3.358 +   freeListOfArrays(semanticEnv->dynDependenciesList);
   3.359 +   
   3.360 +   #endif
   3.361 +#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS    
   3.362 +    for(n=0;n<255;n++)
   3.363 +    {
   3.364 +        sprintf(filename, "./counters/Counters.%d.csv",n);
   3.365 +        output = fopen(filename,"r");
   3.366 +        if(output)
   3.367 +        {
   3.368 +            fclose(output);
   3.369 +        }else{
   3.370 +            break;
   3.371 +        }
   3.372 +    }
   3.373 +    if(n<255){
   3.374 +    printf("Saving Counter measurements to File: %s ...\n", filename);
   3.375 +    output = fopen(filename,"w+");
   3.376 +    if(output!=NULL){
   3.377 +        set_counter_file(output);
   3.378 +        int i;
   3.379 +        for(i=0;i<NUM_CORES;i++){
   3.380 +            forAllInListOfArraysDo( semanticEnv->counterList[i], &print_counter_events_to_file );
   3.381 +            fflush(output);
   3.382 +        }
   3.383 +
   3.384 +    } else
   3.385 +        printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n");
   3.386 +   } else {
   3.387 +       printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n");
   3.388 +   }
   3.389 +    
   3.390 +#endif
   3.391 +/* It's all allocated inside VMS's big chunk -- that's about to be freed, so
   3.392 + *  nothing to do here
   3.393 +   
   3.394 +
   3.395 +   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   3.396 +    {
   3.397 +      VMS_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData );
   3.398 +      VMS_int__free( semanticEnv->readyVPQs[coreIdx] );
   3.399 +    }
   3.400 +   VMS_int__free( semanticEnv->readyVPQs );
   3.401 +   
   3.402 +   freeHashTable( semanticEnv->commHashTbl );
   3.403 +   VMS_int__free( _VMSMasterEnv->semanticEnv );
   3.404 + */
   3.405 +   VMS_SS__cleanup_at_end_of_shutdown();
   3.406 + }
   3.407 +
   3.408 +
   3.409 +//===========================================================================
   3.410 +
   3.411 +SlaveVP *
   3.412 +VSs__create_thread( TopLevelFnPtr fnPtr,   void *initData,
   3.413 +                        SlaveVP *creatingThd )
   3.414 + { VSsSemReq reqData;
   3.415 +
   3.416 +      //the semantic request data is on the stack and disappears when this
   3.417 +      // call returns -- it's guaranteed to remain in the VP's stack for as
   3.418 +      // long as the VP is suspended.
   3.419 +   reqData.reqType            = 0; //know type because in a VMS create req
   3.420 +   reqData.fnPtr              = fnPtr;
   3.421 +   reqData.initData           = initData;
   3.422 +   reqData.callingSlv         = creatingThd;
   3.423 +
   3.424 +   VMS_WL__send_create_slaveVP_req( &reqData, creatingThd );
   3.425 +
   3.426 +   return creatingThd->dataRetFromReq;
   3.427 + }
   3.428 +
   3.429 +/*This is always the last thing done in the code animated by a thread VP.
   3.430 + * Normally, this would be the last line of the thread's top level function.
   3.431 + * But, if the thread exits from any point, it has to do so by calling
   3.432 + * this.
   3.433 + *
   3.434 + *It simply sends a dissipate request, which handles all the state cleanup.
   3.435 + */
   3.436 +void
   3.437 +VSs__end_thread( SlaveVP *thdToEnd )
   3.438 + { VSsSemData *semData;
   3.439 +   
   3.440 +   VMS_WL__send_dissipate_req( thdToEnd );
   3.441 + }
   3.442 +
   3.443 +
   3.444 +
   3.445 +//===========================================================================
   3.446 +
   3.447 +
   3.448 +//======================= task submit and end ==============================
   3.449 +/*
   3.450 + */
   3.451 +void
   3.452 +VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv)
   3.453 + { VSsSemReq  reqData;
   3.454 +
   3.455 +   reqData.reqType    = submit_task;
   3.456 +   
   3.457 +   reqData.taskType   = taskType;
   3.458 +   reqData.args       = args;
   3.459 +   reqData.callingSlv = animSlv;
   3.460 +  
   3.461 +   reqData.taskID     = NULL;
   3.462 + 
   3.463 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.464 + }
   3.465 +
   3.466 +inline int32 *
   3.467 +VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv )
   3.468 + { int32 *taskID;
   3.469 +   
   3.470 +   taskID    = VMS_WL__malloc( sizeof(int32) + numInts * sizeof(int32) );
   3.471 +   taskID[0] = numInts;
   3.472 +   return taskID;
   3.473 + }
   3.474 +
   3.475 +void
   3.476 +VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, 
   3.477 +                          SlaveVP     *animSlv)
   3.478 + { VSsSemReq  reqData;
   3.479 +
   3.480 +   reqData.reqType    = submit_task;
   3.481 +   
   3.482 +   reqData.taskType   = taskType;
   3.483 +   reqData.args       = args;
   3.484 +   reqData.taskID     = taskID;
   3.485 +   reqData.callingSlv = animSlv;
   3.486 + 
   3.487 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.488 + }
   3.489 +
   3.490 +
   3.491 +/*This call is the last to happen in every task.  It causes the slave to
   3.492 + * suspend and get the next task out of the task-queue.  Notice there is no
   3.493 + * assigner here.. only one slave, no slave ReadyQ, and so on..
   3.494 + *Can either make the assigner take the next task out of the taskQ, or can
   3.495 + * leave all as it is, and make task-end take the next task.
   3.496 + *Note: this fits the case in the new VMS for no-context tasks, so will use
   3.497 + * the built-in taskQ of new VMS, and should be local and much faster.
   3.498 + * 
   3.499 + *The task-stub is saved in the animSlv, so the request handler will get it
   3.500 + * from there, along with the task-type which has arg types, and so on..
   3.501 + * 
   3.502 + * NOTE: if want, don't need to send the animating SlaveVP around.. 
   3.503 + * instead, can make a single slave per core, and coreCtrlr looks up the
   3.504 + * slave from having the core number.
   3.505 + * 
   3.506 + *But, to stay compatible with all the other VMS languages, leave it in..
   3.507 + */
   3.508 +void
   3.509 +VSs__end_task( SlaveVP *animSlv )
   3.510 + { VSsSemReq  reqData;
   3.511 +
   3.512 +   reqData.reqType      = end_task;
   3.513 +   reqData.callingSlv   = animSlv;
   3.514 +   
   3.515 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.516 + }
   3.517 +
   3.518 +
   3.519 +void
   3.520 +VSs__taskwait(SlaveVP *animSlv)
   3.521 +{
   3.522 +    VSsSemReq  reqData;
   3.523 +
   3.524 +   reqData.reqType      = taskwait;
   3.525 +   reqData.callingSlv   = animSlv;
   3.526 +   
   3.527 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.528 +}
   3.529 +
   3.530 +
   3.531 +
   3.532 +//==========================  send and receive ============================
   3.533 +//
   3.534 +
   3.535 +inline int32 *
   3.536 +VSs__give_self_taskID( SlaveVP *animSlv )
   3.537 + {
   3.538 +   return ((VSsSemData*)animSlv->semanticData)->taskStub->taskID;
   3.539 + }
   3.540 +
   3.541 +//================================ send ===================================
   3.542 +
   3.543 +void
   3.544 +VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID,
   3.545 +                      SlaveVP *senderSlv )
   3.546 + { VSsSemReq  reqData;
   3.547 +
   3.548 +   reqData.reqType    = send_type_to;
   3.549 +   
   3.550 +   reqData.msg        = msg;
   3.551 +   reqData.msgType    = type;
   3.552 +   reqData.receiverID = receiverID;
   3.553 +   reqData.senderSlv  = senderSlv;
   3.554 +   
   3.555 +   reqData.nextReqInHashEntry = NULL;
   3.556 +
   3.557 +   VMS_WL__send_sem_request( &reqData, senderSlv );
   3.558 +
   3.559 +      //When come back from suspend, no longer own data reachable from msg
   3.560 + }
   3.561 +
   3.562 +void
   3.563 +VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv )
   3.564 + { VSsSemReq  reqData;
   3.565 +
   3.566 +   reqData.reqType     = send_from_to;
   3.567 +   
   3.568 +   reqData.msg         = msg;
   3.569 +   reqData.senderID    = senderID;
   3.570 +   reqData.receiverID  = receiverID;
   3.571 +   reqData.senderSlv   = senderSlv;
   3.572 +
   3.573 +   reqData.nextReqInHashEntry = NULL;
   3.574 +
   3.575 +   VMS_WL__send_sem_request( &reqData, senderSlv );
   3.576 + }
   3.577 +
   3.578 +
   3.579 +//================================ receive ================================
   3.580 +
   3.581 +/*The "type" version of send and receive creates a many-to-one relationship.
   3.582 + * The sender is anonymous, and many sends can stack up, waiting to be
   3.583 + * received.  The same receiver can also have send from-to's
   3.584 + * waiting for it, and those will be kept separate from the "type"
   3.585 + * messages.
   3.586 + */
   3.587 +void *
   3.588 +VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv )
   3.589 + {       DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] );
   3.590 +   VSsSemReq  reqData;
   3.591 +
   3.592 +   reqData.reqType     = receive_type_to;
   3.593 +   
   3.594 +   reqData.msgType     = type;
   3.595 +   reqData.receiverID  = receiverID;
   3.596 +   reqData.receiverSlv = receiverSlv;
   3.597 +   
   3.598 +   reqData.nextReqInHashEntry = NULL;
   3.599 +
   3.600 +   VMS_WL__send_sem_request( &reqData, receiverSlv );
   3.601 +   
   3.602 +   return receiverSlv->dataRetFromReq;
   3.603 + }
   3.604 +
   3.605 +
   3.606 +
   3.607 +/*Call this at the point a receiving task wants in-coming data.
   3.608 + * Use this from-to form when know senderID -- it makes a direct channel
   3.609 + * between sender and receiver.
   3.610 + */
   3.611 +void *
   3.612 +VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv )
   3.613 + { 
   3.614 +   VSsSemReq  reqData;
   3.615 +
   3.616 +   reqData.reqType     = receive_from_to;
   3.617 +
   3.618 +   reqData.senderID    = senderID;
   3.619 +   reqData.receiverID  = receiverID;
   3.620 +   reqData.receiverSlv = receiverSlv;
   3.621 +
   3.622 +   reqData.nextReqInHashEntry = NULL;
   3.623 +      DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]);
   3.624 +      
   3.625 +   VMS_WL__send_sem_request( &reqData, receiverSlv );
   3.626 +
   3.627 +   return receiverSlv->dataRetFromReq;
   3.628 + }
   3.629 +
   3.630 +
   3.631 +
   3.632 +
   3.633 +//==========================================================================
   3.634 +//
   3.635 +/*A function singleton is a function whose body executes exactly once, on a
   3.636 + * single core, no matter how many times the fuction is called and no
   3.637 + * matter how many cores or the timing of cores calling it.
   3.638 + *
   3.639 + *A data singleton is a ticket attached to data.  That ticket can be used
   3.640 + * to get the data through the function exactly once, no matter how many
   3.641 + * times the data is given to the function, and no matter the timing of
   3.642 + * trying to get the data through from different cores.
   3.643 + */
   3.644 +
   3.645 +/*asm function declarations*/
   3.646 +void asm_save_ret_to_singleton(VSsSingleton *singletonPtrAddr);
   3.647 +void asm_write_ret_from_singleton(VSsSingleton *singletonPtrAddr);
   3.648 +
   3.649 +/*Fn singleton uses ID as index into array of singleton structs held in the
   3.650 + * semantic environment.
   3.651 + */
   3.652 +void
   3.653 +VSs__start_fn_singleton( int32 singletonID,   SlaveVP *animSlv )
   3.654 + {
   3.655 +   VSsSemReq  reqData;
   3.656 +
   3.657 +      //
   3.658 +   reqData.reqType     = singleton_fn_start;
   3.659 +   reqData.singletonID = singletonID;
   3.660 +
   3.661 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.662 +   if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton
   3.663 +    {
   3.664 +       VSsSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv );
   3.665 +       asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID]));
   3.666 +    }
   3.667 + }
   3.668 +
   3.669 +/*Data singleton hands addr of loc holding a pointer to a singleton struct.
   3.670 + * The start_data_singleton makes the structure and puts its addr into the
   3.671 + * location.
   3.672 + */
   3.673 +void
   3.674 +VSs__start_data_singleton( VSsSingleton **singletonAddr,  SlaveVP *animSlv )
   3.675 + {
   3.676 +   VSsSemReq  reqData;
   3.677 +
   3.678 +   if( *singletonAddr && (*singletonAddr)->hasFinished )
   3.679 +       goto JmpToEndSingleton;
   3.680 +   
   3.681 +   reqData.reqType          = singleton_data_start;
   3.682 +   reqData.singletonPtrAddr = singletonAddr;
   3.683 +
   3.684 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.685 +   if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr
   3.686 +    {    //Assembly code changes the return addr on the stack to the one
   3.687 +         // saved into the singleton by the end-singleton-fn
   3.688 +         //The return addr is at 0x4(%%ebp)
   3.689 +        JmpToEndSingleton:
   3.690 +          asm_write_ret_from_singleton(*singletonAddr);
   3.691 +    }
   3.692 +   //now, simply return
   3.693 +   //will exit either from the start singleton call or the end-singleton call
   3.694 + }
   3.695 +
   3.696 +/*Uses ID as index into array of flags.  If flag already set, resumes from
   3.697 + * end-label.  Else, sets flag and resumes normally.
   3.698 + *
   3.699 + *Note, this call cannot be inlined because the instr addr at the label
   3.700 + * inside is shared by all invocations of a given singleton ID.
   3.701 + */
   3.702 +void
   3.703 +VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv )
   3.704 + {
   3.705 +   VSsSemReq  reqData;
   3.706 +
   3.707 +      //don't need this addr until after at least one singleton has reached
   3.708 +      // this function
   3.709 +   VSsSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv );
   3.710 +   asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID]));
   3.711 +
   3.712 +   reqData.reqType     = singleton_fn_end;
   3.713 +   reqData.singletonID = singletonID;
   3.714 +
   3.715 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.716 +
   3.717 +EndSingletonInstrAddr:
   3.718 +   return;
   3.719 + }
   3.720 +
   3.721 +void
   3.722 +VSs__end_data_singleton(  VSsSingleton **singletonPtrAddr, SlaveVP *animSlv )
   3.723 + {
   3.724 +   VSsSemReq  reqData;
   3.725 +
   3.726 +      //don't need this addr until after singleton struct has reached
   3.727 +      // this function for first time
   3.728 +      //do assembly that saves the return addr of this fn call into the
   3.729 +      // data singleton -- that data-singleton can only be given to exactly
   3.730 +      // one instance in the code of this function.  However, can use this
   3.731 +      // function in different places for different data-singletons.
   3.732 +//   (*(singletonAddr))->endInstrAddr =  &&EndDataSingletonInstrAddr;
   3.733 +
   3.734 +
   3.735 +   asm_save_ret_to_singleton(*singletonPtrAddr);
   3.736 +
   3.737 +   reqData.reqType          = singleton_data_end;
   3.738 +   reqData.singletonPtrAddr = singletonPtrAddr;
   3.739 +
   3.740 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.741 + }
   3.742 +
   3.743 +/*This executes the function in the masterVP, so it executes in isolation
   3.744 + * from any other copies -- only one copy of the function can ever execute
   3.745 + * at a time.
   3.746 + *
   3.747 + *It suspends to the master, and the request handler takes the function
   3.748 + * pointer out of the request and calls it, then resumes the VP.
   3.749 + *Only very short functions should be called this way -- for longer-running
   3.750 + * isolation, use transaction-start and transaction-end, which run the code
   3.751 + * between as work-code.
   3.752 + */
   3.753 +void
   3.754 +VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
   3.755 +                                    void *data, SlaveVP *animSlv )
   3.756 + {
   3.757 +   VSsSemReq  reqData;
   3.758 +
   3.759 +      //
   3.760 +   reqData.reqType          = atomic;
   3.761 +   reqData.fnToExecInMaster = ptrToFnToExecInMaster;
   3.762 +   reqData.dataForFn        = data;
   3.763 +
   3.764 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.765 + }
   3.766 +
   3.767 +
   3.768 +/*This suspends to the master.
   3.769 + *First, it looks at the VP's data, to see the highest transactionID that VP
   3.770 + * already has entered.  If the current ID is not larger, it throws an
   3.771 + * exception stating a bug in the code.  Otherwise it puts the current ID
   3.772 + * there, and adds the ID to a linked list of IDs entered -- the list is
   3.773 + * used to check that exits are properly ordered.
   3.774 + *Next it is uses transactionID as index into an array of transaction
   3.775 + * structures.
   3.776 + *If the "VP_currently_executing" field is non-null, then put requesting VP
   3.777 + * into queue in the struct.  (At some point a holder will request
   3.778 + * end-transaction, which will take this VP from the queue and resume it.)
   3.779 + *If NULL, then write requesting into the field and resume.
   3.780 + */
   3.781 +void
   3.782 +VSs__start_transaction( int32 transactionID, SlaveVP *animSlv )
   3.783 + {
   3.784 +   VSsSemReq  reqData;
   3.785 +
   3.786 +      //
   3.787 +   reqData.callingSlv      = animSlv;
   3.788 +   reqData.reqType     = trans_start;
   3.789 +   reqData.transID     = transactionID;
   3.790 +
   3.791 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.792 + }
   3.793 +
   3.794 +/*This suspends to the master, then uses transactionID as index into an
   3.795 + * array of transaction structures.
   3.796 + *It looks at VP_currently_executing to be sure it's same as requesting VP.
   3.797 + * If different, throws an exception, stating there's a bug in the code.
   3.798 + *Next it looks at the queue in the structure.
   3.799 + *If it's empty, it sets VP_currently_executing field to NULL and resumes.
   3.800 + *If something in, gets it, sets VP_currently_executing to that VP, then
   3.801 + * resumes both.
   3.802 + */
   3.803 +void
   3.804 +VSs__end_transaction( int32 transactionID, SlaveVP *animSlv )
   3.805 + {
   3.806 +   VSsSemReq  reqData;
   3.807 +
   3.808 +      //
   3.809 +   reqData.callingSlv      = animSlv;
   3.810 +   reqData.reqType     = trans_end;
   3.811 +   reqData.transID     = transactionID;
   3.812 +
   3.813 +   VMS_WL__send_sem_request( &reqData, animSlv );
   3.814 + }
   3.815 +
   3.816 +//======================== Internal ==================================
   3.817 +/*
   3.818 + */
   3.819 +SlaveVP *
   3.820 +VSs__create_slave_with( TopLevelFnPtr fnPtr,   void *initData,
   3.821 +                        SlaveVP *creatingSlv )
   3.822 + { VSsSemReq reqData;
   3.823 +
   3.824 +      //the semantic request data is on the stack and disappears when this
   3.825 +      // call returns -- it's guaranteed to remain in the VP's stack for as
   3.826 +      // long as the VP is suspended.
   3.827 +   reqData.reqType            = 0; //know type because in a VMS create req
   3.828 +   reqData.coreToAssignOnto = -1; //means round-robin assign
   3.829 +   reqData.fnPtr              = fnPtr;
   3.830 +   reqData.initData           = initData;
   3.831 +   reqData.callingSlv             = creatingSlv;
   3.832 +
   3.833 +   VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv );
   3.834 +
   3.835 +   return creatingSlv->dataRetFromReq;
   3.836 + }
   3.837 +
   3.838 +SlaveVP *
   3.839 +VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData,
   3.840 +                        SlaveVP *creatingSlv,  int32  coreToAssignOnto )
   3.841 + { VSsSemReq  reqData;
   3.842 +
   3.843 +      //the semantic request data is on the stack and disappears when this
   3.844 +      // call returns -- it's guaranteed to remain in the VP's stack for as
   3.845 +      // long as the VP is suspended.
   3.846 +   reqData.reqType            = create_slave_w_aff; //not used, May 2012
   3.847 +   reqData.coreToAssignOnto   = coreToAssignOnto;
   3.848 +   reqData.fnPtr              = fnPtr;
   3.849 +   reqData.initData           = initData;
   3.850 +   reqData.callingSlv         = creatingSlv;
   3.851 +
   3.852 +   VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv );
   3.853 +
   3.854 +   return creatingSlv->dataRetFromReq;
   3.855 + }
   3.856 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/DKU.h	Mon Aug 27 02:14:35 2012 -0700
     4.3 @@ -0,0 +1,374 @@
     4.4 +/*
     4.5 + *  Copyright 2009 OpenSourceStewardshipFoundation.org
     4.6 + *  Licensed under GNU General Public License version 2
     4.7 + *
     4.8 + * Author: seanhalle@yahoo.com
     4.9 + *
    4.10 + */
    4.11 +
    4.12 +#ifndef _VSs_H
    4.13 +#define	_VSs_H
    4.14 +
    4.15 +#include "Queue_impl/PrivateQueue.h"
    4.16 +#include "Hash_impl/PrivateHash.h"
    4.17 +#include "VMS_impl/VMS.h"
    4.18 +#include "Measurement/dependency.h"
    4.19 +
    4.20 +
    4.21 +//===========================================================================
    4.22 +#define NUM_STRUCS_IN_SEM_ENV 1000
    4.23 +
    4.24 +   //This is hardware dependent -- it's the number of cycles of scheduling
    4.25 +   // overhead -- if a work unit is fewer than this, it is better being
    4.26 +   // combined sequentially with other work
    4.27 +   //This value depends on both VMS overhead and VSs's plugin.  At some point
    4.28 +   // it will be derived by perf-counter measurements during init of VSs
    4.29 +#define MIN_WORK_UNIT_CYCLES 20000
    4.30 +
    4.31 +//===========================================================================
    4.32 +/*This header defines everything specific to the VSs semantic plug-in
    4.33 + */
    4.34 +typedef struct _VSsSemReq   VSsSemReq;
    4.35 +typedef void  (*VSsTaskFnPtr )   ( void *, SlaveVP *);
    4.36 +typedef void  (*PtrToAtomicFn )  ( void * ); //executed atomically in master
    4.37 +//===========================================================================
    4.38 +
    4.39 +#define NONCTLD 0
    4.40 +#define IN      1  /*Trick -- READER same as IN*/
    4.41 +#define OUT     2  /*Trick -- WRITER same as OUT and INOUT*/
    4.42 +#define INOUT   2  /*Trick -- WRITER same as OUT and INOUT*/
    4.43 +
    4.44 +#define READER  1  /*Trick -- READER same as IN*/
    4.45 +#define WRITER  2  /*Trick -- WRITER same as OUT and INOUT*/
    4.46 +
    4.47 +#define IS_A_THREAD NULL
    4.48 +#define IS_ENDED    NULL
    4.49 +#define SEED_SLV    NULL
    4.50 +
    4.51 +typedef struct
    4.52 + {
    4.53 +   VSsTaskFnPtr fn;
    4.54 +   int32  numTotalArgs;//the number of inputs to function
    4.55 +   int32  numCtldArgs;//how many of args have dependencies
    4.56 +   int32 *argTypes;   //says reader, writer, or non-ctld
    4.57 +   int32 *argSizes;   //for detecting overlap
    4.58 +   int32  sizeOfArgs; //for memcpy of args struct
    4.59 + }
    4.60 +VSsTaskType;
    4.61 +
    4.62 +
    4.63 +typedef struct
    4.64 + {
    4.65 +   bool32       hasEnabledNonFinishedWriter;
    4.66 +   int32        numEnabledNonDoneReaders;
    4.67 +   PrivQueueStruc *waitersQ;
    4.68 + }
    4.69 +VSsPointerEntry;
    4.70 +
    4.71 +typedef struct
    4.72 + {
    4.73 +   void       **args; //ctld args must come first, as ptrs
    4.74 +   VSsTaskType *taskType;
    4.75 +   int32       *taskID;
    4.76 +   int32        numBlockingProp;
    4.77 +   SlaveVP     *slaveAssignedTo; //only valid before end task (thread)
    4.78 +   VSsPointerEntry  **ptrEntries;
    4.79 +   void*        parentTaskStub;
    4.80 +   int32        numLiveChildTasks;
    4.81 +   int32        numLiveChildThreads;
    4.82 +   bool32       isWaitingForChildTasksToEnd;
    4.83 +   bool32       isWaitingForChildThreadsToEnd;
    4.84 +   bool32       isEnded;
    4.85 + }
    4.86 +VSsTaskStub;
    4.87 +
    4.88 +
    4.89 +typedef struct
    4.90 + {
    4.91 +   VSsTaskStub *taskStub;
    4.92 +   int32        argNum;
    4.93 +   int32        isReader;
    4.94 + }
    4.95 +VSsTaskStubCarrier;
    4.96 +
    4.97 +
    4.98 +/*Semantic layer-specific data sent inside a request from lib called in app
    4.99 + * to request handler called in AnimationMaster
   4.100 + */
   4.101 +
   4.102 +typedef struct
   4.103 + {
   4.104 +   SlaveVP      *VPCurrentlyExecuting;
   4.105 +   PrivQueueStruc *waitingVPQ;
   4.106 + }
   4.107 +VSsTrans;
   4.108 +
   4.109 +/*WARNING: assembly hard-codes position of endInstrAddr as first field
   4.110 + */
   4.111 +typedef struct
   4.112 + {
   4.113 +   void           *endInstrAddr;
   4.114 +   int32           hasBeenStarted;
   4.115 +   int32           hasFinished;
   4.116 +   PrivQueueStruc *waitQ;
   4.117 + }
   4.118 +VSsSingleton;
   4.119 +
   4.120 +enum VSsReqType
   4.121 + {
   4.122 +   submit_task = 1,
   4.123 +   end_task,
   4.124 +   create_slave,
   4.125 +   create_slave_w_aff,
   4.126 +   dissipate_slave,
   4.127 +   //===============================
   4.128 +   send_type_to,
   4.129 +   receive_type_to,
   4.130 +   send_from_to,
   4.131 +   receive_from_to,
   4.132 +   //===============================
   4.133 +   taskwait,
   4.134 +   malloc_req,
   4.135 +   free_req,
   4.136 +   singleton_fn_start,
   4.137 +   singleton_fn_end,
   4.138 +   singleton_data_start,
   4.139 +   singleton_data_end,
   4.140 +   atomic,
   4.141 +   trans_start,
   4.142 +   trans_end
   4.143 + };
   4.144 +
   4.145 +struct _VSsSemReq
   4.146 + { enum VSsReqType    reqType;
   4.147 +   SlaveVP           *callingSlv;
   4.148 +   VSsTaskType       *taskType;
   4.149 +   void              *args;
   4.150 +   VSsTaskStub       *taskStub;
   4.151 +   
   4.152 +   SlaveVP           *senderSlv;
   4.153 +   SlaveVP           *receiverSlv;
   4.154 +   int32             *senderID;
   4.155 +   int32             *receiverID;
   4.156 +   int32              msgType;
   4.157 +   void              *msg;
   4.158 +   VSsSemReq         *nextReqInHashEntry;
   4.159 +   int32             *taskID;
   4.160 +   
   4.161 +   TopLevelFnPtr      fnPtr;
   4.162 +   void              *initData;
   4.163 +   int32              coreToAssignOnto;
   4.164 +
   4.165 +   int32              sizeToMalloc;
   4.166 +   void              *ptrToFree;
   4.167 +
   4.168 +   int32              singletonID;
   4.169 +   VSsSingleton     **singletonPtrAddr;
   4.170 +
   4.171 +   PtrToAtomicFn      fnToExecInMaster;
   4.172 +   void              *dataForFn;
   4.173 +
   4.174 +   int32              transID;
   4.175 + }
   4.176 +/* VSsSemReq */;
   4.177 +
   4.178 +
   4.179 +typedef struct
   4.180 + {
   4.181 +   PrivQueueStruc  *slavesReadyToResumeQ; //Shared (slaves not pinned)
   4.182 +   PrivQueueStruc  *freeExtraTaskSlvQ;    //Shared
   4.183 +   PrivQueueStruc  *taskReadyQ;           //Shared (tasks not pinned)
   4.184 +   SlaveVP         *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS];
   4.185 +   HashTable       *argPtrHashTbl;
   4.186 +   HashTable       *commHashTbl;
   4.187 +   int32            numLiveExtraTaskSlvs;
   4.188 +   int32            numLiveThreadSlvs;
   4.189 +   int32            nextCoreToGetNewSlv;
   4.190 +   int32            primitiveStartTime;
   4.191 +
   4.192 +                       //fix limit on num with dynArray
   4.193 +   VSsSingleton     fnSingletons[NUM_STRUCS_IN_SEM_ENV];
   4.194 +   VSsTrans         transactionStrucs[NUM_STRUCS_IN_SEM_ENV];
   4.195 +
   4.196 +   bool32          *coreIsDone;
   4.197 +   int32            numCoresDone;
   4.198 +   
   4.199 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   4.200 +   ListOfArrays* unitList;
   4.201 +   ListOfArrays* ctlDependenciesList;
   4.202 +   ListOfArrays* commDependenciesList;
   4.203 +   NtoN** ntonGroups;
   4.204 +   PrivDynArrayInfo* ntonGroupsInfo;
   4.205 +   ListOfArrays* dynDependenciesList;
   4.206 +   Unit last_in_slot[NUM_CORES * NUM_ANIM_SLOTS];
   4.207 +   ListOfArrays* hwArcs;
   4.208 +   #endif
   4.209 +
   4.210 +   #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS
   4.211 +   ListOfArrays* counterList[NUM_CORES];
   4.212 +   #endif
   4.213 +   SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS];
   4.214 +   int shutdownInitiated;
   4.215 + }
   4.216 +VSsSemEnv;
   4.217 +
   4.218 +
   4.219 +typedef struct _TransListElem TransListElem;
   4.220 +struct _TransListElem
   4.221 + {
   4.222 +   int32          transID;
   4.223 +   TransListElem *nextTrans;
   4.224 + };
   4.225 +//TransListElem
   4.226 + 
   4.227 +enum VSsSlvType
   4.228 + { ExtraTaskSlv = 1,
   4.229 +   SlotTaskSlv,
   4.230 +   ThreadSlv
   4.231 + };
   4.232 + 
   4.233 +typedef struct
   4.234 + {
   4.235 +   int32           highestTransEntered;
   4.236 +   TransListElem  *lastTransEntered;
   4.237 +   bool32          needsTaskAssigned;
   4.238 +   VSsTaskStub    *taskStub;
   4.239 +   enum VSsSlvType slaveType;
   4.240 + }
   4.241 +VSsSemData;
   4.242 + 
   4.243 +//===========================================================================
   4.244 +
   4.245 +void
   4.246 +VSs__create_seed_slave_and_do_work( TopLevelFnPtr fn, void *initData );
   4.247 +
   4.248 +int32
   4.249 +VSs__giveMinWorkUnitCycles( float32 percentOverhead );
   4.250 +
   4.251 +void
   4.252 +VSs__start_primitive();
   4.253 +
   4.254 +int32
   4.255 +VSs__end_primitive_and_give_cycles();
   4.256 +
   4.257 +int32
   4.258 +VSs__giveIdealNumWorkUnits();
   4.259 +
   4.260 +int32
   4.261 +VSs__give_number_of_cores_to_schedule_onto();
   4.262 +
   4.263 +//=======================
   4.264 +
   4.265 +void
   4.266 +VSs__init();
   4.267 +
   4.268 +void
   4.269 +VSs__cleanup_after_shutdown();
   4.270 +
   4.271 +//=======================
   4.272 +
   4.273 +SlaveVP *
   4.274 +VSs__create_thread( TopLevelFnPtr fnPtr,   void *initData,
   4.275 +                                                     SlaveVP *creatingThd );
   4.276 +
   4.277 +void
   4.278 +VSs__end_thread( SlaveVP *thdToEnd );
   4.279 +
   4.280 +//=======================
   4.281 +
   4.282 +#define VSs__malloc( numBytes, callingSlave ) VMS_App__malloc( numBytes, callingSlave)
   4.283 +
   4.284 +#define VSs__free(ptrToFree, callingSlave ) VMS_App__free( ptrToFree, callingSlave )
   4.285 +
   4.286 +
   4.287 +//=======================
   4.288 +void
   4.289 +VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv);
   4.290 +
   4.291 +inline int32 *
   4.292 +VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv );
   4.293 +
   4.294 +void
   4.295 +VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, 
   4.296 +                          SlaveVP     *animSlv);
   4.297 +
   4.298 +void
   4.299 +VSs__end_task( SlaveVP *animSlv );
   4.300 +
   4.301 +//=========================
   4.302 +void
   4.303 +VSs__taskwait(SlaveVP *animSlv);
   4.304 +
   4.305 +
   4.306 +inline int32 *
   4.307 +VSs__give_self_taskID( SlaveVP *animSlv );
   4.308 +
   4.309 +void
   4.310 +VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID,
   4.311 +                      SlaveVP *senderSlv );
   4.312 +
   4.313 +void
   4.314 +VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv );
   4.315 +
   4.316 +void *
   4.317 +VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv );
   4.318 +
   4.319 +void *
   4.320 +VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv );
   4.321 +
   4.322 +//======================= Concurrency Stuff ======================
   4.323 +void
   4.324 +VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv );
   4.325 +
   4.326 +void
   4.327 +VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv );
   4.328 +
   4.329 +void
   4.330 +VSs__start_data_singleton( VSsSingleton **singeltonAddr, SlaveVP *animSlv );
   4.331 +
   4.332 +void
   4.333 +VSs__end_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv );
   4.334 +
   4.335 +void
   4.336 +VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
   4.337 +                                    void *data, SlaveVP *animSlv );
   4.338 +
   4.339 +void
   4.340 +VSs__start_transaction( int32 transactionID, SlaveVP *animSlv );
   4.341 +
   4.342 +void
   4.343 +VSs__end_transaction( int32 transactionID, SlaveVP *animSlv );
   4.344 +
   4.345 +
   4.346 +//=========================  Internal use only  =============================
   4.347 +void
   4.348 +VSs__Request_Handler( SlaveVP *requestingSlv, void *_semEnv );
   4.349 +
   4.350 +SlaveVP *
   4.351 +VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot );
   4.352 +
   4.353 +SlaveVP*
   4.354 +VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData,
   4.355 +                          VSsSemEnv *semEnv,    int32 coreToAssignOnto );
   4.356 +
   4.357 +VSsTaskStub *
   4.358 +create_thread_task_stub( void *initData );
   4.359 +
   4.360 +
   4.361 +SlaveVP *
   4.362 +VSs__create_slave_with( TopLevelFnPtr fnPtr, void *initData,
   4.363 +                          SlaveVP *creatingSlv );
   4.364 +
   4.365 +SlaveVP *
   4.366 +VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr,    void *initData,
   4.367 +                            SlaveVP *creatingSlv, int32 coreToAssignOnto);
   4.368 +
   4.369 +void 
   4.370 +idle_fn(void* data, SlaveVP *animatingSlv);
   4.371 +
   4.372 +//=====================  Measurement of Lang Overheads  =====================
   4.373 +#include "Measurement/VSs_Measurement.h"
   4.374 +
   4.375 +//===========================================================================
   4.376 +#endif	/* _VSs_H */
   4.377 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/DKU_PluginFns.c	Mon Aug 27 02:14:35 2012 -0700
     5.3 @@ -0,0 +1,505 @@
     5.4 +/*
     5.5 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
     5.6 + *
     5.7 + * Licensed under BSD
     5.8 + */
     5.9 +
    5.10 +#include <stdio.h>
    5.11 +#include <stdlib.h>
    5.12 +
    5.13 +#include "Queue_impl/PrivateQueue.h"
    5.14 +#include "VSs.h"
    5.15 +#include "VSs_Request_Handlers.h"
    5.16 +
    5.17 +//=========================== Local Fn Prototypes ===========================
    5.18 +void
    5.19 +resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv );
    5.20 +
    5.21 +inline void
    5.22 +handleSemReq( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv );
    5.23 +
    5.24 +inline void
    5.25 +handleDissipate(                SlaveVP *requestingSlv, VSsSemEnv *semEnv );
    5.26 +
    5.27 +inline void
    5.28 +handleCreate(    VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv );
    5.29 +
    5.30 +//============================== Assigner ==================================
    5.31 +//
    5.32 +/*The assigner is complicated by having both tasks and explicitly created
    5.33 + * VPs, and by tasks being able to suspend.
    5.34 + *It can't use an explicit slave to animate a task because of stack
    5.35 + * pollution. So, it has to keep the two kinds separate.
    5.36 + *Simplest way for the assigner logic is with a Q for extra empty task
    5.37 + * slaves, and another Q for slaves of both types that are ready to resume.
    5.38 + *
    5.39 + *Keep a current task slave for each anim slot. The request handler manages
    5.40 + * it by pulling from the extraTaskSlvQ when a task suspends, or else
    5.41 + * creating a new task slave if taskSlvQ empty. 
    5.42 + *Assigner only assigns a task to the current task slave for the slot.
    5.43 + *If no more tasks, then takes a ready to resume slave, if also none of them
    5.44 + * then dissipates extra task slaves (one per invocation).
    5.45 + *Shutdown condition is: must have no suspended tasks, and no suspended
    5.46 + * explicit slaves and no more tasks in taskQ.  Will only have the masters
    5.47 + * plus a current task slave for each slot.. detects this condition. 
    5.48 + * 
    5.49 + *Having the two types of slave is part of having communications directly
    5.50 + * between tasks, and tasks to explicit slaves, which requires the ability
    5.51 + * to suspend both kinds, but also to keep explicit slave stacks clean from
    5.52 + * the junk tasks are allowed to leave behind.
    5.53 + */
    5.54 +SlaveVP *
    5.55 +VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot )
    5.56 + { SlaveVP     *returnSlv;
    5.57 +   VSsSemEnv   *semEnv;
    5.58 +   VSsSemData  *semData;
    5.59 +   int32        coreNum, slotNum;
    5.60 +   VSsTaskStub *newTaskStub;
    5.61 +   SlaveVP     *extraSlv;
    5.62 +  
    5.63 +   coreNum = slot->coreSlotIsOn;
    5.64 +   slotNum = slot->slotIdx;
    5.65 +   
    5.66 +   semEnv  = (VSsSemEnv *)_semEnv;
    5.67 +   
    5.68 +      //Check for suspended slaves that are ready to resume
    5.69 +   returnSlv = readPrivQ( semEnv->slavesReadyToResumeQ );
    5.70 +   if( returnSlv != NULL )  //Yes, have a slave, so return it.
    5.71 +    { returnSlv->coreAnimatedBy   = coreNum;
    5.72 +    
    5.73 +         //have work, so reset Done flag (when work generated on other core)
    5.74 +      if( semEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf
    5.75 +         semEnv->coreIsDone[coreNum] = FALSE;   //don't just write always
    5.76 +      goto ReturnTheSlv;
    5.77 +    }
    5.78 +   
    5.79 +      //If none, speculate will have a task, so get the slot slave
    5.80 +      //TODO: false sharing ?  (think not bad cause mostly read..)
    5.81 +   returnSlv = semEnv->slotTaskSlvs[coreNum][slotNum];
    5.82 +   
    5.83 +   semData = (VSsSemData *)returnSlv->semanticData;
    5.84 +
    5.85 +      //There is always a curr task slave, and it always needs a task
    5.86 +      // (task slaves that are resuming are in resumeQ)
    5.87 +   newTaskStub = readPrivQ( semEnv->taskReadyQ );
    5.88 +   if( newTaskStub != NULL )
    5.89 +    {    //point slave to task's function, and mark slave as having task
    5.90 +      VMS_int__reset_slaveVP_to_TopLvlFn( returnSlv, 
    5.91 +                          newTaskStub->taskType->fn, newTaskStub->args );
    5.92 +      semData->taskStub            = newTaskStub;
    5.93 +      newTaskStub->slaveAssignedTo = returnSlv;
    5.94 +      semData->needsTaskAssigned   = FALSE;
    5.95 +      
    5.96 +         //have work, so reset Done flag, if was set
    5.97 +      if( semEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf
    5.98 +         semEnv->coreIsDone[coreNum] = FALSE;   //don't just write always
    5.99 +      goto ReturnTheSlv;
   5.100 +    }
   5.101 +   else
   5.102 +    {    //no task, so try to clean up unused extra task slaves
   5.103 +      extraSlv = readPrivQ( semEnv->freeExtraTaskSlvQ );
   5.104 +      if( extraSlv != NULL )
   5.105 +       {    //have two slaves need tasks, so delete one
   5.106 +            //This both bounds the num extras, and delivers shutdown cond
   5.107 +         handleDissipate( extraSlv, semEnv );
   5.108 +            //then return NULL
   5.109 +         returnSlv = NULL;
   5.110 +         goto ReturnTheSlv;
   5.111 +       }
   5.112 +      else
   5.113 +       { //candidate for shutdown.. if all extras dissipated, and no tasks
   5.114 +         // and no ready to resume slaves, then no way to generate
   5.115 +         // more tasks (on this core -- other core might have task still)
   5.116 +         if( semEnv->numLiveExtraTaskSlvs == 0 && 
   5.117 +             semEnv->numLiveThreadSlvs == 0 )
   5.118 +          { //This core sees no way to generate more tasks, so say it
   5.119 +            if( semEnv->coreIsDone[coreNum] == FALSE )
   5.120 +             { semEnv->numCoresDone += 1;
   5.121 +               semEnv->coreIsDone[coreNum] = TRUE;
   5.122 +               #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
   5.123 +               semEnv->shutdownInitiated = TRUE;
   5.124 +               
   5.125 +               #else
   5.126 +               if( semEnv->numCoresDone == NUM_CORES )
   5.127 +                { //means no cores have work, and none can generate more
   5.128 +                  semEnv->shutdownInitiated = TRUE;
   5.129 +                }
   5.130 +               #endif
   5.131 +             }
   5.132 +          }
   5.133 +            //return NULL.. no task and none to resume
   5.134 +         returnSlv = NULL;
   5.135 +            //except if shutdown has been initiated by this or other core
   5.136 +         if(semEnv->shutdownInitiated) 
   5.137 +          { returnSlv = VMS_SS__create_shutdown_slave();
   5.138 +          }
   5.139 +         goto ReturnTheSlv; //don't need, but completes pattern
   5.140 +       } //if( extraSlv != NULL )
   5.141 +    } //if( newTaskStub == NULL )
   5.142 +   //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL
   5.143 +
   5.144 +ReturnTheSlv:  //Nina, doing gotos to here should help with holistic..
   5.145 +
   5.146 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   5.147 +   if( returnSlv == NULL )
   5.148 +    { returnSlv = semEnv->idleSlv[coreNum][slotNum]; 
   5.149 +    
   5.150 +         //things that would normally happen in resume(), but these VPs
   5.151 +         // never go there
   5.152 +      returnSlv->assignCount++; //Somewhere here!
   5.153 +      Unit newu;
   5.154 +      newu.vp = returnSlv->slaveID;
   5.155 +      newu.task = returnSlv->assignCount;
   5.156 +      addToListOfArrays(Unit,newu,semEnv->unitList);
   5.157 +
   5.158 +      if (returnSlv->assignCount > 1)
   5.159 +       { Dependency newd;
   5.160 +         newd.from_vp = returnSlv->slaveID;
   5.161 +         newd.from_task = returnSlv->assignCount - 1;
   5.162 +         newd.to_vp = returnSlv->slaveID;
   5.163 +         newd.to_task = returnSlv->assignCount;
   5.164 +         addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList);  
   5.165 +       }
   5.166 +    }
   5.167 +   #endif
   5.168 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   5.169 +   if( returnSlv != NULL )
   5.170 +    { //assignSlv->numTimesAssigned++;
   5.171 +      Unit prev_in_slot = 
   5.172 +         semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
   5.173 +      if(prev_in_slot.vp != 0)
   5.174 +       { Dependency newd;
   5.175 +         newd.from_vp = prev_in_slot.vp;
   5.176 +         newd.from_task = prev_in_slot.task;
   5.177 +         newd.to_vp = returnSlv->slaveID;
   5.178 +         newd.to_task = returnSlv->assignCount;
   5.179 +         addToListOfArrays(Dependency,newd,semEnv->hwArcs);   
   5.180 +       }
   5.181 +      prev_in_slot.vp = returnSlv->slaveID;
   5.182 +      prev_in_slot.task = returnSlv->assignCount;
   5.183 +      semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
   5.184 +         prev_in_slot;        
   5.185 +    }
   5.186 +   #endif
   5.187 +   return( returnSlv );
   5.188 + }
   5.189 +
   5.190 +
   5.191 +//===========================  Request Handler  ============================
   5.192 +//
   5.193 +/*
   5.194 + * (BTW not inline because invoked indirectly via a pointer)
   5.195 + */
   5.196 +void
   5.197 +VSs__Request_Handler( SlaveVP *requestingSlv, void *_semEnv )
   5.198 + { VSsSemEnv *semEnv;
   5.199 +   VMSReqst  *req;
   5.200 +   
   5.201 +   semEnv = (VSsSemEnv *)_semEnv;
   5.202 +
   5.203 +   req    = VMS_PI__take_next_request_out_of( requestingSlv );
   5.204 +
   5.205 +   while( req != NULL )
   5.206 +    {
   5.207 +      switch( req->reqType )
   5.208 +       { case semantic:     handleSemReq(        req, requestingSlv, semEnv);
   5.209 +            break;
   5.210 +         case createReq:    handleCreate(        req, requestingSlv, semEnv);
   5.211 +            break;
   5.212 +         case dissipate:    handleDissipate(          requestingSlv, semEnv);
   5.213 +            break;
   5.214 +         case VMSSemantic:  VMS_PI__handle_VMSSemReq(req, requestingSlv, semEnv,
   5.215 +                                           (ResumeSlvFnPtr) &resume_slaveVP);
   5.216 +            break;
   5.217 +         default:
   5.218 +            break;
   5.219 +       }
   5.220 +      
   5.221 +      req = VMS_PI__take_next_request_out_of( requestingSlv );
   5.222 +    } //while( req != NULL )
   5.223 +
   5.224 + }
   5.225 +
   5.226 +
   5.227 +inline void
   5.228 +handleSemReq( VMSReqst *req, SlaveVP *reqSlv, VSsSemEnv *semEnv )
   5.229 + { VSsSemReq *semReq;
   5.230 +
   5.231 +   semReq = VMS_PI__take_sem_reqst_from(req);
   5.232 +   if( semReq == NULL ) return;
   5.233 +   switch( semReq->reqType )  //sem handlers are all in other file
   5.234 +    {
   5.235 +      case submit_task:     handleSubmitTask(   semReq,         semEnv);
   5.236 +         break; 
   5.237 +      case end_task:        handleEndTask(      semReq,         semEnv);
   5.238 +         break;
   5.239 +      case send_type_to:    handleSendTypeTo(   semReq,         semEnv);
   5.240 +         break;
   5.241 +      case send_from_to:    handleSendFromTo(   semReq,         semEnv);
   5.242 +         break;
   5.243 +      case receive_type_to: handleReceiveTypeTo(semReq,         semEnv);
   5.244 +         break;
   5.245 +      case receive_from_to: handleReceiveFromTo(semReq,         semEnv);
   5.246 +         break;
   5.247 +      case taskwait:        handleTaskwait(     semReq, reqSlv, semEnv);
   5.248 +           break;
   5.249 +         
   5.250 +      //====================================================================
   5.251 +      case malloc_req:      handleMalloc(       semReq, reqSlv, semEnv);
   5.252 +         break;
   5.253 +      case free_req:        handleFree(         semReq, reqSlv, semEnv);
   5.254 +         break;
   5.255 +      case singleton_fn_start:  handleStartFnSingleton(semReq, reqSlv, semEnv);
   5.256 +         break;
   5.257 +      case singleton_fn_end:    handleEndFnSingleton(  semReq, reqSlv, semEnv);
   5.258 +         break;
   5.259 +      case singleton_data_start:handleStartDataSingleton(semReq,reqSlv,semEnv);
   5.260 +         break;
   5.261 +      case singleton_data_end:  handleEndDataSingleton(semReq, reqSlv, semEnv);
   5.262 +         break;
   5.263 +      case atomic:          handleAtomic(       semReq, reqSlv, semEnv);
   5.264 +         break;
   5.265 +      case trans_start:     handleTransStart(   semReq, reqSlv, semEnv);
   5.266 +         break;
   5.267 +      case trans_end:       handleTransEnd(     semReq, reqSlv, semEnv);
   5.268 +         break;
   5.269 +    }
   5.270 + }
   5.271 +
   5.272 +
   5.273 +
   5.274 +//=========================== VMS Request Handlers ==============================
   5.275 +/*SlaveVP dissipate -- this is NOT task-end!, only call this to get rid of
   5.276 + * extra task slaves, and to end explicitly created threads
   5.277 + */
   5.278 +inline void
   5.279 +handleDissipate( SlaveVP *requestingSlv, VSsSemEnv *semEnv )
   5.280 + { VSsSemData  *semData;
   5.281 +   VSsTaskStub *parentTaskStub, *ownTaskStub;
   5.282 + 
   5.283 +         DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d",
   5.284 +                                                     requestingSlv->slaveID)
   5.285 +   semData = (VSsSemData *)requestingSlv->semanticData;
   5.286 +
   5.287 +   if( semData->slaveType == ExtraTaskSlv )
   5.288 +    { semEnv->numLiveExtraTaskSlvs -= 1; //for detecting shutdown condition
   5.289 +         //Has no task assigned, so no parents and no children, so free self
   5.290 +      goto FreeSlaveStateAndReturn;
   5.291 +    }
   5.292 +
   5.293 +   if( semData->slaveType == SlotTaskSlv )
   5.294 +    {    //should never call dissipate on a slot assigned slave
   5.295 +      VMS_PI__throw_exception( "dissipate a slot-assigned slave", requestingSlv, NULL );
   5.296 +    }
   5.297 +
   5.298 +      //if make it to here, then is a thread slave ending
   5.299 +   semEnv->numLiveThreadSlvs -= 1; //for detecting shutdown condition
   5.300 +   
   5.301 +   ownTaskStub    = semData->taskStub;
   5.302 +   parentTaskStub = ownTaskStub->parentTaskStub;
   5.303 +   parentTaskStub->numLiveChildThreads -= 1;  //not freed, even if ended
   5.304 +   
   5.305 +      //if all children ended, then free this task's stub
   5.306 +      // else, keep stub around, and last child will free it (below)
   5.307 +   if( ownTaskStub->numLiveChildTasks   == 0 &&
   5.308 +       ownTaskStub->numLiveChildThreads == 0 )
   5.309 +      free_task_stub( ownTaskStub );
   5.310 +   else
   5.311 +      ownTaskStub->isEnded = TRUE; //for children to see when they end
   5.312 +
   5.313 +      //Now, check on parents waiting on child threads to end
   5.314 +   if( parentTaskStub->isWaitingForChildThreadsToEnd &&
   5.315 +       parentTaskStub->numLiveChildThreads == 0 )
   5.316 +    { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE;
   5.317 +      if( parentTaskStub->isWaitingForChildTasksToEnd )
   5.318 +        return; //still waiting on tasks (should be impossible)
   5.319 +      else //parent free to resume
   5.320 +        resume_slaveVP( parentTaskStub->slaveAssignedTo, semEnv );
   5.321 +    }
   5.322 +   
   5.323 +      //check if this is last child of ended parent (note, not possible to
   5.324 +      // have more than one level of ancestor waiting to be freed)
   5.325 +   if( parentTaskStub->isEnded )
   5.326 +    { if( parentTaskStub->numLiveChildTasks   == 0 && 
   5.327 +          parentTaskStub->numLiveChildThreads == 0 )
   5.328 +         free_task_stub( parentTaskStub ); //just stub, semData already freed
   5.329 +    }
   5.330 +
   5.331 +      //Free the semData and requesting slave's base state for all cases
   5.332 + FreeSlaveStateAndReturn:
   5.333 +   VMS_PI__free( semData );
   5.334 +   VMS_PI__dissipate_slaveVP( requestingSlv );
   5.335 +   return; 
   5.336 +      //Note, this is not a location to check for shutdown because doesn't
   5.337 +      // say anything about work availability here.. check for shutdown in
   5.338 +      // places try to get work for the core (in the assigner)
   5.339 + }
   5.340 +
   5.341 +   
   5.342 +
   5.343 +/*Re-use this in the entry-point fn
   5.344 + */
   5.345 +inline SlaveVP *
   5.346 +VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData,
   5.347 +                          VSsSemEnv *semEnv,    int32 coreToAssignOnto )
   5.348 + { SlaveVP    *newSlv;
   5.349 +   VSsSemData   *semData;
   5.350 +
   5.351 +      //This is running in master, so use internal version
   5.352 +   newSlv = VMS_PI__create_slaveVP( fnPtr, initData );
   5.353 +
   5.354 +      //task slaves differ from thread slaves by the settings in the taskStub
   5.355 +      //so, don't create task stub here, only create semData, which is same
   5.356 +      // for all kinds of slaves
   5.357 +   semData = VMS_PI__malloc( sizeof(VSsSemData) );
   5.358 +   semData->highestTransEntered = -1;
   5.359 +   semData->lastTransEntered    = NULL;
   5.360 +   semData->needsTaskAssigned   = TRUE;
   5.361 +   semData->taskStub            = NULL;
   5.362 +   
   5.363 +   newSlv->semanticData = semData;
   5.364 +
   5.365 +   //=================== Assign new processor to a core =====================
   5.366 +   #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
   5.367 +   newSlv->coreAnimatedBy = 0;
   5.368 +
   5.369 +   #else
   5.370 +      //Assigning slaves to cores is part of SSR code..
   5.371 +   if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES )
   5.372 +    {    //out-of-range, so round-robin assignment
   5.373 +      newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv;
   5.374 +
   5.375 +      if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 )
   5.376 +          semEnv->nextCoreToGetNewSlv  = 0;
   5.377 +      else
   5.378 +          semEnv->nextCoreToGetNewSlv += 1;
   5.379 +    }
   5.380 +   else //core num in-range, so use it
   5.381 +    { newSlv->coreAnimatedBy = coreToAssignOnto;
   5.382 +    }
   5.383 +   #endif
   5.384 +   //========================================================================
   5.385 +   
   5.386 +   return newSlv;
   5.387 + }
   5.388 +
   5.389 +VSsTaskStub *
   5.390 +create_thread_task_stub( void *initData )
   5.391 + { VSsTaskStub *newStub;
   5.392 +         
   5.393 +   newStub = VMS_PI__malloc( sizeof(VSsTaskStub) );
   5.394 +   newStub->numBlockingProp = 0;
   5.395 +   newStub->slaveAssignedTo = NULL; //set later
   5.396 +   newStub->taskType        = IS_A_THREAD;
   5.397 +   newStub->ptrEntries      = NULL;
   5.398 +   newStub->args            = initData;  
   5.399 +   newStub->numLiveChildTasks              = 0;
   5.400 +   newStub->numLiveChildThreads            = 0;
   5.401 +   newStub->parentTaskStub                = NULL;
   5.402 +   newStub->isWaitingForChildTasksToEnd    = FALSE;
   5.403 +   newStub->isWaitingForChildThreadsToEnd  = FALSE;
   5.404 +   newStub->taskID          = NULL;
   5.405 +
   5.406 +   return newStub;
   5.407 + }
   5.408 +
   5.409 +/*Application invokes this when it explicitly creates a thread via the
   5.410 + * "VSs__create_thread()" command.
   5.411 + * 
   5.412 + *The request handlers create new task slaves directly, not via this hdlr.
   5.413 + * 
   5.414 + *Make everything in VSs be a task.  An explicitly created VP is just a
   5.415 + * suspendable task, and the seedVP is also a suspendable task. 
   5.416 + *So, here, create a task Stub. 
   5.417 + * Then, see if there are any extra slaveVPs hanging around, and if not,
   5.418 + * call the helper to make a new one.
   5.419 + * Then, put the task stub into the slave's semantic Data.
   5.420 + *When the slave calls dissipate, have to recycle the task stub.
   5.421 + */
   5.422 +inline void
   5.423 +handleCreate( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv )
   5.424 + { VSsSemReq  *semReq;
   5.425 +   SlaveVP    *newSlv;
   5.426 +   VSsSemData *semData, *parentSemData;
   5.427 +   
   5.428 +   semReq = VMS_PI__take_sem_reqst_from( req );
   5.429 +
   5.430 +   semEnv->numLiveThreadSlvs += 1;
   5.431 +   
   5.432 +      //Deceptive -- must work when creator is a normal task, or seed,
   5.433 +      // or another thd.. think have valid sem data and task stub for all
   5.434 +      //This hdlr is NOT called when creating the seed slave
   5.435 +   parentSemData = (VSsSemData *)semReq->callingSlv->semanticData;
   5.436 +   parentSemData->taskStub->numLiveChildThreads += 1;
   5.437 +
   5.438 +      //use an idle "extra" slave, if have one
   5.439 +   newSlv = readPrivQ( semEnv->freeExtraTaskSlvQ );
   5.440 +   if( newSlv != NULL ) //got an idle one, so reset it
   5.441 +    { semData = (VSsSemData *)newSlv->semanticData;
   5.442 +      semData->highestTransEntered = -1;
   5.443 +      semData->lastTransEntered    = NULL;
   5.444 +      VMS_int__reset_slaveVP_to_TopLvlFn( newSlv, semReq->fnPtr, 
   5.445 +                                                         semReq->initData );
   5.446 +    }
   5.447 +   else //no idle ones, create a new
   5.448 +    { newSlv = VSs__create_slave_helper( semReq->fnPtr, semReq->initData,
   5.449 +                                         semEnv, semReq->coreToAssignOnto ); 
   5.450 +      semData = (VSsSemData *)newSlv->semanticData;
   5.451 +    }
   5.452 +
   5.453 +      //now, create a new task and assign to the thread
   5.454 +   semData->needsTaskAssigned = FALSE;  //thread has a permanent task
   5.455 +   semData->taskStub = create_thread_task_stub( semReq->initData );
   5.456 +   semData->taskStub->parentTaskStub = parentSemData->taskStub;
   5.457 +   semData->slaveType = ThreadSlv; //this hdlr only creates thread slvs
   5.458 +
   5.459 +         DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d",
   5.460 +                                    requestingSlv->slaveID, newSlv->slaveID)
   5.461 +
   5.462 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   5.463 +   Dependency newd;
   5.464 +   newd.from_vp = requestingSlv->slaveID;
   5.465 +   newd.from_task = requestingSlv->assignCount;
   5.466 +   newd.to_vp = newSlv->slaveID;
   5.467 +   newd.to_task = 1;
   5.468 +   addToListOfArrays(Dependency,newd,semEnv->commDependenciesList);   
   5.469 +   #endif
   5.470 +
   5.471 +      //For VSs, caller needs ptr to created thread returned to it
   5.472 +   requestingSlv->dataRetFromReq = newSlv;
   5.473 +   resume_slaveVP(requestingSlv , semEnv );
   5.474 +   resume_slaveVP( newSlv,        semEnv );
   5.475 + }
   5.476 +
   5.477 +
   5.478 +//=========================== Helper ==============================
   5.479 +void
   5.480 +resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv )
   5.481 + {
   5.482 +      //both suspended tasks and suspended explicit slaves resumed with this
   5.483 +   writePrivQ( slave, semEnv->slavesReadyToResumeQ );
   5.484 +   
   5.485 +   #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS
   5.486 +/*
   5.487 +   int lastRecordIdx = slave->counter_history_array_info->numInArray -1;
   5.488 +   CounterRecord* lastRecord = slave->counter_history[lastRecordIdx];
   5.489 +   saveLowTimeStampCountInto(lastRecord->unblocked_timestamp);
   5.490 +*/
   5.491 +   #endif
   5.492 +   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   5.493 +   slave->assignCount++; //Somewhere here!
   5.494 +   Unit newu;
   5.495 +   newu.vp = slave->slaveID;
   5.496 +   newu.task = slave->assignCount;
   5.497 +   addToListOfArrays(Unit,newu,semEnv->unitList);
   5.498 +   
   5.499 +   if (slave->assignCount > 1){
   5.500 +        Dependency newd;
   5.501 +        newd.from_vp = slave->slaveID;
   5.502 +        newd.from_task = slave->assignCount - 1;
   5.503 +        newd.to_vp = slave->slaveID;
   5.504 +        newd.to_task = slave->assignCount;
   5.505 +        addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList);  
   5.506 +   }
   5.507 +   #endif
   5.508 + }
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/DKU_Request_Handlers.c	Mon Aug 27 02:14:35 2012 -0700
     6.3 @@ -0,0 +1,1213 @@
     6.4 +/*
     6.5 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
     6.6 + *
     6.7 + * Licensed under BSD
     6.8 + */
     6.9 +
    6.10 +#include <stdio.h>
    6.11 +#include <stdlib.h>
    6.12 +
    6.13 +#include "VMS_impl/VMS.h"
    6.14 +#include "Queue_impl/PrivateQueue.h"
    6.15 +#include "Hash_impl/PrivateHash.h"
    6.16 +#include "VSs.h"
    6.17 +#include "VSs_Request_Handlers.h"
    6.18 +
    6.19 +
    6.20 +
    6.21 +
    6.22 +//=========================== Local Fn Prototypes ===========================
    6.23 +void
    6.24 +resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv );
    6.25 +
    6.26 +
    6.27 +
    6.28 +//==========================================================================
    6.29 +//                           Helpers
    6.30 +//
    6.31 +
    6.32 +/*Only clone the elements of req used in these reqst handlers
    6.33 + */
    6.34 +VSsSemReq *
    6.35 +cloneReq( VSsSemReq *semReq )
    6.36 + { VSsSemReq *clonedReq;
    6.37 +
    6.38 +   clonedReq             = VMS_PI__malloc( sizeof(VSsSemReq) );
    6.39 +   clonedReq->reqType    = semReq->reqType;
    6.40 +   clonedReq->senderSlv  = semReq->senderSlv;
    6.41 +   clonedReq->receiverSlv= semReq->receiverSlv;
    6.42 +   clonedReq->msg        = semReq->msg;
    6.43 +   clonedReq->nextReqInHashEntry = NULL;
    6.44 +   
    6.45 +   return clonedReq;
    6.46 + }
    6.47 +
    6.48 +
    6.49 +
    6.50 +HashEntry *
    6.51 +giveEntryElseInsertReqst32( int32 *key, VSsSemReq *semReq,
    6.52 +                            HashTable   *commHashTbl )
    6.53 + { HashEntry    *entry;
    6.54 +   VSsSemReq    *waitingReq;
    6.55 +
    6.56 +   entry = getEntryFromTable32( key, commHashTbl );
    6.57 +   if( entry == NULL )
    6.58 +    {    //no waiting sends or receives, so add this request and exit
    6.59 +         // note: have to clone the request because it's on stack of sender
    6.60 +      addValueIntoTable32( key, cloneReq( semReq ), commHashTbl );
    6.61 +      return NULL;
    6.62 +    }
    6.63 +   waitingReq = (VSsSemReq *)entry->content;
    6.64 +   if( waitingReq == NULL )  //might happen when last waiting gets paired
    6.65 +    {    //no waiting sends or receives, so add this request and exit
    6.66 +      entry->content = semReq;
    6.67 +      return NULL;
    6.68 +    }
    6.69 +   return entry;
    6.70 + }
    6.71 +
    6.72 +      
    6.73 +inline VSsPointerEntry *
    6.74 +create_pointer_entry( )
    6.75 + { VSsPointerEntry *newEntry;
    6.76 +   
    6.77 +   newEntry = VMS_PI__malloc( sizeof(VSsPointerEntry) );
    6.78 +   newEntry->hasEnabledNonFinishedWriter = FALSE;
    6.79 +   newEntry->numEnabledNonDoneReaders    = 0;
    6.80 +   newEntry->waitersQ                    = makePrivQ();
    6.81 +      
    6.82 +   return newEntry;
    6.83 + }
    6.84 +
    6.85 +/*malloc's space and initializes fields -- and COPIES the arg values
    6.86 + * to new space
    6.87 + */
    6.88 +inline VSsTaskStub *
    6.89 +create_task_stub( VSsTaskType *taskType, void **args )
    6.90 + { void **newArgs;
    6.91 +   VSsTaskStub* newStub = VMS_int__malloc( sizeof(VSsTaskStub) + taskType->sizeOfArgs );
    6.92 +   newStub->numBlockingProp = taskType->numCtldArgs;
    6.93 +   newStub->slaveAssignedTo = NULL;
    6.94 +   newStub->taskType   = taskType;
    6.95 +   newStub->ptrEntries = 
    6.96 +      VMS_int__malloc( taskType->numCtldArgs * sizeof(VSsPointerEntry *) );
    6.97 +   newArgs = (void **)( (uint8 *)newStub + sizeof(VSsTaskStub) );
    6.98 +   newStub->args = newArgs;
    6.99 +   newStub->numLiveChildTasks   = 0;
   6.100 +   newStub->numLiveChildThreads = 0;
   6.101 +   newStub->isEnded = FALSE;
   6.102 +   
   6.103 +      //Copy the arg-pointers.. can be more arguments than just the ones 
   6.104 +      // that StarSs uses to control ordering of task execution.
   6.105 +   memcpy( newArgs, args, taskType->sizeOfArgs );
   6.106 +   
   6.107 +   return newStub;
   6.108 + }
   6.109 +
   6.110 +inline VSsTaskStubCarrier *
   6.111 +create_task_carrier( VSsTaskStub *taskStub, int32 argNum, int32 rdOrWrite )
   6.112 + { VSsTaskStubCarrier *newCarrier;
   6.113 + 
   6.114 +   newCarrier = VMS_PI__malloc( sizeof(VSsTaskStubCarrier) );
   6.115 +   newCarrier->taskStub = taskStub;
   6.116 +   newCarrier->argNum   = argNum;
   6.117 +   newCarrier->isReader = rdOrWrite == READER;
   6.118 + }
   6.119 +
   6.120 +//==========================================================================
   6.121 +//
   6.122 +//
   6.123 +/*Submit Task
   6.124 + * 
   6.125 + *Uses a hash table to match the arg-pointers to each other. So, an
   6.126 + * argument-pointer is one-to-one with a hash-table entry.
   6.127 + * 
   6.128 + *If overlapping region detection is enabled, then a hash entry is one
   6.129 + * link in a ring of all entries that overlap each other.  For example,
   6.130 + * say region A shared common addresses with region B, but the pointers
   6.131 + * to them are different, then the hash entries for the two would be
   6.132 + * linked in a ring.  When a pointer is processed, all the pointers in
   6.133 + * the ring are processed (Doesn't differentiate independent siblings
   6.134 + * from parent-child or conjoined twins overlap..)
   6.135 + * NOT ENABLED AS OF MAY 25 2012
   6.136 + * 
   6.137 + *A hash entry has a queue of tasks that are waiting to access the
   6.138 + * pointed-to  region.  The queue goes in the order of creation of
   6.139 + * the tasks.  Each entry in the queue has a pointer to the task-stub
   6.140 + * and whether the task reads-only vs writes to the hash-entry's region.
   6.141 + * 
   6.142 + *A hash entry also has a count of the enabled but not yet finished readers
   6.143 + * of the region. It also has a flag that says whether a writer has been
   6.144 + * enabled and is not yet finished.
   6.145 + * 
   6.146 + *There are two kinds of events that access a hash entry: creation of a
   6.147 + * task and end of a task.
   6.148 + *
   6.149 + * 
   6.150 + * ==========================  creation  ========================== 
   6.151 + * 
   6.152 + *At creation, make a task-stub.  Set the count of blocking propendents
   6.153 + * to the number of controlled arguments (a task can have
   6.154 + * arguments that are not controlled by the language, like simple integer
   6.155 + * inputs from the sequential portion. Note that all controlled arguments
   6.156 + * are pointers, and marked as controlled in the application code).
   6.157 + * 
   6.158 + *The controlled arguments are then processed one by one.
   6.159 + *Processing an argument means getting the hash of the pointer.  Then,
   6.160 + * looking up the hash entry.  (If none, create one).
   6.161 + *With the hash entry:
   6.162 + *
   6.163 + *If the arg is a reader, and the entry does not have an enabled
   6.164 + * non-finished writer, and the queue is empty (could be prev readers,
   6.165 + * then a writer that got queued and now new readers that have to also be
   6.166 + * queued).
   6.167 + *The reader is free.  So, decrement the blocking-propendent count in
   6.168 + * the task-stub. If the count is zero, then put the task-stub into the
   6.169 + * readyQ.
   6.170 + *At the same time, increment the hash-entry's count of enabled and
   6.171 + * non-finished readers. 
   6.172 + * 
   6.173 + *Otherwise, the reader is put into the hash-entry's Q of waiters
   6.174 + * 
   6.175 + *If the arg is a writer, plus the entry does not have a current writer,
   6.176 + * plus the number of enabled non-finished readers is zero, plus the Q is
   6.177 + * empty, then the writer is free.  Mark the entry has having an
   6.178 + * enabled and non-finished writer.  Decrement the blocking-propendent
   6.179 + * count in the writer's task-stub. If the count is zero, then put the
   6.180 + * task-stub into the readyQ.
   6.181 + * 
   6.182 + *Otherwise, put the writer into the entry's Q of waiters.
   6.183 + * 
   6.184 + *No matter what, if the hash entry was chained, put it at the start of
   6.185 + * the chain.  (Means no-longer-used pointers accumulate at end of chain,
   6.186 + * decide garbage collection of no-longer-used pointers later)
   6.187 + *
   6.188 + *  
   6.189 + * ========================== end of task ===========================
   6.190 + * 
   6.191 + *At the end of a task,
   6.192 + *The task's controlled arguments are processed one by one.
   6.193 + *Processing an argument means getting the hash of the pointer.  Then,
   6.194 + * looking up the hash entry (and putting the entry at the start of the
   6.195 + * chain, if there was a chain).
   6.196 + *With the hash entry:
   6.197 + *
   6.198 + *If the arg is a reader, then decrement the enabled and non-finished
   6.199 + * reader-count in the hash-entry. If the count becomes zero, then take
   6.200 + * the next entry from the Q. It should be a writer, or else there's a
   6.201 + * bug in this algorithm.
   6.202 + *Set the hash-entry to have an enabled non-finished writer.  Decrement
   6.203 + * the blocking-propendent-count of the writer's task-stub.  If the count
   6.204 + * has reached zero, then put the task-stub into the readyQ.
   6.205 + * 
   6.206 + *If the arg is a writer, then clear the enabled non-finished writer flag
   6.207 + * of the hash-entry. Take the next entry from the Q. 
   6.208 + *If it is a writer, then turn the flag back on.  Decrement the writer's
   6.209 + * blocking-propendent-count in its task-stub.  If it becomes zero, then
   6.210 + * put the task-stub into the readyQ.
   6.211 + *
   6.212 + *If it is a reader, then increment the hash-entry's count of enabled
   6.213 + * non-finished readers.  Decrement the blocking propendents count of the
   6.214 + * reader's task-stub.  If it reaches zero, then put the task-stub into the
   6.215 + * readyQ.
   6.216 + *Then repeat until encounter a writer -- put that writer back into the Q.
   6.217 + * 
   6.218 + *That should be it -- that should work.
   6.219 + */
   6.220 +inline void
   6.221 +handleSubmitTask( VSsSemReq *semReq, VSsSemEnv *semEnv )
   6.222 + { uint32           key[3];
   6.223 +   HashEntry       *rawHashEntry; //has char *, but use with uint32 *
   6.224 +   VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer
   6.225 +   void           **args;
   6.226 +   VSsTaskStub     *taskStub;
   6.227 +   VSsTaskType     *taskType;
   6.228 +   VSsTaskStubCarrier *taskCarrier;
   6.229 +   
   6.230 +   HashTable *
   6.231 +   argPtrHashTbl = semEnv->argPtrHashTbl;
   6.232 +   
   6.233 +      //suspending a task always makes the slave into an extra slot slave,
   6.234 +      // because it ends up in the resumeQ, even when resumes immediately.
   6.235 +      //Eventually task_end will put the slave into the freeExtraTaskSlvQ
   6.236 +   replaceWithNewSlotSlvIfNeeded( semReq->callingSlv, semEnv );
   6.237 + 
   6.238 +   /* ==========================  creation  ========================== 
   6.239 +    * 
   6.240 +    *At creation, make a task-stub.  Set the count of blocking propendents
   6.241 +    * to the number of controlled arguments (a task can have
   6.242 +    * arguments that are not controlled by the language, like simple integer
   6.243 +    * inputs from the sequential portion. Note that all controlled arguments
   6.244 +    * are pointers, and marked as controlled in the application code).
   6.245 +    */
   6.246 +   args     = semReq->args;
   6.247 +   taskType = semReq->taskType;
   6.248 +   taskStub = create_task_stub( taskType, args );//copies arg ptrs
   6.249 +   taskStub->numBlockingProp = taskType->numCtldArgs;
   6.250 +   taskStub->taskID          = semReq->taskID; //may be NULL
   6.251 +   
   6.252 +   VSsSemData* 
   6.253 +   parentSemData = (VSsSemData*) semReq->callingSlv->semanticData;
   6.254 +   taskStub->parentTaskStub = (void*) parentSemData->taskStub;
   6.255 +   parentSemData->taskStub->numLiveChildTasks += 1;
   6.256 +   
   6.257 +         //DEBUG__printf3(dbgRqstHdlr,"Submit req from slaveID: %d, from task: %d, for task: %d", semReq->callingSlv->slaveID, parentSemData->taskStub->taskID[1], taskStub->taskID[1])
   6.258 +         DEBUG__printf2(dbgRqstHdlr,"Submit req from slaveID: %d, for task: %d", semReq->callingSlv->slaveID, taskStub->taskID[1])
   6.259 +          
   6.260 +   /*The controlled arguments are then processed one by one.
   6.261 +    *Processing an argument means getting the hash of the pointer.  Then,
   6.262 +    * looking up the hash entry.  (If none, create one).
   6.263 +    */
   6.264 +   int32 argNum;
   6.265 +   for( argNum = 0; argNum < taskType->numCtldArgs; argNum++ )
   6.266 +    { 
   6.267 +      key[0] = 2; //two 32b values in key
   6.268 +      *( (uint64*)&key[1]) = (uint64)args[argNum];  //write 64b into two 32b
   6.269 +
   6.270 +      /*If the hash entry was chained, put it at the
   6.271 +       * start of the chain.  (Means no-longer-used pointers accumulate
   6.272 +       * at end of chain, decide garbage collection later) */
   6.273 +      rawHashEntry = getEntryFromTable32( key, argPtrHashTbl );
   6.274 +      if( rawHashEntry == NULL )
   6.275 +       {    //adding a value auto-creates the hash-entry
   6.276 +         ptrEntry = create_pointer_entry();
   6.277 +         rawHashEntry = addValueIntoTable32( key, ptrEntry, argPtrHashTbl );
   6.278 +       }
   6.279 +      else
   6.280 +       { ptrEntry = (VSsPointerEntry *)rawHashEntry->content;
   6.281 +         if( ptrEntry == NULL )
   6.282 +          { ptrEntry = create_pointer_entry();
   6.283 +            rawHashEntry = addValueIntoTable32(key, ptrEntry, argPtrHashTbl);
   6.284 +          }
   6.285 +       }
   6.286 +      taskStub->ptrEntries[argNum] = ptrEntry;
   6.287 +      
   6.288 +      /*Have the hash entry.
   6.289 +       *If the arg is a reader and the entry does not have an enabled
   6.290 +       * non-finished writer, and the queue is empty. */
   6.291 +      if( taskType->argTypes[argNum] == READER )
   6.292 +       { if( !ptrEntry->hasEnabledNonFinishedWriter && 
   6.293 +             isEmptyPrivQ( ptrEntry->waitersQ ) )
   6.294 +          { /*The reader is free.  So, decrement the blocking-propendent
   6.295 +             * count in the task-stub. If the count is zero, then put the
   6.296 +             * task-stub into the readyQ.  At the same time, increment
   6.297 +             * the hash-entry's count of enabled and non-finished readers.*/
   6.298 +            taskStub->numBlockingProp -= 1;
   6.299 +            if( taskStub->numBlockingProp == 0 )
   6.300 +             { writePrivQ( taskStub, semEnv->taskReadyQ );
   6.301 +             }
   6.302 +            ptrEntry->numEnabledNonDoneReaders += 1;
   6.303 +          }
   6.304 +         else
   6.305 +          { /*Otherwise, the reader is put into the hash-entry's Q of
   6.306 +             * waiters*/
   6.307 +            taskCarrier = create_task_carrier( taskStub, argNum, READER );
   6.308 +            writePrivQ( taskCarrier, ptrEntry->waitersQ );
   6.309 +          }
   6.310 +       }
   6.311 +      else //arg is a writer
   6.312 +       { /*the arg is a writer, plus the entry does not have a current
   6.313 +          * writer, plus the number of enabled non-finished readers is
   6.314 +          * zero, (the Q must be empty, else bug!) then the writer is free*/
   6.315 +         if( !ptrEntry->hasEnabledNonFinishedWriter &&
   6.316 +              ptrEntry->numEnabledNonDoneReaders == 0 )
   6.317 +          { /*Mark the entry has having a enabled and non-finished writer.
   6.318 +              * Decrement the blocking-propenden count in the writer's
   6.319 +              * task-stub. If the count is zero, then put the task-stub
   6.320 +              * into the readyQ.*/
   6.321 +            taskStub->numBlockingProp -= 1;
   6.322 +            if( taskStub->numBlockingProp == 0 )
   6.323 +             { writePrivQ( taskStub, semEnv->taskReadyQ );
   6.324 +             }
   6.325 +            ptrEntry->hasEnabledNonFinishedWriter = TRUE;
   6.326 +          }
   6.327 +         else
   6.328 +          {/*Otherwise, put the writer into the entry's Q of waiters.*/
   6.329 +            taskCarrier = create_task_carrier( taskStub, argNum, WRITER );
   6.330 +            writePrivQ( taskCarrier, ptrEntry->waitersQ );            
   6.331 +          }
   6.332 +       }
   6.333 +    } //for argNum
   6.334 +   
   6.335 +   
   6.336 +   resume_slaveVP( semReq->callingSlv, semEnv );
   6.337 +
   6.338 +   return;
   6.339 + }
   6.340 +
   6.341 +
   6.342 +/* ========================== end of task ===========================
   6.343 + * 
   6.344 + *At the end of a task,
   6.345 + *The task's controlled arguments are processed one by one.
   6.346 + *Processing an argument means getting the hash of the pointer.  Then,
   6.347 + * looking up the hash entry (and putting the entry at the start of the
   6.348 + * chain, if there was a chain).
   6.349 + *With the hash entry:
   6.350 + *
   6.351 + *If the arg is a reader, then decrement the enabled and non-finished
   6.352 + * reader-count in the hash-entry. If the count becomes zero, then take
   6.353 + * the next entry from the Q. It should be a writer, or else there's a
   6.354 + * bug in this algorithm.
   6.355 + *Set the hash-entry to have an enabled non-finished writer.  Decrement
   6.356 + * the blocking-propendent-count of the writer's task-stub.  If the count
   6.357 + * has reached zero, then put the task-stub into the readyQ.
   6.358 + * 
   6.359 + *If the arg is a writer, then clear the enabled non-finished writer flag
   6.360 + * of the hash-entry. Take the next entry from the waiters Q. 
   6.361 + *If it is a writer, then turn the flag back on.  Decrement the writer's
   6.362 + * blocking-propendent-count in its task-stub.  If it becomes zero, then
   6.363 + * put the task-stub into the readyQ.
   6.364 + *
   6.365 + *If waiter is a reader, then do a loop, getting all waiting readers.
   6.366 + * For each, increment the hash-entry's count of enabled
   6.367 + * non-finished readers.  Decrement the blocking propendents count of the
   6.368 + * reader's task-stub.  If it reaches zero, then put the task-stub into the
   6.369 + * readyQ.
   6.370 + *Repeat until encounter a writer -- put that writer back into the Q.
   6.371 + * 
   6.372 + *May 2012 -- not keeping track of how many references to a given ptrEntry
   6.373 + * exist, so no way to garbage collect..
   6.374 + *TODO: Might be safe to delete an entry when task ends and waiterQ empty
   6.375 + * and no readers and no writers..
   6.376 + */
   6.377 +inline void
   6.378 +handleEndTask( VSsSemReq *semReq, VSsSemEnv *semEnv )
   6.379 + { VSsPointerEntry  *ptrEntry; //contents of hash table entry for an arg pointer
   6.380 +   void            **args;
   6.381 +   VSsSemData       *endingSlvSemData;
   6.382 +   VSsTaskStub      *endingTaskStub, *waitingTaskStub, *parent;
   6.383 +   VSsTaskType      *endingTaskType;
   6.384 +   VSsTaskStubCarrier *waitingTaskCarrier;
   6.385 +   VSsPointerEntry **ptrEntries;
   6.386 +         
   6.387 + 
   6.388 +   endingSlvSemData = (VSsSemData *)semReq->callingSlv->semanticData;
   6.389 +   endingTaskStub   = endingSlvSemData->taskStub;
   6.390 +   args             = endingTaskStub->args;
   6.391 +   endingTaskType   = endingTaskStub->taskType;
   6.392 +   ptrEntries       = endingTaskStub->ptrEntries; //saved in stub when create
   6.393 +   
   6.394 +         DEBUG__printf2(dbgRqstHdlr,"EndTask req from slaveID: %d, task: %d",semReq->callingSlv->slaveID, endingTaskStub->taskID[1])
   6.395 +          
   6.396 +      //Check if parent was waiting on this task
   6.397 +   parent = (VSsTaskStub *) endingTaskStub->parentTaskStub;
   6.398 +   parent->numLiveChildTasks -= 1;
   6.399 +   if( parent->isWaitingForChildTasksToEnd && parent->numLiveChildTasks == 0)
   6.400 +    {
   6.401 +      parent->isWaitingForChildTasksToEnd = FALSE;
   6.402 +      resume_slaveVP( parent->slaveAssignedTo, semEnv );
   6.403 +    }
   6.404 +   
   6.405 +      //Check if parent ended, and this was last descendent, then free it
   6.406 +   if( parent->isEnded && parent->numLiveChildTasks == 0 )
   6.407 +    { VMS_PI__free( parent );
   6.408 +    }
   6.409 +   
   6.410 +   
   6.411 +      //Now, update state of dependents and start ready tasks
   6.412 +   /*The task's controlled arguments are processed one by one.
   6.413 +    *Processing an argument means getting arg-pointer's entry.
   6.414 +    */
   6.415 +   int32 argNum;
   6.416 +   for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ )
   6.417 +    { 
   6.418 +      /* commented out 'cause remembering entry ptr when create stub
   6.419 +      key[0] = 2; //says are 2 32b values in key
   6.420 +      *( (uint64*)&key[1] ) = args[argNum];  //write 64b ptr into two 32b
   6.421 +
   6.422 +       /*If the hash entry was chained, put it at the
   6.423 +       * start of the chain.  (Means no-longer-used pointers accumulate
   6.424 +       * at end of chain, decide garbage collection later) 
   6.425 +       */
   6.426 +      /*NOTE: don't do hash lookups here, instead, have a pointer to the
   6.427 +       * hash entry inside task-stub, put there during task creation.
   6.428 +      rawHashEntry = getEntryFromTable32( key, ptrHashTbl );
   6.429 +      ptrEntry = (VSsPointerEntry *)rawHashEntry->content;
   6.430 +      if( ptrEntry == NULL ) 
   6.431 +          VMS_App__throw_exception("hash entry NULL", NULL, NULL);
   6.432 +      */ 
   6.433 +      
   6.434 +      ptrEntry = ptrEntries[argNum];
   6.435 +      /*check if the ending task was reader of this arg*/
   6.436 +      if( endingTaskType->argTypes[argNum] == READER )
   6.437 +       { /*then decrement the enabled and non-finished reader-count in
   6.438 +          * the hash-entry. */ 
   6.439 +         ptrEntry->numEnabledNonDoneReaders -= 1;
   6.440 +         
   6.441 +         /*If the count becomes zero, then take the next entry from the Q. 
   6.442 +          *It should be a writer, or else there's a bug in this algorithm.*/
   6.443 +         if( ptrEntry->numEnabledNonDoneReaders == 0 )
   6.444 +          { waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ );
   6.445 +            if( waitingTaskCarrier == NULL ) 
   6.446 +             { //TODO: looks safe to delete the ptr entry at this point 
   6.447 +               continue; //next iter of loop
   6.448 +             }
   6.449 +            if( waitingTaskCarrier->isReader ) 
   6.450 +               VMS_App__throw_exception("READER waiting", NULL, NULL);
   6.451 +                   
   6.452 +            waitingTaskStub = waitingTaskCarrier->taskStub;
   6.453 +            
   6.454 +            /*Set the hash-entry to have an enabled non-finished writer.*/
   6.455 +            ptrEntry->hasEnabledNonFinishedWriter = TRUE;
   6.456 +            
   6.457 +            /* Decrement the blocking-propendent-count of the writer's
   6.458 +             * task-stub.  If the count has reached zero, then put the
   6.459 +             * task-stub into the readyQ.*/
   6.460 +            waitingTaskStub->numBlockingProp -= 1;
   6.461 +            if( waitingTaskStub->numBlockingProp == 0 )
   6.462 +             { writePrivQ( waitingTaskStub, semEnv->taskReadyQ );
   6.463 +             }
   6.464 +          }
   6.465 +       }
   6.466 +      else /*the ending task is a writer of this arg*/ 
   6.467 +       { /*clear the enabled non-finished writer flag of the hash-entry.*/
   6.468 +         ptrEntry->hasEnabledNonFinishedWriter = FALSE;
   6.469 +         
   6.470 +         /*Take the next waiter from the hash-entry's Q.*/
   6.471 +         waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ );
   6.472 +         if( waitingTaskCarrier == NULL )
   6.473 +          { //TODO: looks safe to delete ptr entry at this point
   6.474 +            continue; //go to next iter of loop, done here.
   6.475 +          }
   6.476 +         waitingTaskStub = waitingTaskCarrier->taskStub;
   6.477 +         
   6.478 +         /*If task is a writer of this hash-entry's pointer*/
   6.479 +         if( !waitingTaskCarrier->isReader ) 
   6.480 +          { /* then turn the flag back on.*/
   6.481 +            ptrEntry->hasEnabledNonFinishedWriter = TRUE;
   6.482 +            /*Decrement the writer's blocking-propendent-count in task-stub
   6.483 +             * If it becomes zero, then put the task-stub into the readyQ.*/
   6.484 +            waitingTaskStub->numBlockingProp -= 1;
   6.485 +            if( waitingTaskStub->numBlockingProp == 0 )
   6.486 +             { writePrivQ( waitingTaskStub, semEnv->taskReadyQ );
   6.487 +             }
   6.488 +          }
   6.489 +         else
   6.490 +          { /*Waiting task is a reader, so do a loop, of all waiting readers
   6.491 +             * until encounter a writer or waitersQ is empty*/
   6.492 +            while( TRUE ) /*The checks guarantee have a waiting reader*/
   6.493 +             { /*Increment the hash-entry's count of enabled non-finished
   6.494 +                * readers.*/
   6.495 +               ptrEntry->numEnabledNonDoneReaders += 1;
   6.496 +
   6.497 +               /*Decrement the blocking propendents count of the reader's
   6.498 +                * task-stub.  If it reaches zero, then put the task-stub
   6.499 +                * into the readyQ.*/
   6.500 +               waitingTaskStub->numBlockingProp -= 1;
   6.501 +               if( waitingTaskStub->numBlockingProp == 0 )
   6.502 +                { writePrivQ( waitingTaskStub, semEnv->taskReadyQ );
   6.503 +                }
   6.504 +               /*Get next waiting task*/
   6.505 +               waitingTaskCarrier = peekPrivQ( ptrEntry->waitersQ );
   6.506 +               if( waitingTaskCarrier == NULL ) break;
   6.507 +               if( !waitingTaskCarrier->isReader ) break;
   6.508 +               waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ );               
   6.509 +               waitingTaskStub = waitingTaskCarrier->taskStub;
   6.510 +             }//while waiter is a reader
   6.511 +          }//if-else, first waiting task is a reader
   6.512 +       }//if-else, check of ending task, whether writer or reader
   6.513 +    }//for argnum in ending task
   6.514 +   
   6.515 +   
   6.516 +      //done ending the task, now free the stub + args copy
   6.517 +      // if still has live children, then keep stub around
   6.518 +   if( endingTaskStub->numLiveChildTasks   == 0 &&
   6.519 +       endingTaskStub->numLiveChildThreads == 0 )
   6.520 +    { free_task_stub( endingTaskStub ); 
   6.521 +    }
   6.522 +   
   6.523 +   
   6.524 +   endingSlvSemData->needsTaskAssigned = TRUE;
   6.525 +   
   6.526 +      //Check if the slave is an extra task slave, and put into free Q
   6.527 +   if( endingSlvSemData->slaveType == ExtraTaskSlv )
   6.528 +    { writePrivQ( semReq->callingSlv, semEnv->freeExtraTaskSlvQ );
   6.529 +    }
   6.530 +   
   6.531 +      //otherwise, it's a slot slave, so it will get used from matrix
   6.532 +      // so, do nothing with it, just return
   6.533 +   return; 
   6.534 + }
   6.535 +
   6.536 +inline void
   6.537 +free_task_stub( VSsTaskStub *stubToFree )
   6.538 + { if(stubToFree->ptrEntries != NULL ) //a thread stub has NULL entry
   6.539 +    { VMS_PI__free( stubToFree->ptrEntries );
   6.540 +    }
   6.541 +   VMS_PI__free( stubToFree );
   6.542 + }
   6.543 +
   6.544 +//========================== Task Comm handlers ===========================
   6.545 +
   6.546 +
   6.547 +
   6.548 +//============================  Send Handlers ==============================
   6.549 +/*Send of Type -- The semantic request has the receiving task ID and Type
   6.550 + *
   6.551 + *Messages of a given Type have to be kept separate..  so need a separate
   6.552 + * entry in the hash table for each pair: receiverID, Type
   6.553 + *
   6.554 + *Also, if same sender sends multiple before any get received, then need to
   6.555 + * stack the sends up -- even if a send waits until it's paired, several
   6.556 + * separate tasks can send to the same receiver, and doing hash on the
   6.557 + * receive task, so they will stack up.
   6.558 + */
   6.559 +inline void
   6.560 +handleSendTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv )
   6.561 + { SlaveVP    *senderSlv, *receiverSlv;
   6.562 +   int32      *senderID, *receiverID;
   6.563 +   int32      *key, keySz, receiverIDNumInt;
   6.564 +   VSsSemReq  *waitingReq;
   6.565 +   HashEntry  *entry;
   6.566 +   HashTable  *commHashTbl = semEnv->commHashTbl;
   6.567 +   
   6.568 +   receiverID  = semReq->receiverID; //For "send", know both send & recv procrs
   6.569 +   senderSlv   = semReq->senderSlv;
   6.570 +
   6.571 +         DEBUG__printf2(dbgRqstHdlr,"SendType req from sender slaveID: %d, recTask: %d", senderSlv->slaveID, receiverID[1])
   6.572 +          
   6.573 +      //suspending a task always makes the slave into an extra slot slave,
   6.574 +      // because it ends up in the resumeQ, even when resumes immediately.
   6.575 +      //Eventually task_end will put the slave into the freeExtraTaskSlvQ
   6.576 +   replaceWithNewSlotSlvIfNeeded( senderSlv, semEnv );
   6.577 +         
   6.578 +   receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself
   6.579 +   keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32);
   6.580 +   key = VMS_PI__malloc( keySz );
   6.581 +   key[0] = receiverIDNumInt + 1; //loc 0 is num int32 in key
   6.582 +   memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) );
   6.583 +   key[ 1 + receiverIDNumInt ] = semReq->msgType; 
   6.584 +   
   6.585 +   entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );
   6.586 +   if( entry == NULL ) //was just inserted, means task has to wait
   6.587 +    { return;
   6.588 +    }
   6.589 +
   6.590 +      //if here, found a waiting request with same key
   6.591 +   waitingReq = (VSsSemReq *)entry->content;
   6.592 +
   6.593 +      //At this point, know have waiting request(s) -- either sends or recv
   6.594 +      //Note, can only have max of one receive waiting, and cannot have both
   6.595 +      // sends and receives waiting (they would have paired off)
   6.596 +      // but can have multiple sends from diff sending VPs, all same msg-type
   6.597 +   if( waitingReq->reqType == send_type_to )
   6.598 +    {    //waiting request is another send, so stack this up on list
   6.599 +         // but first clone the sending request so it persists.
   6.600 +      VSsSemReq *clonedReq = cloneReq( semReq );
   6.601 +      clonedReq-> nextReqInHashEntry = waitingReq->nextReqInHashEntry;
   6.602 +      waitingReq->nextReqInHashEntry = clonedReq;
   6.603 +         DEBUG__printf2( dbgRqstHdlr, "linked requests: %p, %p ", clonedReq,\
   6.604 +                                                                 waitingReq )
   6.605 +      return;
   6.606 +    }
   6.607 +   else
   6.608 +    {    
   6.609 +       #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   6.610 +        Dependency newd;
   6.611 +        newd.from_vp = senderID->slaveID;
   6.612 +        newd.from_task = senderID->assignCount;
   6.613 +        newd.to_vp = receiverID->slaveID;
   6.614 +        newd.to_task = receiverID->assignCount +1;
   6.615 +        //(newd,semEnv->commDependenciesList);  
   6.616 +        addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList);  
   6.617 +                int32 groupId = semReq->msgType;
   6.618 +        if(semEnv->ntonGroupsInfo->numInArray <= groupId){
   6.619 +            makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId);
   6.620 +        }
   6.621 +        if(semEnv->ntonGroups[groupId] == NULL){
   6.622 +            semEnv->ntonGroups[groupId] = new_NtoN(groupId);
   6.623 +        }
   6.624 +        Unit u;
   6.625 +        u.vp = senderID->slaveID;
   6.626 +        u.task = senderID->assignCount;
   6.627 +        addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders);
   6.628 +        u.vp = receiverID->slaveID;
   6.629 +        u.task = receiverID->assignCount +1;
   6.630 +        addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers);
   6.631 +       #endif
   6.632 +
   6.633 +         //set receiver slave, from the waiting request
   6.634 +      receiverSlv = waitingReq->receiverSlv;
   6.635 +      
   6.636 +         //waiting request is a receive_type_to, so it pairs to this send
   6.637 +         //First, remove the waiting receive request from the entry
   6.638 +      entry->content = waitingReq->nextReqInHashEntry;
   6.639 +      VMS_PI__free( waitingReq ); //Don't use contents -- so free it
   6.640 +      
   6.641 +      if( entry->content == NULL )
   6.642 +       {    //TODO: mod hash table to double-link, so can delete entry from
   6.643 +            // table without hashing the key and looking it up again
   6.644 +         deleteEntryFromTable32( (uint32*)entry->key, commHashTbl );  //frees hashEntry
   6.645 +       }
   6.646 +      
   6.647 +         //attach msg that's in this send request to receiving task's Slv
   6.648 +         // when comes back from suspend will have msg in dataRetFromReq
   6.649 +      receiverSlv->dataRetFromReq = semReq->msg;
   6.650 +
   6.651 +         //bring both processors back from suspend
   6.652 +      resume_slaveVP( senderSlv,   semEnv );
   6.653 +      resume_slaveVP( receiverSlv, semEnv );
   6.654 +
   6.655 +      return;
   6.656 +    }
   6.657 + }
   6.658 +
   6.659 +
   6.660 +/*Looks like can make single handler for both sends..
   6.661 + */
   6.662 +//TODO: combine both send handlers into single handler
   6.663 +inline void
   6.664 +handleSendFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv)
   6.665 + { SlaveVP     *senderSlv, *receiverSlv;
   6.666 +   int32       *senderID, *receiverID;
   6.667 +   int32       *key, keySz, receiverIDNumInt, senderIDNumInt;
   6.668 +   VSsSemReq   *waitingReq;
   6.669 +   HashEntry   *entry;
   6.670 +   HashTable   *commHashTbl = semEnv->commHashTbl;
   6.671 +
   6.672 +         DEBUG__printf2(dbgRqstHdlr,"SendFromTo req from task %d to %d",
   6.673 +                        semReq->senderID[1],semReq->receiverID[1])
   6.674 +   
   6.675 +   receiverID  = semReq->receiverID; //For "send", know both send & recv procrs
   6.676 +   senderID    = semReq->senderID;
   6.677 +   senderSlv   = semReq->senderSlv;
   6.678 +
   6.679 +      //suspending a task always makes the slave into an extra slot slave,
   6.680 +      // because it ends up in the resumeQ, even when resumes immediately.
   6.681 +      //Eventually task_end will put the slave into the freeExtraTaskSlvQ
   6.682 +   replaceWithNewSlotSlvIfNeeded( senderSlv, semEnv );
   6.683 +   
   6.684 +   receiverIDNumInt = receiverID[0] + 1; //include the count in the key
   6.685 +   senderIDNumInt   = senderID[0] + 1;
   6.686 +   keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32);
   6.687 +   key   = VMS_PI__malloc( keySz );
   6.688 +   key[0] = receiverIDNumInt + senderIDNumInt;
   6.689 +   memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) );
   6.690 +   memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) );
   6.691 +
   6.692 +   entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );
   6.693 +   if( entry == NULL ) //was just inserted, means task has to wait
   6.694 +    { return;
   6.695 +    }
   6.696 +
   6.697 +   waitingReq = (VSsSemReq *)entry->content;
   6.698 +
   6.699 +      //At this point, know have waiting request(s) -- either sends or recv
   6.700 +   if( waitingReq->reqType == send_from_to )
   6.701 +    { printf("\n ERROR: shouldn't be two send-from-tos waiting \n");
   6.702 +    }
   6.703 +   else
   6.704 +    {    //waiting request is a receive, so it completes pair with this send
   6.705 +      #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   6.706 +        Dependency newd;
   6.707 +        newd.from_vp = sendPr->slaveID;
   6.708 +        newd.from_task = sendPr->assignCount;
   6.709 +        newd.to_vp = receivePr->slaveID;
   6.710 +        newd.to_task = receivePr->assignCount +1;
   6.711 +        //addToListOfArraysDependency(newd,semEnv->commDependenciesList);  
   6.712 +        addToListOfArrays(Dependency,newd,semEnv->commDependenciesList);   
   6.713 +      #endif 
   6.714 +
   6.715 +         //set receiver slave, from the waiting request
   6.716 +      receiverSlv = waitingReq->receiverSlv;
   6.717 +       
   6.718 +         //First, remove the waiting receive request from the entry
   6.719 +      entry->content = waitingReq->nextReqInHashEntry;
   6.720 +      VMS_PI__free( waitingReq ); //Don't use contents -- so free it
   6.721 +      
   6.722 +         //can only be one waiting req for "from-to" semantics
   6.723 +      if( entry->content != NULL )
   6.724 +       {
   6.725 +         printf("\nERROR in handleSendFromTo\n");
   6.726 +       }
   6.727 +      deleteEntryFromTable32( (uint32*)entry->key, commHashTbl );  //frees HashEntry
   6.728 +
   6.729 +         //attach msg that's in this send request to receiving procr
   6.730 +         // when comes back from suspend, will have msg in dataRetFromReq
   6.731 +      receiverSlv->dataRetFromReq = semReq->msg;
   6.732 +
   6.733 +         //bring both processors back from suspend
   6.734 +      resume_slaveVP( senderSlv,   semEnv );
   6.735 +      resume_slaveVP( receiverSlv, semEnv );
   6.736 +            
   6.737 +      return;
   6.738 +    }
   6.739 + }
   6.740 +
   6.741 +
   6.742 +
   6.743 +//==============================  Receives  ===========================
   6.744 +//
   6.745 +
   6.746 +
   6.747 +inline void
   6.748 +handleReceiveTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv)
   6.749 + { SlaveVP    *senderSlv, *receiverSlv;
   6.750 +   int32      *receiverID;
   6.751 +   int32      *key, keySz, receiverIDNumInt;
   6.752 +   VSsSemReq  *waitingReq;
   6.753 +   HashEntry  *entry;
   6.754 +   HashTable  *commHashTbl = semEnv->commHashTbl;
   6.755 +   
   6.756 +         DEBUG__printf2(dbgRqstHdlr,"ReceiveType req to ID: %d type: %d",semReq->receiverID[1], semReq->msgType)
   6.757 + 
   6.758 +   receiverID  = semReq->receiverID; //For "send", know both send & recv procrs
   6.759 +   receiverSlv = semReq->receiverSlv;
   6.760 +   
   6.761 +      //suspending a task always makes the slave into an extra slot slave,
   6.762 +      // because it ends up in the resumeQ, even when resumes immediately.
   6.763 +      //Eventually task_end will put the slave into the freeExtraTaskSlvQ
   6.764 +   replaceWithNewSlotSlvIfNeeded( receiverSlv, semEnv );
   6.765 +
   6.766 +      //key is the receiverID plus the type -- have to copy them into key
   6.767 +   receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself
   6.768 +   keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32);
   6.769 +   key = VMS_PI__malloc( keySz );
   6.770 +   key[0] = receiverIDNumInt + 1; //loc 0 is num int32s in key
   6.771 +   memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) );
   6.772 +   key[ 1 + receiverIDNumInt ] = semReq->msgType; 
   6.773 +
   6.774 +   entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );//clones
   6.775 +   if( entry == NULL ) //was just inserted, means task has to wait
   6.776 +    { return;
   6.777 +    }
   6.778 +
   6.779 +   waitingReq = (VSsSemReq *)entry->content;  //previously cloned by insert
   6.780 +
   6.781 +      //At this point, know have waiting request(s) -- should be send(s)
   6.782 +   if( waitingReq->reqType == send_type_to )
   6.783 +    {    
   6.784 +         //set sending slave  from the request
   6.785 +      senderSlv = waitingReq->senderSlv;
   6.786 +      
   6.787 +         //waiting request is a send, so pair it with this receive
   6.788 +         //first, remove the waiting send request from the list in entry
   6.789 +      entry->content = waitingReq->nextReqInHashEntry;
   6.790 +      if( entry->content == NULL )
   6.791 +       { deleteEntryFromTable32( (uint32*)entry->key, commHashTbl );  //frees HashEntry
   6.792 +       }
   6.793 +      
   6.794 +         //attach msg that's in the send request to receiving procr
   6.795 +         // when comes back from suspend, will have msg in dataRetFromReq
   6.796 +      receiverSlv->dataRetFromReq = waitingReq->msg;
   6.797 +
   6.798 +         //bring both processors back from suspend
   6.799 +      VMS_PI__free( waitingReq );
   6.800 +
   6.801 +       #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   6.802 +        Dependency newd;
   6.803 +        newd.from_vp = sendPr->slaveID;
   6.804 +        newd.from_task = sendPr->assignCount;
   6.805 +        newd.to_vp = receivePr->slaveID;
   6.806 +        newd.to_task = receivePr->assignCount +1;
   6.807 +        //addToListOfArraysDependency(newd,semEnv->commDependenciesList);  
   6.808 +        addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); 
   6.809 +        int32 groupId = semReq->msgType;
   6.810 +        if(semEnv->ntonGroupsInfo->numInArray <= groupId){
   6.811 +            makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId);
   6.812 +        }
   6.813 +        if(semEnv->ntonGroups[groupId] == NULL){
   6.814 +            semEnv->ntonGroups[groupId] = new_NtoN(groupId);
   6.815 +        }
   6.816 +        Unit u;
   6.817 +        u.vp = sendPr->slaveID;
   6.818 +        u.task = sendPr->assignCount;
   6.819 +        addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders);
   6.820 +        u.vp = receivePr->slaveID;
   6.821 +        u.task = receivePr->assignCount +1;
   6.822 +        addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers);
   6.823 +       #endif
   6.824 +      
   6.825 +      resume_slaveVP( senderSlv,   semEnv );
   6.826 +      resume_slaveVP( receiverSlv, semEnv );
   6.827 +
   6.828 +      return;
   6.829 +    }
   6.830 +   printf("\nLang Impl Error: Should never be two waiting receives!\n");
   6.831 + }
   6.832 +
   6.833 +
   6.834 +/*
   6.835 + */
   6.836 +inline void
   6.837 +handleReceiveFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv)
   6.838 + { SlaveVP     *senderSlv, *receiverSlv;
   6.839 +   int32       *senderID,  *receiverID;
   6.840 +   int32       *key, keySz, receiverIDNumInt, senderIDNumInt;
   6.841 +   VSsSemReq   *waitingReq;
   6.842 +   HashEntry   *entry;
   6.843 +   HashTable   *commHashTbl = semEnv->commHashTbl;
   6.844 +
   6.845 +         DEBUG__printf2(dbgRqstHdlr,"RecFromTo req from ID: %d to ID: %d",semReq->senderID[1],semReq->receiverID[1])
   6.846 +   
   6.847 +   receiverID  = semReq->receiverID; //For "send", know both send & recv procrs
   6.848 +   senderID    = semReq->senderID;
   6.849 +   receiverSlv = semReq->receiverSlv;
   6.850 +   
   6.851 +      //suspending a task always makes the slave into an extra slot slave,
   6.852 +      // because it ends up in the resumeQ, even when resumes immediately.
   6.853 +      //Eventually task_end will put the slave into the freeExtraTaskSlvQ
   6.854 +   replaceWithNewSlotSlvIfNeeded( receiverSlv, semEnv );
   6.855 +
   6.856 +   receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself
   6.857 +   senderIDNumInt   = senderID[0] + 1;
   6.858 +   keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32);
   6.859 +   key = VMS_PI__malloc( keySz );
   6.860 +   key[0] = receiverIDNumInt + senderIDNumInt; //loc 0 is num int32s in key
   6.861 +   memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) );
   6.862 +   memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32));
   6.863 +
   6.864 +   entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );
   6.865 +   if( entry == NULL ) //was just inserted, means task has to wait
   6.866 +    { return;
   6.867 +    }
   6.868 +
   6.869 +   waitingReq = (VSsSemReq *)entry->content;
   6.870 +
   6.871 +      //At this point, know have a request to rendez-vous -- should be send
   6.872 +   if( waitingReq->reqType == send_from_to )
   6.873 +    {    //waiting request is a send, so pair it with this receive
   6.874 +      #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   6.875 +        Dependency newd;
   6.876 +        newd.from_vp = sendPr->slaveID;
   6.877 +        newd.from_task = sendPr->assignCount;
   6.878 +        newd.to_vp = receivePr->slaveID;
   6.879 +        newd.to_task = receivePr->assignCount +1;
   6.880 +        //addToListOfArraysDependency(newd,semEnv->commDependenciesList);  
   6.881 +        addToListOfArrays(Dependency,newd,semEnv->commDependenciesList);    
   6.882 +      #endif
   6.883 +      
   6.884 +         //have receiver slave, now set sender slave
   6.885 +      senderSlv = waitingReq->senderSlv;
   6.886 +      
   6.887 +         //For from-to, should only ever be a single reqst waiting tobe paird
   6.888 +      entry->content = waitingReq->nextReqInHashEntry;
   6.889 +      if( entry->content != NULL ) printf("\nERROR in handleRecvFromTo\n");
   6.890 +      deleteEntryFromTable32( (uint32*)entry->key, commHashTbl );  //frees entry too
   6.891 +
   6.892 +         //attach msg that's in the send request to receiving procr
   6.893 +         // when comes back from suspend, will have msg in dataRetFromReq
   6.894 +      receiverSlv->dataRetFromReq = waitingReq->msg;
   6.895 +
   6.896 +         //bring both processors back from suspend
   6.897 +      VMS_PI__free( waitingReq );
   6.898 +
   6.899 +      resume_slaveVP( senderSlv,   semEnv );
   6.900 +      resume_slaveVP( receiverSlv, semEnv );
   6.901 +
   6.902 +      return;
   6.903 +    }
   6.904 +   printf("\nLang Impl Error: Should never be two waiting receives!\n");
   6.905 + }
   6.906 +
   6.907 +//==========================================================================
   6.908 +inline void
   6.909 +replaceWithNewSlotSlvIfNeeded( SlaveVP *requestingSlv, VSsSemEnv *semEnv )
   6.910 + { SlaveVP *newSlotSlv;
   6.911 +   VSsSemData *semData, *reqSemData;
   6.912 +
   6.913 +   reqSemData = (VSsSemData *)requestingSlv->semanticData;
   6.914 +   if( reqSemData->slaveType != SlotTaskSlv )
   6.915 +      return; //already replaced, so just return
   6.916 +   
   6.917 +      //get a new slave to be the slot slave
   6.918 +   newSlotSlv     = readPrivQ( semEnv->freeExtraTaskSlvQ );
   6.919 +   if( newSlotSlv == NULL )
   6.920 +    { newSlotSlv  = VSs__create_slave_helper( &idle_fn, NULL, semEnv, 0);
   6.921 +         //just made a new extra task slave, so count it
   6.922 +      semEnv->numLiveExtraTaskSlvs += 1;
   6.923 +    }
   6.924 +   
   6.925 +      //set slave values to make it the slot slave
   6.926 +   semData                        = newSlotSlv->semanticData;
   6.927 +   semData->taskStub              = NULL;
   6.928 +   semData->slaveType             = SlotTaskSlv;
   6.929 +   semData->needsTaskAssigned     = TRUE;
   6.930 +   
   6.931 +      //a slot slave is pinned to a particular slot on a particular core
   6.932 +   newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo;
   6.933 +   newSlotSlv->coreAnimatedBy     = requestingSlv->coreAnimatedBy;
   6.934 +    
   6.935 +      //put it into the slot slave matrix
   6.936 +   int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx;
   6.937 +   int32 coreNum = requestingSlv->coreAnimatedBy;
   6.938 +   semEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv;
   6.939 +
   6.940 +      //Fix up requester, to be an extra slave now (but not a free one)
   6.941 +      // because it's not free, doesn't go into freeExtraTaskSlvQ
   6.942 +   semData = requestingSlv->semanticData;
   6.943 +   semData->slaveType = ExtraTaskSlv;
   6.944 + }
   6.945 +
   6.946 +inline void
   6.947 +handleTaskwait( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv)
   6.948 + { VSsTaskStub* requestingTaskStub;
   6.949 +   VSsSemData* semData;
   6.950 +         DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d",
   6.951 +                                                      requestingSlv->slaveID)
   6.952 +    
   6.953 +   semData = (VSsSemData *)semReq->callingSlv->semanticData;
   6.954 +   requestingTaskStub = semData->taskStub;
   6.955 +   
   6.956 +   if( semData->taskStub->numLiveChildTasks == 0 )
   6.957 +    {    //nobody to wait for, resume
   6.958 +      resume_slaveVP( requestingSlv, semEnv );
   6.959 +    }
   6.960 +   else  //have to wait, replace requester with new slot slv & mark waiting
   6.961 +    { 
   6.962 +       if(semData->slaveType == SlotTaskSlv){
   6.963 +         replaceWithNewSlotSlvIfNeeded( requestingSlv, semEnv );
   6.964 +       }
   6.965 +       
   6.966 +      requestingTaskStub->isWaitingForChildTasksToEnd = TRUE;
   6.967 +    }    
   6.968 + }
   6.969 +
   6.970 +
   6.971 +//==========================================================================
   6.972 +/*
   6.973 + */
   6.974 +void
   6.975 +handleMalloc( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv )
   6.976 + { void *ptr;
   6.977 + 
   6.978 +      DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveID)
   6.979 +
   6.980 +   ptr = VMS_PI__malloc( semReq->sizeToMalloc );
   6.981 +   requestingSlv->dataRetFromReq = ptr;
   6.982 +   resume_slaveVP( requestingSlv, semEnv );
   6.983 + }
   6.984 +
   6.985 +/*
   6.986 + */
   6.987 +void
   6.988 +handleFree( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv )
   6.989 + {
   6.990 +         DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveID)
   6.991 +   VMS_PI__free( semReq->ptrToFree );
   6.992 +   resume_slaveVP( requestingSlv, semEnv );
   6.993 + }
   6.994 +
   6.995 +
   6.996 +//===========================================================================
   6.997 +//
   6.998 +/*Uses ID as index into array of flags.  If flag already set, resumes from
   6.999 + * end-label.  Else, sets flag and resumes normally.
  6.1000 + */
  6.1001 +void inline
  6.1002 +handleStartSingleton_helper( VSsSingleton *singleton, SlaveVP *reqstingSlv,
  6.1003 +                             VSsSemEnv    *semEnv )
  6.1004 + {
  6.1005 +   if( singleton->hasFinished )
  6.1006 +    {    //the code that sets the flag to true first sets the end instr addr
  6.1007 +      reqstingSlv->dataRetFromReq = singleton->endInstrAddr;
  6.1008 +      resume_slaveVP( reqstingSlv, semEnv );
  6.1009 +      return;
  6.1010 +    }
  6.1011 +   else if( singleton->hasBeenStarted )
  6.1012 +    {    //singleton is in-progress in a diff slave, so wait for it to finish
  6.1013 +      writePrivQ(reqstingSlv, singleton->waitQ );
  6.1014 +      return;
  6.1015 +    }
  6.1016 +   else
  6.1017 +    {    //hasn't been started, so this is the first attempt at the singleton
  6.1018 +      singleton->hasBeenStarted = TRUE;
  6.1019 +      reqstingSlv->dataRetFromReq = 0x0;
  6.1020 +      resume_slaveVP( reqstingSlv, semEnv );
  6.1021 +      return;
  6.1022 +    }
  6.1023 + }
  6.1024 +void inline
  6.1025 +handleStartFnSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv,
  6.1026 +                      VSsSemEnv *semEnv )
  6.1027 + { VSsSingleton *singleton;
  6.1028 +         DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingSlv->slaveID)
  6.1029 +
  6.1030 +   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
  6.1031 +   handleStartSingleton_helper( singleton, requestingSlv, semEnv );
  6.1032 + }
  6.1033 +void inline
  6.1034 +handleStartDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv,
  6.1035 +                      VSsSemEnv *semEnv )
  6.1036 + { VSsSingleton *singleton;
  6.1037 +
  6.1038 +         DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveID)
  6.1039 +   if( *(semReq->singletonPtrAddr) == NULL )
  6.1040 +    { singleton                 = VMS_PI__malloc( sizeof(VSsSingleton) );
  6.1041 +      singleton->waitQ          = makeVMSQ();
  6.1042 +      singleton->endInstrAddr   = 0x0;
  6.1043 +      singleton->hasBeenStarted = FALSE;
  6.1044 +      singleton->hasFinished    = FALSE;
  6.1045 +      *(semReq->singletonPtrAddr)  = singleton;
  6.1046 +    }
  6.1047 +   else
  6.1048 +      singleton = *(semReq->singletonPtrAddr);
  6.1049 +   handleStartSingleton_helper( singleton, requestingSlv, semEnv );
  6.1050 + }
  6.1051 +
  6.1052 +
  6.1053 +void inline
  6.1054 +handleEndSingleton_helper( VSsSingleton *singleton, SlaveVP *requestingSlv,
  6.1055 +                           VSsSemEnv    *semEnv )
  6.1056 + { PrivQueueStruc *waitQ;
  6.1057 +   int32           numWaiting, i;
  6.1058 +   SlaveVP      *resumingSlv;
  6.1059 +
  6.1060 +   if( singleton->hasFinished )
  6.1061 +    { //by definition, only one slave should ever be able to run end singleton
  6.1062 +      // so if this is true, is an error
  6.1063 +      ERROR1( "singleton code ran twice", requestingSlv );
  6.1064 +    }
  6.1065 +
  6.1066 +   singleton->hasFinished = TRUE;
  6.1067 +   waitQ = singleton->waitQ;
  6.1068 +   numWaiting = numInPrivQ( waitQ );
  6.1069 +   for( i = 0; i < numWaiting; i++ )
  6.1070 +    {    //they will resume inside start singleton, then jmp to end singleton
  6.1071 +      resumingSlv = readPrivQ( waitQ );
  6.1072 +      resumingSlv->dataRetFromReq = singleton->endInstrAddr;
  6.1073 +      resume_slaveVP( resumingSlv, semEnv );
  6.1074 +    }
  6.1075 +
  6.1076 +   resume_slaveVP( requestingSlv, semEnv );
  6.1077 +
  6.1078 +}
  6.1079 +void inline
  6.1080 +handleEndFnSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv,
  6.1081 +                        VSsSemEnv *semEnv )
  6.1082 + {
  6.1083 +   VSsSingleton   *singleton;
  6.1084 +
  6.1085 +         DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingSlv->slaveID)
  6.1086 +   
  6.1087 +   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
  6.1088 +   handleEndSingleton_helper( singleton, requestingSlv, semEnv );
  6.1089 +  }
  6.1090 +void inline
  6.1091 +handleEndDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv,
  6.1092 +                        VSsSemEnv *semEnv )
  6.1093 + {
  6.1094 +   VSsSingleton   *singleton;
  6.1095 +
  6.1096 +         DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingSlv->slaveID)
  6.1097 +   
  6.1098 +   singleton = *(semReq->singletonPtrAddr);
  6.1099 +   handleEndSingleton_helper( singleton, requestingSlv, semEnv );
  6.1100 +  }
  6.1101 +
  6.1102 +
  6.1103 +/*This executes the function in the masterVP, take the function
  6.1104 + * pointer out of the request and call it, then resume the VP.
  6.1105 + */
  6.1106 +void
  6.1107 +handleAtomic( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv )
  6.1108 + {
  6.1109 +         DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingSlv->slaveID)
  6.1110 +   semReq->fnToExecInMaster( semReq->dataForFn );
  6.1111 +   resume_slaveVP( requestingSlv, semEnv );
  6.1112 + }
  6.1113 +
  6.1114 +/*First, it looks at the VP's semantic data, to see the highest transactionID
  6.1115 + * that VP
  6.1116 + * already has entered.  If the current ID is not larger, it throws an
  6.1117 + * exception stating a bug in the code.
  6.1118 + *Otherwise it puts the current ID
  6.1119 + * there, and adds the ID to a linked list of IDs entered -- the list is
  6.1120 + * used to check that exits are properly ordered.
  6.1121 + *Next it is uses transactionID as index into an array of transaction
  6.1122 + * structures.
  6.1123 + *If the "VP_currently_executing" field is non-null, then put requesting VP
  6.1124 + * into queue in the struct.  (At some point a holder will request
  6.1125 + * end-transaction, which will take this VP from the queue and resume it.)
  6.1126 + *If NULL, then write requesting into the field and resume.
  6.1127 + */
  6.1128 +void
  6.1129 +handleTransStart( VSsSemReq *semReq, SlaveVP *requestingSlv,
  6.1130 +                  VSsSemEnv *semEnv )
  6.1131 + { VSsSemData *semData;
  6.1132 +   TransListElem *nextTransElem;
  6.1133 +
  6.1134 +         DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingSlv->slaveID)
  6.1135 +   
  6.1136 +      //check ordering of entering transactions is correct
  6.1137 +   semData = requestingSlv->semanticData;
  6.1138 +   if( semData->highestTransEntered > semReq->transID )
  6.1139 +    {    //throw VMS exception, which shuts down VMS.
  6.1140 +      VMS_PI__throw_exception( "transID smaller than prev", requestingSlv, NULL);
  6.1141 +    }
  6.1142 +      //add this trans ID to the list of transactions entered -- check when
  6.1143 +      // end a transaction
  6.1144 +   semData->highestTransEntered = semReq->transID;
  6.1145 +   nextTransElem = VMS_PI__malloc( sizeof(TransListElem) );
  6.1146 +   nextTransElem->transID = semReq->transID;
  6.1147 +   nextTransElem->nextTrans = semData->lastTransEntered;
  6.1148 +   semData->lastTransEntered = nextTransElem;
  6.1149 +
  6.1150 +      //get the structure for this transaction ID
  6.1151 +   VSsTrans *
  6.1152 +   transStruc = &(semEnv->transactionStrucs[ semReq->transID ]);
  6.1153 +
  6.1154 +   if( transStruc->VPCurrentlyExecuting == NULL )
  6.1155 +    {
  6.1156 +      transStruc->VPCurrentlyExecuting = requestingSlv;
  6.1157 +      resume_slaveVP( requestingSlv, semEnv );
  6.1158 +    }
  6.1159 +   else
  6.1160 +    {    //note, might make future things cleaner if save request with VP and
  6.1161 +         // add this trans ID to the linked list when gets out of queue.
  6.1162 +         // but don't need for now, and lazy..
  6.1163 +      writePrivQ( requestingSlv, transStruc->waitingVPQ );
  6.1164 +    }
  6.1165 + }
  6.1166 +
  6.1167 +
  6.1168 +/*Use the trans ID to get the transaction structure from the array.
  6.1169 + *Look at VP_currently_executing to be sure it's same as requesting VP.
  6.1170 + * If different, throw an exception, stating there's a bug in the code.
  6.1171 + *Next, take the first element off the list of entered transactions.
  6.1172 + * Check to be sure the ending transaction is the same ID as the next on
  6.1173 + * the list.  If not, incorrectly nested so throw an exception.
  6.1174 + *
  6.1175 + *Next, get from the queue in the structure.
  6.1176 + *If it's empty, set VP_currently_executing field to NULL and resume
  6.1177 + * requesting VP.
  6.1178 + *If get somethine, set VP_currently_executing to the VP from the queue, then
  6.1179 + * resume both.
  6.1180 + */
  6.1181 +void
  6.1182 +handleTransEnd(VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv)
  6.1183 + { VSsSemData    *semData;
  6.1184 +   SlaveVP     *waitingSlv;
  6.1185 +   VSsTrans      *transStruc;
  6.1186 +   TransListElem *lastTrans;
  6.1187 +   
  6.1188 +         DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingSlv->slaveID)
  6.1189 +   
  6.1190 +   transStruc = &(semEnv->transactionStrucs[ semReq->transID ]);
  6.1191 +
  6.1192 +      //make sure transaction ended in same VP as started it.
  6.1193 +   if( transStruc->VPCurrentlyExecuting != requestingSlv )
  6.1194 +    {
  6.1195 +      VMS_PI__throw_exception( "trans ended in diff VP", requestingSlv, NULL );
  6.1196 +    }
  6.1197 +
  6.1198 +      //make sure nesting is correct -- last ID entered should == this ID
  6.1199 +   semData = requestingSlv->semanticData;
  6.1200 +   lastTrans = semData->lastTransEntered;
  6.1201 +   if( lastTrans->transID != semReq->transID )
  6.1202 +    {
  6.1203 +      VMS_PI__throw_exception( "trans incorrectly nested", requestingSlv, NULL );
  6.1204 +    }
  6.1205 +
  6.1206 +   semData->lastTransEntered = semData->lastTransEntered->nextTrans;
  6.1207 +
  6.1208 +
  6.1209 +   waitingSlv = readPrivQ( transStruc->waitingVPQ );
  6.1210 +   transStruc->VPCurrentlyExecuting = waitingSlv;
  6.1211 +
  6.1212 +   if( waitingSlv != NULL )
  6.1213 +      resume_slaveVP( waitingSlv, semEnv );
  6.1214 +
  6.1215 +   resume_slaveVP( requestingSlv, semEnv );
  6.1216 + }
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/DKU_Request_Handlers.h	Mon Aug 27 02:14:35 2012 -0700
     7.3 @@ -0,0 +1,62 @@
     7.4 +/*
     7.5 + *  Copyright 2009 OpenSourceStewardshipFoundation.org
     7.6 + *  Licensed under GNU General Public License version 2
     7.7 + *
     7.8 + * Author: seanhalle@yahoo.com
     7.9 + *
    7.10 + */
    7.11 +
    7.12 +#ifndef _VSs_REQ_H
    7.13 +#define	_VSs_REQ_H
    7.14 +
    7.15 +#include "VSs.h"
    7.16 +
    7.17 +/*This header defines everything specific to the VSs semantic plug-in
    7.18 + */
    7.19 +
    7.20 +inline void
    7.21 +handleSubmitTask( VSsSemReq *semReq, VSsSemEnv *semEnv);
    7.22 +inline void
    7.23 +handleEndTask( VSsSemReq *semReq, VSsSemEnv *semEnv);
    7.24 +inline void
    7.25 +handleSendTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv);
    7.26 +inline void
    7.27 +handleSendFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv);
    7.28 +inline void
    7.29 +handleReceiveTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv);
    7.30 +inline void
    7.31 +handleReceiveFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv);
    7.32 +inline void
    7.33 +handleTaskwait(VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv);
    7.34 +
    7.35 +inline void
    7.36 +handleMalloc( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv);
    7.37 +inline void
    7.38 +handleFree( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv );
    7.39 +inline void
    7.40 +handleTransEnd(VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv*semEnv);
    7.41 +inline void
    7.42 +handleTransStart( VSsSemReq *semReq, SlaveVP *requestingSlv,
    7.43 +                  VSsSemEnv *semEnv );
    7.44 +inline void
    7.45 +handleAtomic( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv);
    7.46 +inline void
    7.47 +handleStartFnSingleton( VSsSemReq *semReq, SlaveVP *reqstingSlv,
    7.48 +                      VSsSemEnv *semEnv );
    7.49 +inline void
    7.50 +handleEndFnSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv,
    7.51 +                    VSsSemEnv *semEnv );
    7.52 +inline void
    7.53 +handleStartDataSingleton( VSsSemReq *semReq, SlaveVP *reqstingSlv,
    7.54 +                      VSsSemEnv *semEnv );
    7.55 +inline void
    7.56 +handleEndDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv,
    7.57 +                    VSsSemEnv *semEnv );
    7.58 +inline void
    7.59 +free_task_stub( VSsTaskStub *stubToFree );
    7.60 +inline void
    7.61 +replaceWithNewSlotSlvIfNeeded( SlaveVP *requestingSlv, VSsSemEnv *semEnv );
    7.62 +
    7.63 +
    7.64 +#endif	/* _VSs_REQ_H */
    7.65 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/DKU_singleton_asm.s	Mon Aug 27 02:14:35 2012 -0700
     8.3 @@ -0,0 +1,21 @@
     8.4 +
     8.5 +//Assembly code takes the return addr off the stack and saves
     8.6 +// into the singleton.  The first field in the singleton is the
     8.7 +// "endInstrAddr" field, and the return addr is at 0x4(%ebp)
     8.8 +.globl asm_save_ret_to_singleton
     8.9 +asm_save_ret_to_singleton:
    8.10 +    movq 0x8(%rbp),     %rax   #get ret address, ebp is the same as in the calling function
    8.11 +    movq     %rax,     (%rdi) #write ret addr to endInstrAddr field
    8.12 +    ret
    8.13 +
    8.14 +
    8.15 +//Assembly code changes the return addr on the stack to the one
    8.16 +// saved into the singleton by the end-singleton-fn
    8.17 +//The stack's return addr is at 0x4(%%ebp)
    8.18 +.globl asm_write_ret_from_singleton
    8.19 +asm_write_ret_from_singleton:
    8.20 +    movq    (%rdi),    %rax  #get endInstrAddr field
    8.21 +    movq      %rax,    0x8(%rbp) #write return addr to the stack of the caller
    8.22 +    ret
    8.23 +
    8.24 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/Measurement/DKU_Counter_Recording.c	Mon Aug 27 02:14:35 2012 -0700
     9.3 @@ -0,0 +1,121 @@
     9.4 +/*
     9.5 + * 
     9.6 + * author: Nina Engelhardt
     9.7 + */
     9.8 +
     9.9 +#include "VSs_Counter_Recording.h"
    9.10 +#include "VMS_impl/VMS.h"
    9.11 +#include "VSs_impl/VSs.h"
    9.12 +
    9.13 +#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS
    9.14 +
    9.15 +void VSs__init_counter_data_structs(){
    9.16 +    VSsSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv;
    9.17 +    int i;
    9.18 +    for(i=0;i<NUM_CORES;i++){
    9.19 +        semanticEnv->counterList[i] = makeListOfArrays(sizeof(CounterEvent), 128);
    9.20 +    }
    9.21 +}
    9.22 +
    9.23 +void addToListOfArraysCounterEvent(CounterEvent value, ListOfArrays* list){
    9.24 +    int offset_in_fragment = list->next_free_index % list->num_entries_per_fragment; 
    9.25 +    if(offset_in_fragment == 0){ 
    9.26 +        void* newBlock = malloc(list->entry_size * list->num_entries_per_fragment); 
    9.27 +        addToDynArray(newBlock,list->dim1info); 
    9.28 +    } 
    9.29 +    CounterEvent* typedFragment = (CounterEvent*) ((list->dim1)[list->dim1info->numInArray -1]); 
    9.30 +    typedFragment[offset_in_fragment] = value; 
    9.31 +    list->next_free_index++; 
    9.32 +}
    9.33 +
    9.34 +void VSs__counter_handler(int evt_type, int vpid, int task, SlaveVP* pr, uint64 cycles, uint64 instrs)
    9.35 +{
    9.36 +    
    9.37 +    if (pr->typeOfVP == Master || pr->typeOfVP == Shutdown)
    9.38 +     { //Only save values for application work, done in a SlaveVP
    9.39 +        return;
    9.40 +     }
    9.41 +
    9.42 +    VSsSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv;
    9.43 +            
    9.44 +    CounterEvent e;
    9.45 +    e.event_type = evt_type;
    9.46 +    e.vp = vpid;
    9.47 +    e.task = task;
    9.48 +    
    9.49 +    e.cycles = cycles;
    9.50 +    e.instrs = instrs;
    9.51 +    
    9.52 +    if(pr){
    9.53 +        e.coreID = pr->coreAnimatedBy;
    9.54 +        e.slot = pr->animSlotAssignedTo;
    9.55 +    } else {
    9.56 +        e.coreID = -1;
    9.57 +        e.slot = NULL;
    9.58 +    }
    9.59 +    
    9.60 +    int corenum;
    9.61 +    
    9.62 +    if(pr) corenum = pr->coreAnimatedBy; else return; 
    9.63 +  
    9.64 +    if(evt_type==Work_start || evt_type==Work_end || evt_type==AppResponderInvocation_start){
    9.65 +        addToListOfArrays_ext(CounterEvent,e,semanticEnv->counterList[corenum]);
    9.66 +    } else {
    9.67 +        addToListOfArraysCounterEvent(e,semanticEnv->counterList[corenum]);
    9.68 +    }
    9.69 +}
    9.70 +
    9.71 +void set_counter_file(FILE* f){
    9.72 +    counterfile = f;
    9.73 +}
    9.74 +
    9.75 +void print_counter_events_to_file(void* _e){
    9.76 +     CounterEvent* e = (CounterEvent*) _e;
    9.77 +     fprintf(counterfile, "event, ");
    9.78 +     switch(e->event_type){
    9.79 +         case AppResponderInvocation_start:
    9.80 +             fprintf(counterfile, "AppResponderInvocation_start");
    9.81 +             break;
    9.82 +         case AppResponder_start:
    9.83 +             fprintf(counterfile, "AppResponder_start");
    9.84 +             break;
    9.85 +         case AppResponder_end:
    9.86 +             fprintf(counterfile, "AppResponder_end");
    9.87 +             break;
    9.88 +         case AssignerInvocation_start:
    9.89 +             fprintf(counterfile, "AssignerInvocation_start");
    9.90 +             break;
    9.91 +         case NextAssigner_start:
    9.92 +             fprintf(counterfile, "NextAssigner_start");
    9.93 +             break;
    9.94 +         case Assigner_start:
    9.95 +             fprintf(counterfile, "Assigner_start");
    9.96 +             break;
    9.97 +         case Assigner_end:
    9.98 +             fprintf(counterfile, "Assigner_end");
    9.99 +             break;
   9.100 +         case Work_end:
   9.101 +             fprintf(counterfile, "Work_end");
   9.102 +             break;
   9.103 +         case Work_start:
   9.104 +             fprintf(counterfile, "Work_start");
   9.105 +             break;
   9.106 +         case HwResponderInvocation_start:
   9.107 +             fprintf(counterfile, "HwResponderInvocation_start");
   9.108 +             break;
   9.109 +         case Timestamp_start:
   9.110 +             fprintf(counterfile, "Timestamp_start");
   9.111 +             break;
   9.112 +         case Timestamp_end:
   9.113 +             fprintf(counterfile, "Timestamp_end");
   9.114 +             break;
   9.115 +         default:
   9.116 +             fprintf(counterfile, "unknown event");
   9.117 +     }
   9.118 +     fprintf(counterfile,", %d, %d, %llu, %llu",e->vp,e->task,e->cycles,e->instrs);
   9.119 +     if(e->coreID >=0)
   9.120 +         fprintf(counterfile,", %d",e->coreID);
   9.121 +     fprintf(counterfile,"\n");
   9.122 +     fflush(counterfile);
   9.123 +}
   9.124 +#endif
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/Measurement/DKU_Counter_Recording.h	Mon Aug 27 02:14:35 2012 -0700
    10.3 @@ -0,0 +1,33 @@
    10.4 +/* 
    10.5 + * File:   VSs_Counter_Recording.h
    10.6 + * Author: nengel
    10.7 + *
    10.8 + * Created on January 11, 2012, 3:03 PM
    10.9 + */
   10.10 +
   10.11 +#ifndef VSs_COUNTER_RECORDING_H
   10.12 +#define	VSs_COUNTER_RECORDING_H
   10.13 +
   10.14 +#include "VMS_impl/VMS.h"
   10.15 +
   10.16 +typedef struct {
   10.17 +   int event_type;
   10.18 +   int coreID;
   10.19 +   AnimSlot* slot;
   10.20 +   int vp;
   10.21 +   int task;
   10.22 +   uint64 cycles;
   10.23 +   uint64 instrs;
   10.24 +} CounterEvent;
   10.25 +
   10.26 +FILE* counterfile;
   10.27 +
   10.28 +void VSs__init_counter_data_structs();
   10.29 +
   10.30 +void VSs__counter_handler(int evt_type, int vpid, int task, SlaveVP* pr, uint64 cycles, uint64 instrs);
   10.31 +
   10.32 +void set_counter_file(FILE* f);
   10.33 +
   10.34 +void print_counter_events_to_file(void* _e);
   10.35 +#endif	/* VSs_COUNTER_RECORDING_H */
   10.36 +
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/Measurement/DKU_Measurement.h	Mon Aug 27 02:14:35 2012 -0700
    11.3 @@ -0,0 +1,87 @@
    11.4 +/*
    11.5 + *  Copyright 2009 OpenSourceStewardshipFoundation.org
    11.6 + *  Licensed under GNU General Public License version 2
    11.7 + *
    11.8 + * Author: seanhalle@yahoo.com
    11.9 + *
   11.10 + */
   11.11 +
   11.12 +#ifndef _VSs_MEAS_H
   11.13 +#define	_VSs_MEAS_H
   11.14 +
   11.15 +
   11.16 +#ifdef MEAS__TURN_ON_LANG_MEAS
   11.17 +
   11.18 +   #ifdef MEAS__Make_Meas_Hists_for_Language
   11.19 +   #undef MEAS__Make_Meas_Hists_for_Language
   11.20 +   #endif
   11.21 +
   11.22 +
   11.23 +//===================  Language-specific Measurement Stuff ===================
   11.24 +//
   11.25 +//
   11.26 +   #define SendFromToHistIdx      1 //note: starts at 1
   11.27 +   #define SendOfTypeHistIdx      2
   11.28 +   #define ReceiveFromToHistIdx   3
   11.29 +   #define ReceiveOfTypeHistIdx   4
   11.30 +
   11.31 +   #define MEAS__Make_Meas_Hists_for_Language \
   11.32 +      _VMSMasterEnv->measHistsInfo = \
   11.33 +                 makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \
   11.34 +       makeAMeasHist( SendFromToHistIdx,   "SendFromTo",    50, 0, 100 ) \
   11.35 +       makeAMeasHist( SendOfTypeHistIdx,   "SendOfType",    50, 0, 100 ) \
   11.36 +       makeAMeasHist( ReceiveFromToHistIdx,"ReceiveFromTo", 50, 0, 100 ) \
   11.37 +       makeAMeasHist( ReceiveOfTypeHistIdx,"ReceiveOfType", 50, 0, 100 )
   11.38 +
   11.39 +   #define Meas_startSendFromTo \
   11.40 +       int32 startStamp, endStamp; \
   11.41 +       saveLowTimeStampCountInto( startStamp ); \
   11.42 +
   11.43 +   #define Meas_endSendFromTo \
   11.44 +       saveLowTimeStampCountInto( endStamp ); \
   11.45 +       addIntervalToHist( startStamp, endStamp, \
   11.46 +                                _VMSMasterEnv->measHists[ SendFromToHistIdx ] );
   11.47 +
   11.48 +   #define Meas_startSendOfType \
   11.49 +       int32 startStamp, endStamp; \
   11.50 +       saveLowTimeStampCountInto( startStamp ); \
   11.51 +
   11.52 +   #define Meas_endSendOfType \
   11.53 +       saveLowTimeStampCountInto( endStamp ); \
   11.54 +       addIntervalToHist( startStamp, endStamp, \
   11.55 +                                _VMSMasterEnv->measHists[ SendOfTypeHistIdx ] );
   11.56 +
   11.57 +   #define Meas_startReceiveFromTo \
   11.58 +       int32 startStamp, endStamp; \
   11.59 +       saveLowTimeStampCountInto( startStamp ); \
   11.60 +
   11.61 +   #define Meas_endReceiveFromTo \
   11.62 +       saveLowTimeStampCountInto( endStamp ); \
   11.63 +       addIntervalToHist( startStamp, endStamp, \
   11.64 +                                _VMSMasterEnv->measHists[ ReceiveFromToHistIdx ] );
   11.65 +
   11.66 +   #define Meas_startReceiveOfType \
   11.67 +       int32 startStamp, endStamp; \
   11.68 +       saveLowTimeStampCountInto( startStamp ); \
   11.69 +
   11.70 +   #define Meas_endReceiveOfType \
   11.71 +       saveLowTimeStampCountInto( endStamp ); \
   11.72 +       addIntervalToHist( startStamp, endStamp, \
   11.73 +                                _VMSMasterEnv->measHists[ReceiveOfTypeHistIdx ] );
   11.74 +
   11.75 +#else //===================== turned off ==========================
   11.76 +
   11.77 +   #define MEAS__Make_Meas_Hists_for_Language
   11.78 +   #define Meas_startSendFromTo
   11.79 +   #define Meas_endSendFromTo
   11.80 +   #define Meas_startSendOfType
   11.81 +   #define Meas_endSendOfType
   11.82 +   #define Meas_startReceiveFromTo
   11.83 +   #define Meas_endReceiveFromTo
   11.84 +   #define Meas_startReceiveOfType
   11.85 +   #define Meas_endReceiveOfType
   11.86 +
   11.87 +#endif  /* MEAS__TURN_ON_LANG_MEAS */
   11.88 +
   11.89 +#endif	/*  */
   11.90 +
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/Measurement/dependency.c	Mon Aug 27 02:14:35 2012 -0700
    12.3 @@ -0,0 +1,78 @@
    12.4 +#include "dependency.h"
    12.5 +#include "VMS_impl/VMS.h"
    12.6 +
    12.7 +Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task){
    12.8 +    Dependency* newDep = (Dependency*) VMS_int__malloc(sizeof(Dependency));
    12.9 +    if (newDep!=NULL){
   12.10 +        newDep->from_vp = from_vp;
   12.11 +        newDep->from_task = from_task;
   12.12 +        newDep->to_vp = to_vp;
   12.13 +        newDep->to_task = to_task;
   12.14 +    }
   12.15 +    return newDep;
   12.16 +}
   12.17 +
   12.18 +NtoN* new_NtoN(int id){
   12.19 +    NtoN* newn = (NtoN*) VMS_int__malloc(sizeof(NtoN));
   12.20 +    newn->id = id;
   12.21 +    newn->senders = makeListOfArrays(sizeof(Unit), 64);
   12.22 +    newn->receivers = makeListOfArrays(sizeof(Unit), 64);
   12.23 +    return newn;
   12.24 +}
   12.25 +
   12.26 +int set_dependency_file(FILE* file){
   12.27 +    dependency_file = file;
   12.28 +}
   12.29 +
   12.30 +void print_ctl_dependency_to_file(void* _dep){
   12.31 +    Dependency* dep = (Dependency*) _dep;
   12.32 +    if(!dep) return;
   12.33 +    fprintf(dependency_file,"ctlDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task);
   12.34 +}
   12.35 +
   12.36 +void print_comm_dependency_to_file(void* _dep){
   12.37 +    Dependency* dep = (Dependency*) _dep;
   12.38 +    if(!dep) return;
   12.39 +    fprintf(dependency_file,"commDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task);
   12.40 +}
   12.41 +
   12.42 +void print_dyn_dependency_to_file(void* _dep){
   12.43 +    Dependency* dep = (Dependency*) _dep;
   12.44 +    if(!dep) return;
   12.45 +    fprintf(dependency_file,"dynDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task);
   12.46 +}
   12.47 +
   12.48 +void print_hw_dependency_to_file(void* _dep){
   12.49 +    Dependency* dep = (Dependency*) _dep;
   12.50 +    if(!dep) return;
   12.51 +    fprintf(dependency_file,"hwDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task);
   12.52 +}
   12.53 +
   12.54 +void print_dependency_to_file(void* _dep){
   12.55 +    Dependency* dep = (Dependency*) _dep;
   12.56 +    if(!dep) return;
   12.57 +    fprintf(dependency_file,"VP_%d_%d -> VP_%d_%d;\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task);
   12.58 +}
   12.59 +
   12.60 +void print_unit_to_file(void* _unit){
   12.61 +    Unit* unit = (Unit*) _unit;
   12.62 +    if(!unit) return;
   12.63 +    fprintf(dependency_file,"unit,%d,%d\n",unit->vp,unit->task);
   12.64 +}
   12.65 +
   12.66 +void print_nton_set_helper(void* _u){
   12.67 +    Unit* u = (Unit*) _u;
   12.68 +    if(!u) return;
   12.69 +    fprintf(dependency_file,",%d,%d",u->vp,u->task);
   12.70 +}
   12.71 +
   12.72 +void print_nton_to_file(void* _nton){
   12.73 +    NtoN* nton = (NtoN*) _nton;
   12.74 +    if(!nton) return;
   12.75 +    //assert(nton->senders->next_free_index==nton->receivers->next_free_index);
   12.76 +    int numInSet = nton->senders->next_free_index;
   12.77 +    fprintf(dependency_file,"NtoN,%d",numInSet);
   12.78 +    forAllInListOfArraysDo(nton->senders,&print_nton_set_helper);
   12.79 +    forAllInListOfArraysDo(nton->receivers,&print_nton_set_helper);
   12.80 +    fprintf(dependency_file,"\n");
   12.81 +}
   12.82 \ No newline at end of file
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/Measurement/dependency.h	Mon Aug 27 02:14:35 2012 -0700
    13.3 @@ -0,0 +1,56 @@
    13.4 +/* 
    13.5 + * File:   dependency.h
    13.6 + * Author: Nina Engelhardt
    13.7 + *
    13.8 + * Created on 29. August 2011, 17:41
    13.9 + */
   13.10 +
   13.11 +#ifndef  _DEPENDENCY_H
   13.12 +#define	_DEPENDENCY_H
   13.13 +
   13.14 +
   13.15 +#include <stdio.h>
   13.16 +#include "ListOfArrays/ListOfArrays.h"
   13.17 +
   13.18 +typedef struct {
   13.19 +    int vp;
   13.20 +    int task;
   13.21 +} Unit;
   13.22 +
   13.23 +typedef struct {
   13.24 +    int from_vp;
   13.25 +    int from_task;
   13.26 +    int to_vp;
   13.27 +    int to_task;
   13.28 +} Dependency; 
   13.29 +
   13.30 +typedef struct {
   13.31 +    int32 id;
   13.32 +    ListOfArrays* senders;
   13.33 +    ListOfArrays* receivers;
   13.34 +} NtoN;
   13.35 +
   13.36 +FILE* dependency_file;
   13.37 +
   13.38 +Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task);
   13.39 +
   13.40 +NtoN* new_NtoN(int id);
   13.41 +
   13.42 +int set_dependency_file(FILE* file);
   13.43 +
   13.44 +void print_ctl_dependency_to_file(void* _dep);
   13.45 +
   13.46 +void print_comm_dependency_to_file(void* _dep);
   13.47 +
   13.48 +void print_dyn_dependency_to_file(void* _dep);
   13.49 +
   13.50 +void print_hw_dependency_to_file(void* _dep);
   13.51 +
   13.52 +void print_dependency_to_file(void* dep);
   13.53 +
   13.54 +void print_unit_to_file(void* unit);
   13.55 +
   13.56 +void print_nton_to_file(void* _nton);
   13.57 +
   13.58 +#endif	/* DEPENDENCY_H */
   13.59 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/__brch__default	Mon Aug 27 02:14:35 2012 -0700
    14.3 @@ -0,0 +1,1 @@
    14.4 +This branch is standard default