changeset 6:58d0c2b1d6a4

removed warnings
author Merten Sach <msach@mailbox.tu-berlin.de>
date Wed, 11 May 2011 16:11:06 +0200
parents 5494943ed3a4
children f0ec8652cbf4
files VCilk.h VCilk_PluginFns.c VCilk_lib.c
diffstat 3 files changed, 1294 insertions(+), 1294 deletions(-) [+]
line diff
     1.1 --- a/VCilk.h	Wed May 11 15:29:58 2011 +0200
     1.2 +++ b/VCilk.h	Wed May 11 16:11:06 2011 +0200
     1.3 @@ -1,200 +1,200 @@
     1.4 -/*
     1.5 - *  Copyright 2009 OpenSourceStewardshipFoundation.org
     1.6 - *  Licensed under GNU General Public License version 2
     1.7 - *
     1.8 - * Author: seanhalle@yahoo.com
     1.9 - *
    1.10 - */
    1.11 -
    1.12 -#ifndef _VCilk_H
    1.13 -#define	_VCilk_H
    1.14 -
    1.15 -#include "VMS/Queue_impl/PrivateQueue.h"
    1.16 -#include "VMS/Hash_impl/PrivateHash.h"
    1.17 -#include "VMS/VMS.h"
    1.18 -
    1.19 -
    1.20 -
    1.21 -/*This header defines everything specific to the VCilk semantic plug-in
    1.22 - */
    1.23 -
    1.24 -//===========================================================================
    1.25 -#define NUM_STRUCS_IN_SEM_ENV 1000
    1.26 -
    1.27 -//===========================================================================
    1.28 -typedef struct _VCilkSemReq   VCilkSemReq;
    1.29 -typedef void  (*PtrToAtomicFn )   ( void * ); //executed atomically in master
    1.30 -
    1.31 -//===========================================================================
    1.32 -
    1.33 -
    1.34 -/*WARNING: assembly hard-codes position of endInstrAddr as first field
    1.35 - */
    1.36 -typedef struct
    1.37 - {
    1.38 -   void           *endInstrAddr;
    1.39 -   int32           hasBeenStarted;
    1.40 -   int32           hasFinished;
    1.41 -   PrivQueueStruc *waitQ;
    1.42 - }
    1.43 -VCilkSingleton;
    1.44 -
    1.45 -/*Semantic layer-specific data sent inside a request from lib called in app
    1.46 - * to request handler called in MasterLoop
    1.47 - */
    1.48 -enum VCilkReqType
    1.49 - {
    1.50 -   syncReq = 1,
    1.51 -   mallocReq,
    1.52 -   freeReq,
    1.53 -   singleton_fn_start,
    1.54 -   singleton_fn_end,
    1.55 -   singleton_data_start,
    1.56 -   singleton_data_end,
    1.57 -   atomic,
    1.58 -   trans_start,
    1.59 -   trans_end
    1.60 - };
    1.61 -
    1.62 -struct _VCilkSemReq
    1.63 - { enum VCilkReqType    reqType;
    1.64 -   VirtProcr           *requestingPr;
    1.65 -   
    1.66 -   int32                sizeToMalloc;
    1.67 -   void                *ptrToFree;
    1.68 -   
    1.69 -   VirtProcrFnPtr       fnPtr;
    1.70 -   void                *initData;
    1.71 -   int32                coreToSpawnOnto;
    1.72 -
    1.73 -   int32              singletonID;
    1.74 -   VCilkSingleton     **singletonPtrAddr;
    1.75 -
    1.76 -   PtrToAtomicFn      fnToExecInMaster;
    1.77 -   void              *dataForFn;
    1.78 -
    1.79 -   int32              transID;
    1.80 - }
    1.81 -/* VCilkSemReq */;
    1.82 -
    1.83 -typedef struct
    1.84 - {
    1.85 -   VirtProcr      *VPCurrentlyExecuting;
    1.86 -   PrivQueueStruc *waitingVPQ;
    1.87 - }
    1.88 -VCilkTrans;
    1.89 -
    1.90 -typedef struct
    1.91 - {
    1.92 -   PrivQueueStruc **readyVPQs;
    1.93 -   HashTable       *commHashTbl;
    1.94 -   int32            numVirtPr;
    1.95 -   int32            nextCoreToGetNewPr;
    1.96 -   int32            primitiveStartTime;
    1.97 -
    1.98 -                       //fix limit on num with dynArray
    1.99 -   VCilkSingleton     fnSingletons[NUM_STRUCS_IN_SEM_ENV];
   1.100 -   VCilkTrans       transactionStrucs[NUM_STRUCS_IN_SEM_ENV];
   1.101 - }
   1.102 -VCilkSemEnv;
   1.103 -
   1.104 -typedef struct _TransListElem TransListElem;
   1.105 -struct _TransListElem
   1.106 - {
   1.107 -   int32          transID;
   1.108 -   TransListElem *nextTrans;
   1.109 - };
   1.110 -//TransListElem
   1.111 -
   1.112 -typedef struct
   1.113 - {
   1.114 -   int32          syncPending;
   1.115 -   int32          numLiveChildren;
   1.116 -   VirtProcr     *parentPr;
   1.117 -   
   1.118 -   int32          highestTransEntered;
   1.119 -   TransListElem *lastTransEntered;
   1.120 - }
   1.121 -VCilkSemData;
   1.122 -
   1.123 -//===========================================================================
   1.124 -
   1.125 -void
   1.126 -VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fn, void *initData );
   1.127 -
   1.128 -int32
   1.129 -VCilk__giveMinWorkUnitCycles( float32 percentOverhead );
   1.130 -
   1.131 -void inline
   1.132 -VCilk__start_primitive();
   1.133 -
   1.134 -int32 inline
   1.135 -VCilk__end_primitive_and_give_cycles();
   1.136 -
   1.137 -int32
   1.138 -VCilk__giveIdealNumWorkUnits();
   1.139 -
   1.140 -//=======================
   1.141 -
   1.142 -void
   1.143 -VCilk__init();
   1.144 -
   1.145 -void
   1.146 -VCilk__cleanup_at_end_of_shutdown();
   1.147 -
   1.148 -//=======================
   1.149 -
   1.150 -void inline
   1.151 -VCilk__spawn( int32  coreToSpawnOnto, VirtProcrFnPtr  fnPtr,
   1.152 -              void  *initData,        VirtProcr      *creatingPr );
   1.153 -
   1.154 -int32
   1.155 -VCilk__give_number_of_cores_to_spawn_onto();
   1.156 -
   1.157 -void
   1.158 -VCilk__sync( VirtProcr *animatingPr );
   1.159 -
   1.160 -void *
   1.161 -VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr );
   1.162 -
   1.163 -void
   1.164 -VCilk__free( void *ptrToFree, VirtProcr *animPr );
   1.165 -
   1.166 -void
   1.167 -VCilk__dissipate_procr( VirtProcr *procrToDissipate );
   1.168 -
   1.169 -
   1.170 -//======================= Concurrency Stuff ======================
   1.171 -void
   1.172 -VCilk__start_fn_singleton( int32 singletonID, VirtProcr *animPr );
   1.173 -
   1.174 -void
   1.175 -VCilk__end_fn_singleton( int32 singletonID, VirtProcr *animPr );
   1.176 -
   1.177 -void
   1.178 -VCilk__start_data_singleton( VCilkSingleton **singeltonAddr, VirtProcr *animPr );
   1.179 -
   1.180 -void
   1.181 -VCilk__end_data_singleton( VCilkSingleton **singletonAddr, VirtProcr *animPr );
   1.182 -
   1.183 -void
   1.184 -VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
   1.185 -                                      void *data, VirtProcr *animPr );
   1.186 -
   1.187 -void
   1.188 -VCilk__start_transaction( int32 transactionID, VirtProcr *animPr );
   1.189 -
   1.190 -void
   1.191 -VCilk__end_transaction( int32 transactionID, VirtProcr *animPr );
   1.192 -
   1.193 -
   1.194 -//=========================  Internal use only  =============================
   1.195 -void
   1.196 -VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv );
   1.197 -
   1.198 -VirtProcr *
   1.199 -VCilk__schedule_virt_procr( void *_semEnv, int coreNum );
   1.200 -
   1.201 -
   1.202 -#endif	/* _VCilk_H */
   1.203 -
   1.204 +/*
   1.205 + *  Copyright 2009 OpenSourceStewardshipFoundation.org
   1.206 + *  Licensed under GNU General Public License version 2
   1.207 + *
   1.208 + * Author: seanhalle@yahoo.com
   1.209 + *
   1.210 + */
   1.211 +
   1.212 +#ifndef _VCilk_H
   1.213 +#define	_VCilk_H
   1.214 +
   1.215 +#include "VMS/Queue_impl/PrivateQueue.h"
   1.216 +#include "VMS/Hash_impl/PrivateHash.h"
   1.217 +#include "VMS/VMS.h"
   1.218 +
   1.219 +
   1.220 +
   1.221 +/*This header defines everything specific to the VCilk semantic plug-in
   1.222 + */
   1.223 +
   1.224 +//===========================================================================
   1.225 +#define NUM_STRUCS_IN_SEM_ENV 1000
   1.226 +
   1.227 +//===========================================================================
   1.228 +typedef struct _VCilkSemReq   VCilkSemReq;
   1.229 +typedef void  (*PtrToAtomicFn )   ( void * ); //executed atomically in master
   1.230 +
   1.231 +//===========================================================================
   1.232 +
   1.233 +
   1.234 +/*WARNING: assembly hard-codes position of endInstrAddr as first field
   1.235 + */
   1.236 +typedef struct
   1.237 + {
   1.238 +   void           *endInstrAddr;
   1.239 +   int32           hasBeenStarted;
   1.240 +   int32           hasFinished;
   1.241 +   PrivQueueStruc *waitQ;
   1.242 + }
   1.243 +VCilkSingleton;
   1.244 +
   1.245 +/*Semantic layer-specific data sent inside a request from lib called in app
   1.246 + * to request handler called in MasterLoop
   1.247 + */
   1.248 +enum VCilkReqType
   1.249 + {
   1.250 +   syncReq = 1,
   1.251 +   mallocReq,
   1.252 +   freeReq,
   1.253 +   singleton_fn_start,
   1.254 +   singleton_fn_end,
   1.255 +   singleton_data_start,
   1.256 +   singleton_data_end,
   1.257 +   atomic,
   1.258 +   trans_start,
   1.259 +   trans_end
   1.260 + };
   1.261 +
   1.262 +struct _VCilkSemReq
   1.263 + { enum VCilkReqType    reqType;
   1.264 +   VirtProcr           *requestingPr;
   1.265 +   
   1.266 +   int32                sizeToMalloc;
   1.267 +   void                *ptrToFree;
   1.268 +   
   1.269 +   VirtProcrFnPtr       fnPtr;
   1.270 +   void                *initData;
   1.271 +   int32                coreToSpawnOnto;
   1.272 +
   1.273 +   int32              singletonID;
   1.274 +   VCilkSingleton     **singletonPtrAddr;
   1.275 +
   1.276 +   PtrToAtomicFn      fnToExecInMaster;
   1.277 +   void              *dataForFn;
   1.278 +
   1.279 +   int32              transID;
   1.280 + }
   1.281 +/* VCilkSemReq */;
   1.282 +
   1.283 +typedef struct
   1.284 + {
   1.285 +   VirtProcr      *VPCurrentlyExecuting;
   1.286 +   PrivQueueStruc *waitingVPQ;
   1.287 + }
   1.288 +VCilkTrans;
   1.289 +
   1.290 +typedef struct
   1.291 + {
   1.292 +   PrivQueueStruc **readyVPQs;
   1.293 +   HashTable       *commHashTbl;
   1.294 +   int32            numVirtPr;
   1.295 +   int32            nextCoreToGetNewPr;
   1.296 +   int32            primitiveStartTime;
   1.297 +
   1.298 +                       //fix limit on num with dynArray
   1.299 +   VCilkSingleton     fnSingletons[NUM_STRUCS_IN_SEM_ENV];
   1.300 +   VCilkTrans       transactionStrucs[NUM_STRUCS_IN_SEM_ENV];
   1.301 + }
   1.302 +VCilkSemEnv;
   1.303 +
   1.304 +typedef struct _TransListElem TransListElem;
   1.305 +struct _TransListElem
   1.306 + {
   1.307 +   int32          transID;
   1.308 +   TransListElem *nextTrans;
   1.309 + };
   1.310 +//TransListElem
   1.311 +
   1.312 +typedef struct
   1.313 + {
   1.314 +   int32          syncPending;
   1.315 +   int32          numLiveChildren;
   1.316 +   VirtProcr     *parentPr;
   1.317 +   
   1.318 +   int32          highestTransEntered;
   1.319 +   TransListElem *lastTransEntered;
   1.320 + }
   1.321 +VCilkSemData;
   1.322 +
   1.323 +//===========================================================================
   1.324 +
   1.325 +void
   1.326 +VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fn, void *initData );
   1.327 +
   1.328 +int32
   1.329 +VCilk__giveMinWorkUnitCycles( float32 percentOverhead );
   1.330 +
   1.331 +void inline
   1.332 +VCilk__start_primitive();
   1.333 +
   1.334 +int32 inline
   1.335 +VCilk__end_primitive_and_give_cycles();
   1.336 +
   1.337 +int32
   1.338 +VCilk__giveIdealNumWorkUnits();
   1.339 +
   1.340 +//=======================
   1.341 +
   1.342 +void
   1.343 +VCilk__init();
   1.344 +
   1.345 +void
   1.346 +VCilk__cleanup_at_end_of_shutdown();
   1.347 +
   1.348 +//=======================
   1.349 +
   1.350 +void inline
   1.351 +VCilk__spawn( int32  coreToSpawnOnto, VirtProcrFnPtr  fnPtr,
   1.352 +              void  *initData,        VirtProcr      *creatingPr );
   1.353 +
   1.354 +int32
   1.355 +VCilk__give_number_of_cores_to_spawn_onto();
   1.356 +
   1.357 +void
   1.358 +VCilk__sync( VirtProcr *animatingPr );
   1.359 +
   1.360 +void *
   1.361 +VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr );
   1.362 +
   1.363 +void
   1.364 +VCilk__free( void *ptrToFree, VirtProcr *animPr );
   1.365 +
   1.366 +void
   1.367 +VCilk__dissipate_procr( VirtProcr *procrToDissipate );
   1.368 +
   1.369 +
   1.370 +//======================= Concurrency Stuff ======================
   1.371 +void
   1.372 +VCilk__start_fn_singleton( int32 singletonID, VirtProcr *animPr );
   1.373 +
   1.374 +void
   1.375 +VCilk__end_fn_singleton( int32 singletonID, VirtProcr *animPr );
   1.376 +
   1.377 +void
   1.378 +VCilk__start_data_singleton( VCilkSingleton **singeltonAddr, VirtProcr *animPr );
   1.379 +
   1.380 +void
   1.381 +VCilk__end_data_singleton( VCilkSingleton **singletonAddr, VirtProcr *animPr );
   1.382 +
   1.383 +void
   1.384 +VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
   1.385 +                                      void *data, VirtProcr *animPr );
   1.386 +
   1.387 +void
   1.388 +VCilk__start_transaction( int32 transactionID, VirtProcr *animPr );
   1.389 +
   1.390 +void
   1.391 +VCilk__end_transaction( int32 transactionID, VirtProcr *animPr );
   1.392 +
   1.393 +
   1.394 +//=========================  Internal use only  =============================
   1.395 +void
   1.396 +VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv );
   1.397 +
   1.398 +VirtProcr *
   1.399 +VCilk__schedule_virt_procr( void *_semEnv, int coreNum );
   1.400 +
   1.401 +
   1.402 +#endif	/* _VCilk_H */
   1.403 +
     2.1 --- a/VCilk_PluginFns.c	Wed May 11 15:29:58 2011 +0200
     2.2 +++ b/VCilk_PluginFns.c	Wed May 11 16:11:06 2011 +0200
     2.3 @@ -1,555 +1,555 @@
     2.4 -/*
     2.5 - * Copyright 2010  OpenSourceCodeStewardshipFoundation
     2.6 - *
     2.7 - * Licensed under BSD
     2.8 - */
     2.9 -
    2.10 -#include <stdio.h>
    2.11 -#include <stdlib.h>
    2.12 -
    2.13 -#include "VMS/Queue_impl/PrivateQueue.h"
    2.14 -#include "VCilk.h"
    2.15 -
    2.16 -
    2.17 -
    2.18 -//===========================================================================
    2.19 -void inline
    2.20 -handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv );
    2.21 -
    2.22 -void inline
    2.23 -handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.24 -              VCilkSemEnv *semEnv );
    2.25 -void inline
    2.26 -handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.27 -            VCilkSemEnv *semEnv );
    2.28 -void inline
    2.29 -handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv );
    2.30 -
    2.31 -void inline
    2.32 -handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv );
    2.33 -
    2.34 -void inline
    2.35 -dispatchSemReq( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv);
    2.36 -
    2.37 -void inline
    2.38 -handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.39 -                VCilkSemEnv*semEnv);
    2.40 -void inline
    2.41 -handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.42 -                  VCilkSemEnv *semEnv );
    2.43 -void inline
    2.44 -handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.45 -              VCilkSemEnv *semEnv);
    2.46 -inline void
    2.47 -handleStartFnSingleton( VCilkSemReq *semReq, VirtProcr *reqstingPr,
    2.48 -                      VCilkSemEnv *semEnv );
    2.49 -inline void
    2.50 -handleEndFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.51 -                    VCilkSemEnv *semEnv );
    2.52 -inline void
    2.53 -handleStartDataSingleton( VCilkSemReq *semReq, VirtProcr *reqstingPr,
    2.54 -                      VCilkSemEnv *semEnv );
    2.55 -inline void
    2.56 -handleEndDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.57 -                    VCilkSemEnv *semEnv );
    2.58 -
    2.59 -void inline
    2.60 -resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv );
    2.61 -
    2.62 -//===========================================================================
    2.63 -
    2.64 -
    2.65 -//============================== Scheduler ==================================
    2.66 -//
    2.67 -/*For VCilk, scheduling a slave simply takes the next work-unit off the
    2.68 - * ready-to-go work-unit queue and assigns it to the slaveToSched.
    2.69 - *If the ready-to-go work-unit queue is empty, then nothing to schedule
    2.70 - * to the slave -- return FALSE to let Master loop know scheduling that
    2.71 - * slave failed.
    2.72 - */
    2.73 -VirtProcr *
    2.74 -VCilk__schedule_virt_procr( void *_semEnv, int coreNum )
    2.75 - { VirtProcr   *schedPr;
    2.76 -   VCilkSemEnv *semEnv;
    2.77 -
    2.78 -   semEnv = (VCilkSemEnv *)_semEnv;
    2.79 -
    2.80 -   schedPr = readPrivQ( semEnv->readyVPQs[coreNum] );
    2.81 -      //Note, using a non-blocking queue -- it returns NULL if queue empty
    2.82 -
    2.83 -   return( schedPr );
    2.84 - }
    2.85 -
    2.86 -
    2.87 -//===========================  Request Handler  =============================
    2.88 -//
    2.89 -/*Will get requests to send, to receive, and to create new processors.
    2.90 - * Upon send, check the hash to see if a receive is waiting.
    2.91 - * Upon receive, check hash to see if a send has already happened.
    2.92 - * When other is not there, put in.  When other is there, the comm.
    2.93 - *  completes, which means the receiver P gets scheduled and
    2.94 - *  picks up right after the receive request.  So make the work-unit
    2.95 - *  and put it into the queue of work-units ready to go.
    2.96 - * Other request is create a new Processor, with the function to run in the
    2.97 - *  Processor, and initial data.
    2.98 - */
    2.99 -void
   2.100 -VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv )
   2.101 - { VCilkSemEnv *semEnv;
   2.102 -   VMSReqst    *req;
   2.103 -   VCilkSemReq *semReq;
   2.104 - 
   2.105 -
   2.106 -   semEnv = (VCilkSemEnv *)_semEnv;
   2.107 -
   2.108 -   req = VMS__take_next_request_out_of( requestingPr );
   2.109 -   
   2.110 -   while( req != NULL )
   2.111 -    {
   2.112 -      switch( req->reqType )
   2.113 -       { case semantic:     dispatchSemReq( req, requestingPr, semEnv );
   2.114 -            break;
   2.115 -         case createReq:    //create request has to come as a VMS request,
   2.116 -                            // to allow MasterLoop to do stuff before gets
   2.117 -                            // here, and maybe also stuff after all requests
   2.118 -                            // done -- however, can still attach semantic
   2.119 -                            // req data to req.
   2.120 -                            handleSpawn(          req, requestingPr, semEnv);
   2.121 -            break;
   2.122 -         case dissipate:    handleDissipate(           requestingPr, semEnv);
   2.123 -            break;
   2.124 -         case VMSSemantic:  VMS__handle_VMSSemReq(req, requestingPr, semEnv,
   2.125 -                                                              &resume_procr);
   2.126 -            break;
   2.127 -         default:
   2.128 -            break;
   2.129 -       }
   2.130 -      
   2.131 -      DoneHandlingReqst:
   2.132 -
   2.133 -      req = VMS__take_next_request_out_of( requestingPr );
   2.134 -    } //while( req != NULL )
   2.135 - }
   2.136 -
   2.137 -void inline
   2.138 -dispatchSemReq( VMSReqst *req, VirtProcr *reqPr, VCilkSemEnv *semEnv )
   2.139 - { VCilkSemReq *semReq;
   2.140 -
   2.141 -   semReq = VMS__take_sem_reqst_from(req);
   2.142 -
   2.143 -   if( semReq == NULL ) return;
   2.144 -   switch( semReq->reqType )
   2.145 -    {
   2.146 -      case syncReq:         handleSync(                 reqPr, semEnv );
   2.147 -         break;
   2.148 -      case mallocReq:       handleMalloc(       semReq, reqPr, semEnv );
   2.149 -         break;
   2.150 -      case freeReq:         handleFree(         semReq, reqPr, semEnv );
   2.151 -         break;
   2.152 -      case singleton_fn_start:  handleStartFnSingleton(semReq, reqPr, semEnv);
   2.153 -         break;
   2.154 -      case singleton_fn_end:    handleEndFnSingleton(  semReq, reqPr, semEnv);
   2.155 -         break;
   2.156 -      case singleton_data_start:handleStartDataSingleton(semReq,reqPr,semEnv);
   2.157 -         break;
   2.158 -      case singleton_data_end:  handleEndDataSingleton(semReq, reqPr, semEnv);
   2.159 -         break;
   2.160 -      case atomic:          handleAtomic(       semReq, reqPr, semEnv );
   2.161 -         break;
   2.162 -      case trans_start:     handleTransStart(   semReq, reqPr, semEnv );
   2.163 -         break;
   2.164 -      case trans_end:       handleTransEnd(     semReq, reqPr, semEnv );
   2.165 -         break;
   2.166 -    }
   2.167 -   //NOTE: semantic request data strucs allocated on stack in VCilk Lib calls
   2.168 - }
   2.169 -
   2.170 -
   2.171 -
   2.172 -//=========================== Request Handlers ==============================
   2.173 -void inline
   2.174 -resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv )
   2.175 - {
   2.176 -   writePrivQ( procr, semEnv->readyVPQs[ procr->coreAnimatedBy] );
   2.177 - }
   2.178 -
   2.179 -
   2.180 -
   2.181 -
   2.182 -/* check if list of live children is empty.
   2.183 - * If yes, then resume.
   2.184 - * If no, then set sync-pending flag.
   2.185 - */
   2.186 -inline void
   2.187 -handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.188 - {
   2.189 -         Meas_startSync
   2.190 -   if(((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren  == 0 )
   2.191 -    { //no live children to wait for
   2.192 -      resume_procr( requestingPr, semEnv );
   2.193 -    }
   2.194 -   else
   2.195 -    {
   2.196 -      ((VCilkSemData *)(requestingPr->semanticData))->syncPending = TRUE;
   2.197 -    }
   2.198 -         Meas_endSync
   2.199 - }
   2.200 -
   2.201 -/*
   2.202 - */
   2.203 -inline void
   2.204 -handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.205 -              VCilkSemEnv *semEnv )
   2.206 - { void *ptr;
   2.207 -   
   2.208 -   ptr = VMS__malloc( semReq->sizeToMalloc );
   2.209 -   requestingPr->dataRetFromReq = ptr;
   2.210 -   resume_procr( requestingPr, semEnv );
   2.211 - }
   2.212 -
   2.213 -/*
   2.214 - */
   2.215 -void inline
   2.216 -handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.217 -            VCilkSemEnv *semEnv )
   2.218 - {
   2.219 -   VMS__free( semReq->ptrToFree );
   2.220 -   resume_procr( requestingPr, semEnv );
   2.221 - }
   2.222 -
   2.223 -
   2.224 -//============================== VMS requests ===============================
   2.225 -/*Re-use this in the entry-point fn
   2.226 - */
   2.227 -inline VirtProcr *
   2.228 -VCilk__create_procr_helper( VirtProcrFnPtr fnPtr, void  *initData,
   2.229 -   VirtProcr *requestingPr, VCilkSemEnv *semEnv,  int32  coreToScheduleOnto )
   2.230 - { VirtProcr    *newPr;
   2.231 -   VCilkSemData *semData;
   2.232 -
   2.233 -      //This is running in master, so use internal version
   2.234 -   newPr = VMS__create_procr( fnPtr, initData );
   2.235 -
   2.236 -   semData = VMS__malloc( sizeof(VCilkSemData) );
   2.237 -
   2.238 -   semData->numLiveChildren = 0;
   2.239 -   semData->parentPr        = requestingPr;
   2.240 -   semData->syncPending     = FALSE;
   2.241 -   
   2.242 -   semData->highestTransEntered = -1;
   2.243 -   semData->lastTransEntered    = NULL;
   2.244 -
   2.245 -   newPr->semanticData = semData;
   2.246 -
   2.247 -   /* increase the number of live children of requester.
   2.248 -    */
   2.249 -   if( requestingPr != NULL ) //NULL when creating seed procr
   2.250 -     ((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren +=1;
   2.251 -
   2.252 -   semEnv->numVirtPr += 1;
   2.253 -
   2.254 -   //=================== Assign new processor to a core =====================
   2.255 -   #ifdef SEQUENTIAL
   2.256 -   newPr->coreAnimatedBy = 0;
   2.257 -
   2.258 -   #else
   2.259 -
   2.260 -   if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES )
   2.261 -    {    //out-of-range, so round-robin assignment
   2.262 -      newPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr;
   2.263 -
   2.264 -      if( semEnv->nextCoreToGetNewPr >= NUM_CORES - 1 )
   2.265 -          semEnv->nextCoreToGetNewPr  = 0;
   2.266 -      else
   2.267 -          semEnv->nextCoreToGetNewPr += 1;
   2.268 -    }
   2.269 -   else //core num in-range, so use it
   2.270 -    { newPr->coreAnimatedBy = coreToScheduleOnto;
   2.271 -    }
   2.272 -   #endif
   2.273 -   //========================================================================
   2.274 -
   2.275 -   return newPr;
   2.276 - }
   2.277 -
   2.278 -
   2.279 -void inline
   2.280 -handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.281 - { VCilkSemReq *semReq;
   2.282 -   VirtProcr    *newPr;
   2.283 -
   2.284 -         Meas_startSpawn
   2.285 -   semReq = VMS__take_sem_reqst_from( req );
   2.286 -
   2.287 -   newPr = VCilk__create_procr_helper( semReq->fnPtr, semReq->initData,
   2.288 -                             requestingPr, semEnv, semReq->coreToSpawnOnto );
   2.289 -
   2.290 -      //For VPThread, caller needs ptr to created processor returned to it
   2.291 -   requestingPr->dataRetFromReq = newPr;
   2.292 -
   2.293 -   resume_procr( newPr,        semEnv );
   2.294 -   resume_procr( requestingPr, semEnv );
   2.295 -         Meas_endSpawn
   2.296 - }
   2.297 -
   2.298 -
   2.299 -
   2.300 -/*get parentVP & remove dissipator from parent's live children.
   2.301 - *If this was last live child, check "sync pending" flag
   2.302 - *-- if set, then resume the parentVP.
   2.303 - */
   2.304 -void inline
   2.305 -handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.306 - {
   2.307 -   VirtProcr *
   2.308 -   parentPr = ((VCilkSemData *)
   2.309 -               (requestingPr->semanticData))->parentPr;
   2.310 -   if( parentPr == NULL ) //means this is seed processor being dissipated
   2.311 -    { //Just act normally, except don't deal with parent
   2.312 -      // VMS__Free is implemented to ignore requests to free data from
   2.313 -      // outside VMS, so all this processor's non-VMS allocated data will
   2.314 -      // remain and be cleaned up outside
   2.315 -    }
   2.316 -   else
   2.317 -    {
   2.318 -      ((VCilkSemData *)(parentPr->semanticData))->numLiveChildren -= 1;
   2.319 -      if( ((VCilkSemData *)
   2.320 -            (parentPr->semanticData))->numLiveChildren <= 0 )
   2.321 -       { //this was last live child of parent
   2.322 -         if( ((VCilkSemData *)
   2.323 -               (parentPr->semanticData))->syncPending == TRUE )
   2.324 -          { //was waiting for last child to dissipate, so resume it
   2.325 -            ((VCilkSemData *)
   2.326 -              (parentPr->semanticData))->syncPending = FALSE;
   2.327 -            resume_procr( parentPr, semEnv );
   2.328 -          }
   2.329 -       }
   2.330 -    }
   2.331 -
   2.332 -   VMS__free( requestingPr->semanticData );
   2.333 -   
   2.334 -       //Now do normal dissipate
   2.335 -   
   2.336 -       //call VMS to free_all AppVP state -- stack and so on
   2.337 -   VMS__dissipate_procr( requestingPr );
   2.338 -
   2.339 -   semEnv->numVirtPr -= 1;
   2.340 -   if( semEnv->numVirtPr == 0 )
   2.341 -    {    //no more work, so shutdown
   2.342 -      VMS__shutdown();
   2.343 -    }
   2.344 - }
   2.345 -
   2.346 -
   2.347 -//=============================== Atomic ====================================
   2.348 -//
   2.349 -/*Uses ID as index into array of flags.  If flag already set, resumes from
   2.350 - * end-label.  Else, sets flag and resumes normally.
   2.351 - */
   2.352 -void inline
   2.353 -handleStartSingleton_helper( VCilkSingleton *singleton, VirtProcr *reqstingPr,
   2.354 -                             VCilkSemEnv    *semEnv )
   2.355 - {
   2.356 -   if( singleton->hasFinished )
   2.357 -    {    //the code that sets the flag to true first sets the end instr addr
   2.358 -      reqstingPr->dataRetFromReq = singleton->endInstrAddr;
   2.359 -      resume_procr( reqstingPr, semEnv );
   2.360 -      return;
   2.361 -    }
   2.362 -   else if( singleton->hasBeenStarted )
   2.363 -    {    //singleton is in-progress in a diff slave, so wait for it to finish
   2.364 -      writePrivQ(reqstingPr, singleton->waitQ );
   2.365 -      return;
   2.366 -    }
   2.367 -   else
   2.368 -    {    //hasn't been started, so this is the first attempt at the singleton
   2.369 -      singleton->hasBeenStarted = TRUE;
   2.370 -      reqstingPr->dataRetFromReq = 0x0;
   2.371 -      resume_procr( reqstingPr, semEnv );
   2.372 -      return;
   2.373 -    }
   2.374 - }
   2.375 -void inline
   2.376 -handleStartFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.377 -                      VCilkSemEnv *semEnv )
   2.378 - { VCilkSingleton *singleton;
   2.379 -
   2.380 -   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
   2.381 -   handleStartSingleton_helper( singleton, requestingPr, semEnv );
   2.382 - }
   2.383 -void inline
   2.384 -handleStartDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.385 -                      VCilkSemEnv *semEnv )
   2.386 - { VCilkSingleton *singleton;
   2.387 -
   2.388 -   if( *(semReq->singletonPtrAddr) == NULL )
   2.389 -    { singleton                 = VMS__malloc( sizeof(VCilkSingleton) );
   2.390 -      singleton->waitQ          = makeVMSPrivQ();
   2.391 -      singleton->endInstrAddr   = 0x0;
   2.392 -      singleton->hasBeenStarted = FALSE;
   2.393 -      singleton->hasFinished    = FALSE;
   2.394 -      *(semReq->singletonPtrAddr)  = singleton;
   2.395 -    }
   2.396 -   else
   2.397 -      singleton = *(semReq->singletonPtrAddr);
   2.398 -   handleStartSingleton_helper( singleton, requestingPr, semEnv );
   2.399 - }
   2.400 -
   2.401 -
   2.402 -void inline
   2.403 -handleEndSingleton_helper( VCilkSingleton *singleton, VirtProcr *requestingPr,
   2.404 -                           VCilkSemEnv    *semEnv )
   2.405 - { PrivQueueStruc *waitQ;
   2.406 -   int32           numWaiting, i;
   2.407 -   VirtProcr      *resumingPr;
   2.408 -
   2.409 -   if( singleton->hasFinished )
   2.410 -    { //by definition, only one slave should ever be able to run end singleton
   2.411 -      // so if this is true, is an error
   2.412 -      //VMS__throw_exception( "singleton code ran twice", requestingPr, NULL);
   2.413 -    }
   2.414 -
   2.415 -   singleton->hasFinished = TRUE;
   2.416 -   waitQ = singleton->waitQ;
   2.417 -   numWaiting = numInPrivQ( waitQ );
   2.418 -   for( i = 0; i < numWaiting; i++ )
   2.419 -    {    //they will resume inside start singleton, then jmp to end singleton
   2.420 -      resumingPr = readPrivQ( waitQ );
   2.421 -      resumingPr->dataRetFromReq = singleton->endInstrAddr;
   2.422 -      resume_procr( resumingPr, semEnv );
   2.423 -    }
   2.424 -
   2.425 -   resume_procr( requestingPr, semEnv );
   2.426 -
   2.427 -}
   2.428 -void inline
   2.429 -handleEndFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.430 -                        VCilkSemEnv *semEnv )
   2.431 - {
   2.432 -   VCilkSingleton   *singleton;
   2.433 -
   2.434 -   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
   2.435 -   handleEndSingleton_helper( singleton, requestingPr, semEnv );
   2.436 -  }
   2.437 -void inline
   2.438 -handleEndDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.439 -                        VCilkSemEnv *semEnv )
   2.440 - {
   2.441 -   VCilkSingleton   *singleton;
   2.442 -
   2.443 -   singleton = *(semReq->singletonPtrAddr);
   2.444 -   handleEndSingleton_helper( singleton, requestingPr, semEnv );
   2.445 -  }
   2.446 -
   2.447 -
   2.448 -/*This executes the function in the masterVP, take the function
   2.449 - * pointer out of the request and call it, then resume the VP.
   2.450 - */
   2.451 -void inline
   2.452 -handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.453 -              VCilkSemEnv *semEnv )
   2.454 - {
   2.455 -   semReq->fnToExecInMaster( semReq->dataForFn );
   2.456 -   resume_procr( requestingPr, semEnv );
   2.457 - }
   2.458 -
   2.459 -/*First, it looks at the VP's semantic data, to see the highest transactionID
   2.460 - * that VP
   2.461 - * already has entered.  If the current ID is not larger, it throws an
   2.462 - * exception stating a bug in the code.
   2.463 - *Otherwise it puts the current ID
   2.464 - * there, and adds the ID to a linked list of IDs entered -- the list is
   2.465 - * used to check that exits are properly ordered.
   2.466 - *Next it is uses transactionID as index into an array of transaction
   2.467 - * structures.
   2.468 - *If the "VP_currently_executing" field is non-null, then put requesting VP
   2.469 - * into queue in the struct.  (At some point a holder will request
   2.470 - * end-transaction, which will take this VP from the queue and resume it.)
   2.471 - *If NULL, then write requesting into the field and resume.
   2.472 - */
   2.473 -void inline
   2.474 -handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.475 -                  VCilkSemEnv *semEnv )
   2.476 - { VCilkSemData *semData;
   2.477 -   TransListElem *nextTransElem;
   2.478 -
   2.479 -      //check ordering of entering transactions is correct
   2.480 -   semData = requestingPr->semanticData;
   2.481 -   if( semData->highestTransEntered > semReq->transID )
   2.482 -    {    //throw VMS exception, which shuts down VMS.
   2.483 -      VMS__throw_exception( "transID smaller than prev", requestingPr, NULL);
   2.484 -    }
   2.485 -      //add this trans ID to the list of transactions entered -- check when
   2.486 -      // end a transaction
   2.487 -   semData->highestTransEntered = semReq->transID;
   2.488 -   nextTransElem = VMS__malloc( sizeof(TransListElem) );
   2.489 -   nextTransElem->transID = semReq->transID;
   2.490 -   nextTransElem->nextTrans = semData->lastTransEntered;
   2.491 -   semData->lastTransEntered = nextTransElem;
   2.492 -
   2.493 -      //get the structure for this transaction ID
   2.494 -   VCilkTrans *
   2.495 -   transStruc = &(semEnv->transactionStrucs[ semReq->transID ]);
   2.496 -
   2.497 -   if( transStruc->VPCurrentlyExecuting == NULL )
   2.498 -    {
   2.499 -      transStruc->VPCurrentlyExecuting = requestingPr;
   2.500 -      resume_procr( requestingPr, semEnv );
   2.501 -    }
   2.502 -   else
   2.503 -    {    //note, might make future things cleaner if save request with VP and
   2.504 -         // add this trans ID to the linked list when gets out of queue.
   2.505 -         // but don't need for now, and lazy..
   2.506 -      writePrivQ( requestingPr, transStruc->waitingVPQ );
   2.507 -    }
   2.508 - }
   2.509 -
   2.510 -
   2.511 -/*Use the trans ID to get the transaction structure from the array.
   2.512 - *Look at VP_currently_executing to be sure it's same as requesting VP.
   2.513 - * If different, throw an exception, stating there's a bug in the code.
   2.514 - *Next, take the first element off the list of entered transactions.
   2.515 - * Check to be sure the ending transaction is the same ID as the next on
   2.516 - * the list.  If not, incorrectly nested so throw an exception.
   2.517 - *
   2.518 - *Next, get from the queue in the structure.
   2.519 - *If it's empty, set VP_currently_executing field to NULL and resume
   2.520 - * requesting VP.
   2.521 - *If get somethine, set VP_currently_executing to the VP from the queue, then
   2.522 - * resume both.
   2.523 - */
   2.524 -void inline
   2.525 -handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.526 -                VCilkSemEnv *semEnv )
   2.527 - { VCilkSemData    *semData;
   2.528 -   VirtProcr     *waitingPr;
   2.529 -   VCilkTrans      *transStruc;
   2.530 -   TransListElem *lastTrans;
   2.531 -
   2.532 -   transStruc = &(semEnv->transactionStrucs[ semReq->transID ]);
   2.533 -
   2.534 -      //make sure transaction ended in same VP as started it.
   2.535 -   if( transStruc->VPCurrentlyExecuting != requestingPr )
   2.536 -    {
   2.537 -      VMS__throw_exception( "trans ended in diff VP", requestingPr, NULL );
   2.538 -    }
   2.539 -
   2.540 -      //make sure nesting is correct -- last ID entered should == this ID
   2.541 -   semData = requestingPr->semanticData;
   2.542 -   lastTrans = semData->lastTransEntered;
   2.543 -   if( lastTrans->transID != semReq->transID )
   2.544 -    {
   2.545 -      VMS__throw_exception( "trans incorrectly nested", requestingPr, NULL );
   2.546 -    }
   2.547 -
   2.548 -   semData->lastTransEntered = semData->lastTransEntered->nextTrans;
   2.549 -
   2.550 -
   2.551 -   waitingPr = readPrivQ( transStruc->waitingVPQ );
   2.552 -   transStruc->VPCurrentlyExecuting = waitingPr;
   2.553 -
   2.554 -   if( waitingPr != NULL )
   2.555 -      resume_procr( waitingPr, semEnv );
   2.556 -
   2.557 -   resume_procr( requestingPr, semEnv );
   2.558 - }
   2.559 +/*
   2.560 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
   2.561 + *
   2.562 + * Licensed under BSD
   2.563 + */
   2.564 +
   2.565 +#include <stdio.h>
   2.566 +#include <stdlib.h>
   2.567 +
   2.568 +#include "VMS/Queue_impl/PrivateQueue.h"
   2.569 +#include "VCilk.h"
   2.570 +
   2.571 +
   2.572 +
   2.573 +//===========================================================================
   2.574 +void inline
   2.575 +handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv );
   2.576 +
   2.577 +void inline
   2.578 +handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.579 +              VCilkSemEnv *semEnv );
   2.580 +void inline
   2.581 +handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.582 +            VCilkSemEnv *semEnv );
   2.583 +void inline
   2.584 +handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv );
   2.585 +
   2.586 +void inline
   2.587 +handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv );
   2.588 +
   2.589 +void inline
   2.590 +dispatchSemReq( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv);
   2.591 +
   2.592 +void inline
   2.593 +handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.594 +                VCilkSemEnv*semEnv);
   2.595 +void inline
   2.596 +handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.597 +                  VCilkSemEnv *semEnv );
   2.598 +void inline
   2.599 +handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.600 +              VCilkSemEnv *semEnv);
   2.601 +inline void
   2.602 +handleStartFnSingleton( VCilkSemReq *semReq, VirtProcr *reqstingPr,
   2.603 +                      VCilkSemEnv *semEnv );
   2.604 +inline void
   2.605 +handleEndFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.606 +                    VCilkSemEnv *semEnv );
   2.607 +inline void
   2.608 +handleStartDataSingleton( VCilkSemReq *semReq, VirtProcr *reqstingPr,
   2.609 +                      VCilkSemEnv *semEnv );
   2.610 +inline void
   2.611 +handleEndDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.612 +                    VCilkSemEnv *semEnv );
   2.613 +
   2.614 +void inline
   2.615 +resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv );
   2.616 +
   2.617 +//===========================================================================
   2.618 +
   2.619 +
   2.620 +//============================== Scheduler ==================================
   2.621 +//
   2.622 +/*For VCilk, scheduling a slave simply takes the next work-unit off the
   2.623 + * ready-to-go work-unit queue and assigns it to the slaveToSched.
   2.624 + *If the ready-to-go work-unit queue is empty, then nothing to schedule
   2.625 + * to the slave -- return FALSE to let Master loop know scheduling that
   2.626 + * slave failed.
   2.627 + */
   2.628 +VirtProcr *
   2.629 +VCilk__schedule_virt_procr( void *_semEnv, int coreNum )
   2.630 + { VirtProcr   *schedPr;
   2.631 +   VCilkSemEnv *semEnv;
   2.632 +
   2.633 +   semEnv = (VCilkSemEnv *)_semEnv;
   2.634 +
   2.635 +   schedPr = readPrivQ( semEnv->readyVPQs[coreNum] );
   2.636 +      //Note, using a non-blocking queue -- it returns NULL if queue empty
   2.637 +
   2.638 +   return( schedPr );
   2.639 + }
   2.640 +
   2.641 +
   2.642 +//===========================  Request Handler  =============================
   2.643 +//
   2.644 +/*Will get requests to send, to receive, and to create new processors.
   2.645 + * Upon send, check the hash to see if a receive is waiting.
   2.646 + * Upon receive, check hash to see if a send has already happened.
   2.647 + * When other is not there, put in.  When other is there, the comm.
   2.648 + *  completes, which means the receiver P gets scheduled and
   2.649 + *  picks up right after the receive request.  So make the work-unit
   2.650 + *  and put it into the queue of work-units ready to go.
   2.651 + * Other request is create a new Processor, with the function to run in the
   2.652 + *  Processor, and initial data.
   2.653 + */
   2.654 +void
   2.655 +VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv )
   2.656 + { VCilkSemEnv *semEnv;
   2.657 +   VMSReqst    *req;
   2.658 +   VCilkSemReq *semReq;
   2.659 + 
   2.660 +
   2.661 +   semEnv = (VCilkSemEnv *)_semEnv;
   2.662 +
   2.663 +   req = VMS__take_next_request_out_of( requestingPr );
   2.664 +   
   2.665 +   while( req != NULL )
   2.666 +    {
   2.667 +      switch( req->reqType )
   2.668 +       { case semantic:     dispatchSemReq( req, requestingPr, semEnv );
   2.669 +            break;
   2.670 +         case createReq:    //create request has to come as a VMS request,
   2.671 +                            // to allow MasterLoop to do stuff before gets
   2.672 +                            // here, and maybe also stuff after all requests
   2.673 +                            // done -- however, can still attach semantic
   2.674 +                            // req data to req.
   2.675 +                            handleSpawn(          req, requestingPr, semEnv);
   2.676 +            break;
   2.677 +         case dissipate:    handleDissipate(           requestingPr, semEnv);
   2.678 +            break;
   2.679 +         case VMSSemantic:  VMS__handle_VMSSemReq(req, requestingPr, semEnv,
   2.680 +                                                              &resume_procr);
   2.681 +            break;
   2.682 +         default:
   2.683 +            break;
   2.684 +       }
   2.685 +      
   2.686 +      DoneHandlingReqst:
   2.687 +
   2.688 +      req = VMS__take_next_request_out_of( requestingPr );
   2.689 +    } //while( req != NULL )
   2.690 + }
   2.691 +
   2.692 +void inline
   2.693 +dispatchSemReq( VMSReqst *req, VirtProcr *reqPr, VCilkSemEnv *semEnv )
   2.694 + { VCilkSemReq *semReq;
   2.695 +
   2.696 +   semReq = VMS__take_sem_reqst_from(req);
   2.697 +
   2.698 +   if( semReq == NULL ) return;
   2.699 +   switch( semReq->reqType )
   2.700 +    {
   2.701 +      case syncReq:         handleSync(                 reqPr, semEnv );
   2.702 +         break;
   2.703 +      case mallocReq:       handleMalloc(       semReq, reqPr, semEnv );
   2.704 +         break;
   2.705 +      case freeReq:         handleFree(         semReq, reqPr, semEnv );
   2.706 +         break;
   2.707 +      case singleton_fn_start:  handleStartFnSingleton(semReq, reqPr, semEnv);
   2.708 +         break;
   2.709 +      case singleton_fn_end:    handleEndFnSingleton(  semReq, reqPr, semEnv);
   2.710 +         break;
   2.711 +      case singleton_data_start:handleStartDataSingleton(semReq,reqPr,semEnv);
   2.712 +         break;
   2.713 +      case singleton_data_end:  handleEndDataSingleton(semReq, reqPr, semEnv);
   2.714 +         break;
   2.715 +      case atomic:          handleAtomic(       semReq, reqPr, semEnv );
   2.716 +         break;
   2.717 +      case trans_start:     handleTransStart(   semReq, reqPr, semEnv );
   2.718 +         break;
   2.719 +      case trans_end:       handleTransEnd(     semReq, reqPr, semEnv );
   2.720 +         break;
   2.721 +    }
   2.722 +   //NOTE: semantic request data strucs allocated on stack in VCilk Lib calls
   2.723 + }
   2.724 +
   2.725 +
   2.726 +
   2.727 +//=========================== Request Handlers ==============================
   2.728 +void inline
   2.729 +resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv )
   2.730 + {
   2.731 +   writePrivQ( procr, semEnv->readyVPQs[ procr->coreAnimatedBy] );
   2.732 + }
   2.733 +
   2.734 +
   2.735 +
   2.736 +
   2.737 +/* check if list of live children is empty.
   2.738 + * If yes, then resume.
   2.739 + * If no, then set sync-pending flag.
   2.740 + */
   2.741 +inline void
   2.742 +handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.743 + {
   2.744 +         Meas_startSync
   2.745 +   if(((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren  == 0 )
   2.746 +    { //no live children to wait for
   2.747 +      resume_procr( requestingPr, semEnv );
   2.748 +    }
   2.749 +   else
   2.750 +    {
   2.751 +      ((VCilkSemData *)(requestingPr->semanticData))->syncPending = TRUE;
   2.752 +    }
   2.753 +         Meas_endSync
   2.754 + }
   2.755 +
   2.756 +/*
   2.757 + */
   2.758 +inline void
   2.759 +handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.760 +              VCilkSemEnv *semEnv )
   2.761 + { void *ptr;
   2.762 +   
   2.763 +   ptr = VMS__malloc( semReq->sizeToMalloc );
   2.764 +   requestingPr->dataRetFromReq = ptr;
   2.765 +   resume_procr( requestingPr, semEnv );
   2.766 + }
   2.767 +
   2.768 +/*
   2.769 + */
   2.770 +void inline
   2.771 +handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.772 +            VCilkSemEnv *semEnv )
   2.773 + {
   2.774 +   VMS__free( semReq->ptrToFree );
   2.775 +   resume_procr( requestingPr, semEnv );
   2.776 + }
   2.777 +
   2.778 +
   2.779 +//============================== VMS requests ===============================
   2.780 +/*Re-use this in the entry-point fn
   2.781 + */
   2.782 +inline VirtProcr *
   2.783 +VCilk__create_procr_helper( VirtProcrFnPtr fnPtr, void  *initData,
   2.784 +   VirtProcr *requestingPr, VCilkSemEnv *semEnv,  int32  coreToScheduleOnto )
   2.785 + { VirtProcr    *newPr;
   2.786 +   VCilkSemData *semData;
   2.787 +
   2.788 +      //This is running in master, so use internal version
   2.789 +   newPr = VMS__create_procr( fnPtr, initData );
   2.790 +
   2.791 +   semData = VMS__malloc( sizeof(VCilkSemData) );
   2.792 +
   2.793 +   semData->numLiveChildren = 0;
   2.794 +   semData->parentPr        = requestingPr;
   2.795 +   semData->syncPending     = FALSE;
   2.796 +   
   2.797 +   semData->highestTransEntered = -1;
   2.798 +   semData->lastTransEntered    = NULL;
   2.799 +
   2.800 +   newPr->semanticData = semData;
   2.801 +
   2.802 +   /* increase the number of live children of requester.
   2.803 +    */
   2.804 +   if( requestingPr != NULL ) //NULL when creating seed procr
   2.805 +     ((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren +=1;
   2.806 +
   2.807 +   semEnv->numVirtPr += 1;
   2.808 +
   2.809 +   //=================== Assign new processor to a core =====================
   2.810 +   #ifdef SEQUENTIAL
   2.811 +   newPr->coreAnimatedBy = 0;
   2.812 +
   2.813 +   #else
   2.814 +
   2.815 +   if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES )
   2.816 +    {    //out-of-range, so round-robin assignment
   2.817 +      newPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr;
   2.818 +
   2.819 +      if( semEnv->nextCoreToGetNewPr >= NUM_CORES - 1 )
   2.820 +          semEnv->nextCoreToGetNewPr  = 0;
   2.821 +      else
   2.822 +          semEnv->nextCoreToGetNewPr += 1;
   2.823 +    }
   2.824 +   else //core num in-range, so use it
   2.825 +    { newPr->coreAnimatedBy = coreToScheduleOnto;
   2.826 +    }
   2.827 +   #endif
   2.828 +   //========================================================================
   2.829 +
   2.830 +   return newPr;
   2.831 + }
   2.832 +
   2.833 +
   2.834 +void inline
   2.835 +handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.836 + { VCilkSemReq *semReq;
   2.837 +   VirtProcr    *newPr;
   2.838 +
   2.839 +         Meas_startSpawn
   2.840 +   semReq = VMS__take_sem_reqst_from( req );
   2.841 +
   2.842 +   newPr = VCilk__create_procr_helper( semReq->fnPtr, semReq->initData,
   2.843 +                             requestingPr, semEnv, semReq->coreToSpawnOnto );
   2.844 +
   2.845 +      //For VPThread, caller needs ptr to created processor returned to it
   2.846 +   requestingPr->dataRetFromReq = newPr;
   2.847 +
   2.848 +   resume_procr( newPr,        semEnv );
   2.849 +   resume_procr( requestingPr, semEnv );
   2.850 +         Meas_endSpawn
   2.851 + }
   2.852 +
   2.853 +
   2.854 +
   2.855 +/*get parentVP & remove dissipator from parent's live children.
   2.856 + *If this was last live child, check "sync pending" flag
   2.857 + *-- if set, then resume the parentVP.
   2.858 + */
   2.859 +void inline
   2.860 +handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.861 + {
   2.862 +   VirtProcr *
   2.863 +   parentPr = ((VCilkSemData *)
   2.864 +               (requestingPr->semanticData))->parentPr;
   2.865 +   if( parentPr == NULL ) //means this is seed processor being dissipated
   2.866 +    { //Just act normally, except don't deal with parent
   2.867 +      // VMS__Free is implemented to ignore requests to free data from
   2.868 +      // outside VMS, so all this processor's non-VMS allocated data will
   2.869 +      // remain and be cleaned up outside
   2.870 +    }
   2.871 +   else
   2.872 +    {
   2.873 +      ((VCilkSemData *)(parentPr->semanticData))->numLiveChildren -= 1;
   2.874 +      if( ((VCilkSemData *)
   2.875 +            (parentPr->semanticData))->numLiveChildren <= 0 )
   2.876 +       { //this was last live child of parent
   2.877 +         if( ((VCilkSemData *)
   2.878 +               (parentPr->semanticData))->syncPending == TRUE )
   2.879 +          { //was waiting for last child to dissipate, so resume it
   2.880 +            ((VCilkSemData *)
   2.881 +              (parentPr->semanticData))->syncPending = FALSE;
   2.882 +            resume_procr( parentPr, semEnv );
   2.883 +          }
   2.884 +       }
   2.885 +    }
   2.886 +
   2.887 +   VMS__free( requestingPr->semanticData );
   2.888 +   
   2.889 +       //Now do normal dissipate
   2.890 +   
   2.891 +       //call VMS to free_all AppVP state -- stack and so on
   2.892 +   VMS__dissipate_procr( requestingPr );
   2.893 +
   2.894 +   semEnv->numVirtPr -= 1;
   2.895 +   if( semEnv->numVirtPr == 0 )
   2.896 +    {    //no more work, so shutdown
   2.897 +      VMS__shutdown();
   2.898 +    }
   2.899 + }
   2.900 +
   2.901 +
   2.902 +//=============================== Atomic ====================================
   2.903 +//
   2.904 +/*Uses ID as index into array of flags.  If flag already set, resumes from
   2.905 + * end-label.  Else, sets flag and resumes normally.
   2.906 + */
   2.907 +void inline
   2.908 +handleStartSingleton_helper( VCilkSingleton *singleton, VirtProcr *reqstingPr,
   2.909 +                             VCilkSemEnv    *semEnv )
   2.910 + {
   2.911 +   if( singleton->hasFinished )
   2.912 +    {    //the code that sets the flag to true first sets the end instr addr
   2.913 +      reqstingPr->dataRetFromReq = singleton->endInstrAddr;
   2.914 +      resume_procr( reqstingPr, semEnv );
   2.915 +      return;
   2.916 +    }
   2.917 +   else if( singleton->hasBeenStarted )
   2.918 +    {    //singleton is in-progress in a diff slave, so wait for it to finish
   2.919 +      writePrivQ(reqstingPr, singleton->waitQ );
   2.920 +      return;
   2.921 +    }
   2.922 +   else
   2.923 +    {    //hasn't been started, so this is the first attempt at the singleton
   2.924 +      singleton->hasBeenStarted = TRUE;
   2.925 +      reqstingPr->dataRetFromReq = 0x0;
   2.926 +      resume_procr( reqstingPr, semEnv );
   2.927 +      return;
   2.928 +    }
   2.929 + }
   2.930 +void inline
   2.931 +handleStartFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.932 +                      VCilkSemEnv *semEnv )
   2.933 + { VCilkSingleton *singleton;
   2.934 +
   2.935 +   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
   2.936 +   handleStartSingleton_helper( singleton, requestingPr, semEnv );
   2.937 + }
   2.938 +void inline
   2.939 +handleStartDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.940 +                      VCilkSemEnv *semEnv )
   2.941 + { VCilkSingleton *singleton;
   2.942 +
   2.943 +   if( *(semReq->singletonPtrAddr) == NULL )
   2.944 +    { singleton                 = VMS__malloc( sizeof(VCilkSingleton) );
   2.945 +      singleton->waitQ          = makeVMSPrivQ();
   2.946 +      singleton->endInstrAddr   = 0x0;
   2.947 +      singleton->hasBeenStarted = FALSE;
   2.948 +      singleton->hasFinished    = FALSE;
   2.949 +      *(semReq->singletonPtrAddr)  = singleton;
   2.950 +    }
   2.951 +   else
   2.952 +      singleton = *(semReq->singletonPtrAddr);
   2.953 +   handleStartSingleton_helper( singleton, requestingPr, semEnv );
   2.954 + }
   2.955 +
   2.956 +
   2.957 +void inline
   2.958 +handleEndSingleton_helper( VCilkSingleton *singleton, VirtProcr *requestingPr,
   2.959 +                           VCilkSemEnv    *semEnv )
   2.960 + { PrivQueueStruc *waitQ;
   2.961 +   int32           numWaiting, i;
   2.962 +   VirtProcr      *resumingPr;
   2.963 +
   2.964 +   if( singleton->hasFinished )
   2.965 +    { //by definition, only one slave should ever be able to run end singleton
   2.966 +      // so if this is true, is an error
   2.967 +      //VMS__throw_exception( "singleton code ran twice", requestingPr, NULL);
   2.968 +    }
   2.969 +
   2.970 +   singleton->hasFinished = TRUE;
   2.971 +   waitQ = singleton->waitQ;
   2.972 +   numWaiting = numInPrivQ( waitQ );
   2.973 +   for( i = 0; i < numWaiting; i++ )
   2.974 +    {    //they will resume inside start singleton, then jmp to end singleton
   2.975 +      resumingPr = readPrivQ( waitQ );
   2.976 +      resumingPr->dataRetFromReq = singleton->endInstrAddr;
   2.977 +      resume_procr( resumingPr, semEnv );
   2.978 +    }
   2.979 +
   2.980 +   resume_procr( requestingPr, semEnv );
   2.981 +
   2.982 +}
   2.983 +void inline
   2.984 +handleEndFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.985 +                        VCilkSemEnv *semEnv )
   2.986 + {
   2.987 +   VCilkSingleton   *singleton;
   2.988 +
   2.989 +   singleton = &(semEnv->fnSingletons[ semReq->singletonID ]);
   2.990 +   handleEndSingleton_helper( singleton, requestingPr, semEnv );
   2.991 +  }
   2.992 +void inline
   2.993 +handleEndDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.994 +                        VCilkSemEnv *semEnv )
   2.995 + {
   2.996 +   VCilkSingleton   *singleton;
   2.997 +
   2.998 +   singleton = *(semReq->singletonPtrAddr);
   2.999 +   handleEndSingleton_helper( singleton, requestingPr, semEnv );
  2.1000 +  }
  2.1001 +
  2.1002 +
  2.1003 +/*This executes the function in the masterVP, take the function
  2.1004 + * pointer out of the request and call it, then resume the VP.
  2.1005 + */
  2.1006 +void inline
  2.1007 +handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr,
  2.1008 +              VCilkSemEnv *semEnv )
  2.1009 + {
  2.1010 +   semReq->fnToExecInMaster( semReq->dataForFn );
  2.1011 +   resume_procr( requestingPr, semEnv );
  2.1012 + }
  2.1013 +
  2.1014 +/*First, it looks at the VP's semantic data, to see the highest transactionID
  2.1015 + * that VP
  2.1016 + * already has entered.  If the current ID is not larger, it throws an
  2.1017 + * exception stating a bug in the code.
  2.1018 + *Otherwise it puts the current ID
  2.1019 + * there, and adds the ID to a linked list of IDs entered -- the list is
  2.1020 + * used to check that exits are properly ordered.
  2.1021 + *Next it is uses transactionID as index into an array of transaction
  2.1022 + * structures.
  2.1023 + *If the "VP_currently_executing" field is non-null, then put requesting VP
  2.1024 + * into queue in the struct.  (At some point a holder will request
  2.1025 + * end-transaction, which will take this VP from the queue and resume it.)
  2.1026 + *If NULL, then write requesting into the field and resume.
  2.1027 + */
  2.1028 +void inline
  2.1029 +handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr,
  2.1030 +                  VCilkSemEnv *semEnv )
  2.1031 + { VCilkSemData *semData;
  2.1032 +   TransListElem *nextTransElem;
  2.1033 +
  2.1034 +      //check ordering of entering transactions is correct
  2.1035 +   semData = requestingPr->semanticData;
  2.1036 +   if( semData->highestTransEntered > semReq->transID )
  2.1037 +    {    //throw VMS exception, which shuts down VMS.
  2.1038 +      VMS__throw_exception( "transID smaller than prev", requestingPr, NULL);
  2.1039 +    }
  2.1040 +      //add this trans ID to the list of transactions entered -- check when
  2.1041 +      // end a transaction
  2.1042 +   semData->highestTransEntered = semReq->transID;
  2.1043 +   nextTransElem = VMS__malloc( sizeof(TransListElem) );
  2.1044 +   nextTransElem->transID = semReq->transID;
  2.1045 +   nextTransElem->nextTrans = semData->lastTransEntered;
  2.1046 +   semData->lastTransEntered = nextTransElem;
  2.1047 +
  2.1048 +      //get the structure for this transaction ID
  2.1049 +   VCilkTrans *
  2.1050 +   transStruc = &(semEnv->transactionStrucs[ semReq->transID ]);
  2.1051 +
  2.1052 +   if( transStruc->VPCurrentlyExecuting == NULL )
  2.1053 +    {
  2.1054 +      transStruc->VPCurrentlyExecuting = requestingPr;
  2.1055 +      resume_procr( requestingPr, semEnv );
  2.1056 +    }
  2.1057 +   else
  2.1058 +    {    //note, might make future things cleaner if save request with VP and
  2.1059 +         // add this trans ID to the linked list when gets out of queue.
  2.1060 +         // but don't need for now, and lazy..
  2.1061 +      writePrivQ( requestingPr, transStruc->waitingVPQ );
  2.1062 +    }
  2.1063 + }
  2.1064 +
  2.1065 +
  2.1066 +/*Use the trans ID to get the transaction structure from the array.
  2.1067 + *Look at VP_currently_executing to be sure it's same as requesting VP.
  2.1068 + * If different, throw an exception, stating there's a bug in the code.
  2.1069 + *Next, take the first element off the list of entered transactions.
  2.1070 + * Check to be sure the ending transaction is the same ID as the next on
  2.1071 + * the list.  If not, incorrectly nested so throw an exception.
  2.1072 + *
  2.1073 + *Next, get from the queue in the structure.
  2.1074 + *If it's empty, set VP_currently_executing field to NULL and resume
  2.1075 + * requesting VP.
  2.1076 + *If get somethine, set VP_currently_executing to the VP from the queue, then
  2.1077 + * resume both.
  2.1078 + */
  2.1079 +void inline
  2.1080 +handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr,
  2.1081 +                VCilkSemEnv *semEnv )
  2.1082 + { VCilkSemData    *semData;
  2.1083 +   VirtProcr     *waitingPr;
  2.1084 +   VCilkTrans      *transStruc;
  2.1085 +   TransListElem *lastTrans;
  2.1086 +
  2.1087 +   transStruc = &(semEnv->transactionStrucs[ semReq->transID ]);
  2.1088 +
  2.1089 +      //make sure transaction ended in same VP as started it.
  2.1090 +   if( transStruc->VPCurrentlyExecuting != requestingPr )
  2.1091 +    {
  2.1092 +      VMS__throw_exception( "trans ended in diff VP", requestingPr, NULL );
  2.1093 +    }
  2.1094 +
  2.1095 +      //make sure nesting is correct -- last ID entered should == this ID
  2.1096 +   semData = requestingPr->semanticData;
  2.1097 +   lastTrans = semData->lastTransEntered;
  2.1098 +   if( lastTrans->transID != semReq->transID )
  2.1099 +    {
  2.1100 +      VMS__throw_exception( "trans incorrectly nested", requestingPr, NULL );
  2.1101 +    }
  2.1102 +
  2.1103 +   semData->lastTransEntered = semData->lastTransEntered->nextTrans;
  2.1104 +
  2.1105 +
  2.1106 +   waitingPr = readPrivQ( transStruc->waitingVPQ );
  2.1107 +   transStruc->VPCurrentlyExecuting = waitingPr;
  2.1108 +
  2.1109 +   if( waitingPr != NULL )
  2.1110 +      resume_procr( waitingPr, semEnv );
  2.1111 +
  2.1112 +   resume_procr( requestingPr, semEnv );
  2.1113 + }
     3.1 --- a/VCilk_lib.c	Wed May 11 15:29:58 2011 +0200
     3.2 +++ b/VCilk_lib.c	Wed May 11 16:11:06 2011 +0200
     3.3 @@ -1,539 +1,539 @@
     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 -
    3.13 -#include "VMS/VMS.h"
    3.14 -#include "VCilk.h"
    3.15 -#include "VMS/Queue_impl/PrivateQueue.h"
    3.16 -#include "VMS/Hash_impl/PrivateHash.h"
    3.17 -
    3.18 -
    3.19 -//==========================================================================
    3.20 -
    3.21 -void
    3.22 -VCilk__init();
    3.23 -
    3.24 -void
    3.25 -VCilk__init_Seq();
    3.26 -
    3.27 -void
    3.28 -VCilk__init_Helper();
    3.29 -//==========================================================================
    3.30 -
    3.31 -
    3.32 -/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR
    3.33 - * (still want to do FoR, with time-lines as syntax, could be super cool)
    3.34 - * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate
    3.35 - * among library, DKU, WT, FoR -- all the patterns in terms of virtual
    3.36 - * processors (or equivalently work-units), so Master picks which virt procr
    3.37 - * from which portions of app (DKU, WT, FoR) onto which sched slots
    3.38 - *Might even do hierarchy of masters -- group of sched slots for each core
    3.39 - * has its own master, that keeps generated work local
    3.40 - * single-reader-single-writer sync everywhere -- no atomic primitives (but
    3.41 - * memory fences on architectures that need them)
    3.42 - * Might have the different schedulers talk to each other, to negotiate
    3.43 - * larger-grain sharing of resources, according to predicted critical
    3.44 - * path, and expansion of work
    3.45 - */
    3.46 -
    3.47 -
    3.48 -
    3.49 -//===========================================================================
    3.50 -
    3.51 -
    3.52 -/*These are the library functions *called in the application*
    3.53 - * 
    3.54 - *There's a pattern for the outside sequential code to interact with the
    3.55 - * VMS_HW code.
    3.56 - *The VMS_HW system is inside a boundary..  every VCilk system is in its
    3.57 - * own directory that contains the functions for each of the processor types.
    3.58 - * One of the processor types is the "seed" processor that starts the
    3.59 - * cascade of creating all the processors that do the work.
    3.60 - *So, in the directory is a file called "EntryPoint.c" that contains the
    3.61 - * function, named appropriately to the work performed, that the outside
    3.62 - * sequential code calls.  This function follows a pattern:
    3.63 - *1) it calls VCilk__init()
    3.64 - *2) it creates the initial data for the seed processor, which is passed
    3.65 - *    in to the function
    3.66 - *3) it creates the seed VCilk processor, with the data to start it with.
    3.67 - *4) it calls startVCilkThenWaitUntilWorkDone
    3.68 - *5) it gets the returnValue from the transfer struc and returns that
    3.69 - *    from the function
    3.70 - *
    3.71 - *For now, a new VCilk system has to be created via VCilk__init every
    3.72 - * time an entry point function is called -- later, might add letting the
    3.73 - * VCilk system be created once, and let all the entry points just reuse
    3.74 - * it -- want to be as simple as possible now, and see by using what makes
    3.75 - * sense for later..
    3.76 - */
    3.77 -
    3.78 -
    3.79 -
    3.80 -//===========================================================================
    3.81 -
    3.82 -/*This is the "border crossing" function -- the thing that crosses from the
    3.83 - * outside world, into the VMS_HW world.  It initializes and starts up the
    3.84 - * VMS system, then creates one processor from the specified function and
    3.85 - * puts it into the readyQ.  From that point, that one function is resp.
    3.86 - * for creating all the other processors, that then create others, and so
    3.87 - * forth.
    3.88 - *When all the processors, including the seed, have dissipated, then this
    3.89 - * function returns.  The results will have been written by side-effect via
    3.90 - * pointers read from, or written into initData.
    3.91 - *
    3.92 - *NOTE: no Threads should exist in the outside program that might touch
    3.93 - * any of the data reachable from initData passed in to here
    3.94 - */
    3.95 -void
    3.96 -VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fnPtr, void *initData )
    3.97 - { VCilkSemEnv *semEnv;
    3.98 -   VirtProcr *seedPr;
    3.99 -
   3.100 -   #ifdef SEQUENTIAL
   3.101 -   VCilk__init_Seq();  //debug sequential exe
   3.102 -   #else
   3.103 -   VCilk__init();      //normal multi-thd
   3.104 -   #endif
   3.105 -   semEnv = _VMSMasterEnv->semanticEnv;
   3.106 -
   3.107 -      //VCilk starts with one processor, which is put into initial environ,
   3.108 -      // and which then calls create() to create more, thereby expanding work
   3.109 -   seedPr = VCilk__create_procr_helper( fnPtr, initData, NULL, semEnv, -1 );
   3.110 -   resume_procr( seedPr, semEnv );
   3.111 -
   3.112 -   #ifdef SEQUENTIAL
   3.113 -   VMS__start_the_work_then_wait_until_done_Seq();  //debug sequential exe
   3.114 -   #else
   3.115 -   VMS__start_the_work_then_wait_until_done();      //normal multi-thd
   3.116 -   #endif
   3.117 -
   3.118 -   VCilk__cleanup_at_end_of_shutdown();
   3.119 - }
   3.120 -
   3.121 -
   3.122 -int32 inline
   3.123 -VCilk__giveMinWorkUnitCycles( float32 percentOverhead )
   3.124 - {
   3.125 -   return MIN_WORK_UNIT_CYCLES;
   3.126 - }
   3.127 -
   3.128 -int32
   3.129 -VCilk__giveIdealNumWorkUnits()
   3.130 - {
   3.131 -   return NUM_SCHED_SLOTS * NUM_CORES;
   3.132 - }
   3.133 -
   3.134 -/*To measure how long a primitive operation takes, when calculating number of
   3.135 - * sub-tasks to divide into.
   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 inline
   3.140 -VCilk__start_primitive()
   3.141 - { //int32 *saveAddr;
   3.142 -   //saveAddr = &(((VCilkSemEnv *)(_VMSMasterEnv->semanticEnv))->primitiveStartTime);
   3.143 -   saveLowTimeStampCountInto( (((VCilkSemEnv *)
   3.144 -                        (_VMSMasterEnv->semanticEnv))->primitiveStartTime) );
   3.145 - }
   3.146 -
   3.147 -/*Just quick and dirty for now -- make reliable later
   3.148 - * will want this to jump back several times -- to be sure cache is warm
   3.149 - * because don't want comm time included in calc-time measurement -- and
   3.150 - * also to throw out any "weird" values due to OS interrupt or TSC rollover
   3.151 - */
   3.152 -int32 inline
   3.153 -VCilk__end_primitive_and_give_cycles()
   3.154 - { int32 endTime, startTime;
   3.155 -   //TODO: fix by repeating time-measurement
   3.156 -   saveLowTimeStampCountInto( endTime );
   3.157 -   startTime = ( (VCilkSemEnv *)
   3.158 -                 (_VMSMasterEnv->semanticEnv))->primitiveStartTime;
   3.159 -   return (endTime - startTime);
   3.160 - }
   3.161 -
   3.162 -//===========================================================================
   3.163 -//
   3.164 -/*Initializes all the data-structures for a VCilk system -- but doesn't
   3.165 - * start it running yet!
   3.166 - *
   3.167 - *This and its callees run in main thread outside VMS
   3.168 - * 
   3.169 - *This sets up the semantic layer over the VMS system
   3.170 - *
   3.171 - *First, calls VMS_Setup, then creates own environment, making it ready
   3.172 - * for creating the seed processor and then starting the work.
   3.173 - */
   3.174 -void
   3.175 -VCilk__init()
   3.176 - {
   3.177 -   VMS__init();
   3.178 -      //masterEnv, a global var, now is partially set up by init_VMS
   3.179 -
   3.180 -   VCilk__init_Helper();
   3.181 - }
   3.182 -
   3.183 -void
   3.184 -VCilk__init_Seq()
   3.185 - {
   3.186 -   VMS__init_Seq();
   3.187 -      //masterEnv, a global var, now is partially set up by init_VMS
   3.188 -
   3.189 -   VCilk__init_Helper();
   3.190 - }
   3.191 -
   3.192 -/*Runs in main thread before VMS system starts
   3.193 - */
   3.194 -void
   3.195 -VCilk__init_Helper()
   3.196 - { VCilkSemEnv     *semanticEnv;
   3.197 -   PrivQueueStruc **readyVPQs;
   3.198 -   int              coreIdx;
   3.199 - 
   3.200 -      //Hook up the semantic layer's plug-ins to the Master virt procr
   3.201 -   _VMSMasterEnv->requestHandler = &VCilk__Request_Handler;
   3.202 -   _VMSMasterEnv->slaveScheduler = &VCilk__schedule_virt_procr;
   3.203 -
   3.204 -      //create the semantic layer's environment (all its data) and add to
   3.205 -      // the master environment
   3.206 -   semanticEnv = VMS__malloc( sizeof( VCilkSemEnv ) );
   3.207 -   _VMSMasterEnv->semanticEnv = semanticEnv;
   3.208 -
   3.209 -      //create the ready queue, hash tables used for pairing send to receive
   3.210 -      // and so forth
   3.211 -      //TODO: add hash tables for pairing sends with receives, and
   3.212 -      // initialize the data ownership system
   3.213 -   readyVPQs = VMS__malloc( NUM_CORES * sizeof(PrivQueueStruc *) );
   3.214 -
   3.215 -   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   3.216 -    {
   3.217 -      readyVPQs[ coreIdx ] = makeVMSPrivQ();
   3.218 -    }
   3.219 -   
   3.220 -   semanticEnv->readyVPQs = readyVPQs;
   3.221 -   
   3.222 -   semanticEnv->nextCoreToGetNewPr = 0;
   3.223 -
   3.224 -   //TODO: bug -- turn these arrays into dyn arrays to eliminate limit
   3.225 -   //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( );
   3.226 -   //semanticEnv->transactionStrucs = makeDynArrayInfo( );
   3.227 -   //something like: setHighestIdx( dynArrayInfo, NUM_STRUCS_IN_SEM_ENV )
   3.228 -   int32 i;
   3.229 -   for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ )
   3.230 -    {
   3.231 -      semanticEnv->fnSingletons[i].endInstrAddr      = NULL;
   3.232 -      semanticEnv->fnSingletons[i].hasBeenStarted    = FALSE;
   3.233 -      semanticEnv->fnSingletons[i].hasFinished       = FALSE;
   3.234 -      semanticEnv->fnSingletons[i].waitQ             = makeVMSPrivQ();
   3.235 -      semanticEnv->transactionStrucs[i].waitingVPQ   = makeVMSPrivQ();
   3.236 -    }
   3.237 -
   3.238 - }
   3.239 -
   3.240 -
   3.241 -/*Runs in main thread, outside VMS
   3.242 - *Frees any memory allocated by VCilk__init() then calls VMS's cleanup
   3.243 - */
   3.244 -void
   3.245 -VCilk__cleanup_at_end_of_shutdown()
   3.246 - { VCilkSemEnv *semanticEnv;
   3.247 - 
   3.248 -   semanticEnv = _VMSMasterEnv->semanticEnv;
   3.249 -
   3.250 -   /*
   3.251 -   int32 coreIdx;
   3.252 -   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   3.253 -    {
   3.254 -      VMS__free( semanticEnv->readyVPQs[coreIdx]->startOfData );
   3.255 -      VMS__free( semanticEnv->readyVPQs[coreIdx] );
   3.256 -    }
   3.257 -   VMS__free( semanticEnv->readyVPQs );
   3.258 -   
   3.259 -   VMS__free( _VMSMasterEnv->semanticEnv );
   3.260 -    */
   3.261 -   VMS__cleanup_at_end_of_shutdown();
   3.262 - }
   3.263 -
   3.264 -
   3.265 -//===========================================================================
   3.266 -
   3.267 -
   3.268 -/*Spawn involves allocating mem as well as creating processor which itself
   3.269 - * allocates, so has to be done inside master
   3.270 - */
   3.271 -void inline
   3.272 -VCilk__spawn( int32  coreToSpawnOnto, VirtProcrFnPtr  fnPtr,
   3.273 -              void  *initData,        VirtProcr      *requestingPr )
   3.274 - { VCilkSemReq reqData;
   3.275 -
   3.276 -      //the semantic request data is on the stack and disappears when this
   3.277 -      // call returns -- it's guaranteed to remain in the VP's stack for as
   3.278 -      // long as the VP is suspended.
   3.279 -   reqData.reqType         = 0; //know it's type because in a VMS create req
   3.280 -   reqData.coreToSpawnOnto = coreToSpawnOnto;
   3.281 -   reqData.fnPtr           = fnPtr;
   3.282 -   reqData.initData        = initData;
   3.283 -   reqData.requestingPr    = requestingPr;
   3.284 -
   3.285 -   VMS__send_create_procr_req( &reqData, requestingPr );
   3.286 - } 
   3.287 -
   3.288 -
   3.289 -int32
   3.290 -VCilk__give_number_of_cores_to_spawn_onto()
   3.291 - {
   3.292 -   return NUM_CORES;
   3.293 - }
   3.294 -
   3.295 -
   3.296 -
   3.297 -/*This runs inside slave VP, so can't do any freeing -- have to do in plugin
   3.298 - */
   3.299 -void inline
   3.300 -VCilk__dissipate_procr( VirtProcr *procrToDissipate )
   3.301 - { 
   3.302 -
   3.303 -   VMS__send_dissipate_req( procrToDissipate );
   3.304 - }
   3.305 -
   3.306 -//===========================================================================
   3.307 -
   3.308 -void
   3.309 -VCilk__sync( VirtProcr *animPr )
   3.310 - { VCilkSemReq reqData;
   3.311 - 
   3.312 -   reqData.reqType      = syncReq;
   3.313 -   reqData.requestingPr = animPr;
   3.314 -
   3.315 -   VMS__send_sem_request( &reqData, animPr );
   3.316 - }
   3.317 -
   3.318 -
   3.319 -
   3.320 -void *
   3.321 -VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr )
   3.322 - { VCilkSemReq reqData;
   3.323 -
   3.324 -   reqData.reqType      = mallocReq;
   3.325 -   reqData.requestingPr = animPr;
   3.326 -   reqData.sizeToMalloc = sizeToMalloc;
   3.327 -
   3.328 -   VMS__send_sem_request( &reqData, animPr );
   3.329 -
   3.330 -   return animPr->dataRetFromReq;
   3.331 - }
   3.332 -
   3.333 -
   3.334 -/*Sends request to Master, which does the work of freeing
   3.335 - */
   3.336 -void
   3.337 -VCilk__free( void *ptrToFree, VirtProcr *animPr )
   3.338 - { VCilkSemReq reqData;
   3.339 -
   3.340 -   reqData.reqType      = freeReq;
   3.341 -   reqData.requestingPr = animPr;
   3.342 -   reqData.ptrToFree    = ptrToFree;
   3.343 -
   3.344 -   VMS__send_sem_request( &reqData, animPr );
   3.345 - }
   3.346 -
   3.347 -//===========================================================================
   3.348 -//
   3.349 -/*A function singleton is a function whose body executes exactly once, on a
   3.350 - * single core, no matter how many times the fuction is called and no
   3.351 - * matter how many cores or the timing of cores calling it.
   3.352 - *
   3.353 - *A data singleton is a ticket attached to data.  That ticket can be used
   3.354 - * to get the data through the function exactly once, no matter how many
   3.355 - * times the data is given to the function, and no matter the timing of
   3.356 - * trying to get the data through from different cores.
   3.357 - */
   3.358 -
   3.359 -/*Fn singleton uses ID as index into array of singleton structs held in the
   3.360 - * semantic environment.
   3.361 - */
   3.362 -void
   3.363 -VCilk__start_fn_singleton( int32 singletonID,   VirtProcr *animPr )
   3.364 - {
   3.365 -   VCilkSemReq  reqData;
   3.366 -
   3.367 -      //
   3.368 -   reqData.reqType     = singleton_fn_start;
   3.369 -   reqData.singletonID = singletonID;
   3.370 -
   3.371 -   VMS__send_sem_request( &reqData, animPr );
   3.372 -   if( animPr->dataRetFromReq ) //will be 0 or addr of label in end singleton
   3.373 -    {
   3.374 -      asm volatile("movl         %0,      %%eax;  \
   3.375 -                    jmp                  *%%eax"  \
   3.376 -      /* outputs */ :                             \
   3.377 -      /* inputs  */ : "g"(animPr->dataRetFromReq) \
   3.378 -      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   3.379 -                   );
   3.380 -    }
   3.381 - }
   3.382 -
   3.383 -/*Data singleton hands addr of loc holding a pointer to a singleton struct.
   3.384 - * The start_data_singleton makes the structure and puts its addr into the
   3.385 - * location.
   3.386 - */
   3.387 -void
   3.388 -VCilk__start_data_singleton( VCilkSingleton **singletonAddr,  VirtProcr *animPr )
   3.389 - {
   3.390 -   VCilkSemReq  reqData;
   3.391 -
   3.392 -   if( *singletonAddr && (*singletonAddr)->hasFinished )
   3.393 -      goto JmpToEndSingleton;
   3.394 -      //
   3.395 -   reqData.reqType       = singleton_data_start;
   3.396 -   reqData.singletonPtrAddr = singletonAddr;
   3.397 -
   3.398 -   VMS__send_sem_request( &reqData, animPr );
   3.399 -   if( animPr->dataRetFromReq ) //either 0 or end singleton's return addr
   3.400 -    {    //Assembly code changes the return addr on the stack to the one
   3.401 -         // saved into the singleton by the end-singleton-fn
   3.402 -         //The return addr is at 0x4(%%ebp)
   3.403 -      JmpToEndSingleton:
   3.404 -      asm volatile("movl        %0,      %%eax;   \
   3.405 -                    movl    (%%eax),     %%ebx;   \
   3.406 -                    movl    (%%ebx),     %%eax;   \
   3.407 -                    movl     %%eax,  0x4(%%ebp);" \
   3.408 -      /* outputs */ :                             \
   3.409 -      /* inputs  */ : "m"(singletonAddr) \
   3.410 -      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   3.411 -                   );
   3.412 -    }
   3.413 -   //now, simply return
   3.414 -   //will exit either from the start singleton call or the end-singleton call
   3.415 - }
   3.416 -
   3.417 -/*Uses ID as index into array of flags.  If flag already set, resumes from
   3.418 - * end-label.  Else, sets flag and resumes normally.
   3.419 - *
   3.420 - *Note, this call cannot be inlined because the instr addr at the label
   3.421 - * inside is shared by all invocations of a given singleton ID.
   3.422 - */
   3.423 -void
   3.424 -VCilk__end_fn_singleton( int32 singletonID, VirtProcr *animPr )
   3.425 - {
   3.426 -   VCilkSemReq  reqData;
   3.427 -
   3.428 -      //don't need this addr until after at least one singleton has reached
   3.429 -      // this function
   3.430 -   VCilkSemEnv *semEnv = VMS__give_sem_env_for( animPr );
   3.431 -   semEnv->fnSingletons[ singletonID].endInstrAddr = &&EndSingletonInstrAddr;
   3.432 -
   3.433 -   reqData.reqType     = singleton_fn_end;
   3.434 -   reqData.singletonID = singletonID;
   3.435 -
   3.436 -   VMS__send_sem_request( &reqData, animPr );
   3.437 -
   3.438 -EndSingletonInstrAddr:
   3.439 -   return;
   3.440 - }
   3.441 -
   3.442 -void
   3.443 -VCilk__end_data_singleton(  VCilkSingleton **singletonPtrAddr, VirtProcr *animPr )
   3.444 - {
   3.445 -   VCilkSemReq  reqData;
   3.446 -
   3.447 -      //don't need this addr until after singleton struct has reached
   3.448 -      // this function for first time
   3.449 -      //do assembly that saves the return addr of this fn call into the
   3.450 -      // data singleton -- that data-singleton can only be given to exactly
   3.451 -      // one instance in the code of this function.  However, can use this
   3.452 -      // function in different places for different data-singletons.
   3.453 -//   (*(singletonAddr))->endInstrAddr =  &&EndDataSingletonInstrAddr;
   3.454 -
   3.455 -         //Assembly code takes the return addr off the stack and saves
   3.456 -         // into the singleton.  The first field in the singleton is the
   3.457 -         // "endInstrAddr" field, and the return addr is at 0x4(%%ebp)
   3.458 -      asm volatile("movl 0x4(%%ebp),     %%eax;   \
   3.459 -                    movl        %0,      %%ebx;   \
   3.460 -                    movl    (%%ebx),     %%ecx;   \
   3.461 -                    movl     %%eax,     (%%ecx);" \
   3.462 -      /* outputs */ :                             \
   3.463 -      /* inputs  */ : "m"(singletonPtrAddr) \
   3.464 -      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   3.465 -                   );
   3.466 -
   3.467 -   reqData.reqType          = singleton_data_end;
   3.468 -   reqData.singletonPtrAddr = singletonPtrAddr;
   3.469 -
   3.470 -   VMS__send_sem_request( &reqData, animPr );
   3.471 - }
   3.472 -
   3.473 -/*This executes the function in the masterVP, so it executes in isolation
   3.474 - * from any other copies -- only one copy of the function can ever execute
   3.475 - * at a time.
   3.476 - *
   3.477 - *It suspends to the master, and the request handler takes the function
   3.478 - * pointer out of the request and calls it, then resumes the VP.
   3.479 - *Only very short functions should be called this way -- for longer-running
   3.480 - * isolation, use transaction-start and transaction-end, which run the code
   3.481 - * between as work-code.
   3.482 - */
   3.483 -void
   3.484 -VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
   3.485 -                                    void *data, VirtProcr *animPr )
   3.486 - {
   3.487 -   VCilkSemReq  reqData;
   3.488 -
   3.489 -      //
   3.490 -   reqData.reqType          = atomic;
   3.491 -   reqData.fnToExecInMaster = ptrToFnToExecInMaster;
   3.492 -   reqData.dataForFn        = data;
   3.493 -
   3.494 -   VMS__send_sem_request( &reqData, animPr );
   3.495 - }
   3.496 -
   3.497 -
   3.498 -/*This suspends to the master.
   3.499 - *First, it looks at the VP's data, to see the highest transactionID that VP
   3.500 - * already has entered.  If the current ID is not larger, it throws an
   3.501 - * exception stating a bug in the code.  Otherwise it puts the current ID
   3.502 - * there, and adds the ID to a linked list of IDs entered -- the list is
   3.503 - * used to check that exits are properly ordered.
   3.504 - *Next it is uses transactionID as index into an array of transaction
   3.505 - * structures.
   3.506 - *If the "VP_currently_executing" field is non-null, then put requesting VP
   3.507 - * into queue in the struct.  (At some point a holder will request
   3.508 - * end-transaction, which will take this VP from the queue and resume it.)
   3.509 - *If NULL, then write requesting into the field and resume.
   3.510 - */
   3.511 -void
   3.512 -VCilk__start_transaction( int32 transactionID, VirtProcr *animPr )
   3.513 - {
   3.514 -   VCilkSemReq  reqData;
   3.515 -
   3.516 -      //
   3.517 -   reqData.reqType     = trans_start;
   3.518 -   reqData.transID     = transactionID;
   3.519 -
   3.520 -   VMS__send_sem_request( &reqData, animPr );
   3.521 - }
   3.522 -
   3.523 -/*This suspends to the master, then uses transactionID as index into an
   3.524 - * array of transaction structures.
   3.525 - *It looks at VP_currently_executing to be sure it's same as requesting VP.
   3.526 - * If different, throws an exception, stating there's a bug in the code.
   3.527 - *Next it looks at the queue in the structure.
   3.528 - *If it's empty, it sets VP_currently_executing field to NULL and resumes.
   3.529 - *If something in, gets it, sets VP_currently_executing to that VP, then
   3.530 - * resumes both.
   3.531 - */
   3.532 -void
   3.533 -VCilk__end_transaction( int32 transactionID, VirtProcr *animPr )
   3.534 - {
   3.535 -   VCilkSemReq  reqData;
   3.536 -
   3.537 -      //
   3.538 -   reqData.reqType     = trans_end;
   3.539 -   reqData.transID     = transactionID;
   3.540 -
   3.541 -   VMS__send_sem_request( &reqData, animPr );
   3.542 - }
   3.543 +/*
   3.544 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
   3.545 + *
   3.546 + * Licensed under BSD
   3.547 + */
   3.548 +
   3.549 +#include <stdio.h>
   3.550 +#include <stdlib.h>
   3.551 +
   3.552 +#include "VMS/VMS.h"
   3.553 +#include "VCilk.h"
   3.554 +#include "VMS/Queue_impl/PrivateQueue.h"
   3.555 +#include "VMS/Hash_impl/PrivateHash.h"
   3.556 +
   3.557 +
   3.558 +//==========================================================================
   3.559 +
   3.560 +void
   3.561 +VCilk__init();
   3.562 +
   3.563 +void
   3.564 +VCilk__init_Seq();
   3.565 +
   3.566 +void
   3.567 +VCilk__init_Helper();
   3.568 +//==========================================================================
   3.569 +
   3.570 +
   3.571 +/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR
   3.572 + * (still want to do FoR, with time-lines as syntax, could be super cool)
   3.573 + * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate
   3.574 + * among library, DKU, WT, FoR -- all the patterns in terms of virtual
   3.575 + * processors (or equivalently work-units), so Master picks which virt procr
   3.576 + * from which portions of app (DKU, WT, FoR) onto which sched slots
   3.577 + *Might even do hierarchy of masters -- group of sched slots for each core
   3.578 + * has its own master, that keeps generated work local
   3.579 + * single-reader-single-writer sync everywhere -- no atomic primitives (but
   3.580 + * memory fences on architectures that need them)
   3.581 + * Might have the different schedulers talk to each other, to negotiate
   3.582 + * larger-grain sharing of resources, according to predicted critical
   3.583 + * path, and expansion of work
   3.584 + */
   3.585 +
   3.586 +
   3.587 +
   3.588 +//===========================================================================
   3.589 +
   3.590 +
   3.591 +/*These are the library functions *called in the application*
   3.592 + * 
   3.593 + *There's a pattern for the outside sequential code to interact with the
   3.594 + * VMS_HW code.
   3.595 + *The VMS_HW system is inside a boundary..  every VCilk system is in its
   3.596 + * own directory that contains the functions for each of the processor types.
   3.597 + * One of the processor types is the "seed" processor that starts the
   3.598 + * cascade of creating all the processors that do the work.
   3.599 + *So, in the directory is a file called "EntryPoint.c" that contains the
   3.600 + * function, named appropriately to the work performed, that the outside
   3.601 + * sequential code calls.  This function follows a pattern:
   3.602 + *1) it calls VCilk__init()
   3.603 + *2) it creates the initial data for the seed processor, which is passed
   3.604 + *    in to the function
   3.605 + *3) it creates the seed VCilk processor, with the data to start it with.
   3.606 + *4) it calls startVCilkThenWaitUntilWorkDone
   3.607 + *5) it gets the returnValue from the transfer struc and returns that
   3.608 + *    from the function
   3.609 + *
   3.610 + *For now, a new VCilk system has to be created via VCilk__init every
   3.611 + * time an entry point function is called -- later, might add letting the
   3.612 + * VCilk system be created once, and let all the entry points just reuse
   3.613 + * it -- want to be as simple as possible now, and see by using what makes
   3.614 + * sense for later..
   3.615 + */
   3.616 +
   3.617 +
   3.618 +
   3.619 +//===========================================================================
   3.620 +
   3.621 +/*This is the "border crossing" function -- the thing that crosses from the
   3.622 + * outside world, into the VMS_HW world.  It initializes and starts up the
   3.623 + * VMS system, then creates one processor from the specified function and
   3.624 + * puts it into the readyQ.  From that point, that one function is resp.
   3.625 + * for creating all the other processors, that then create others, and so
   3.626 + * forth.
   3.627 + *When all the processors, including the seed, have dissipated, then this
   3.628 + * function returns.  The results will have been written by side-effect via
   3.629 + * pointers read from, or written into initData.
   3.630 + *
   3.631 + *NOTE: no Threads should exist in the outside program that might touch
   3.632 + * any of the data reachable from initData passed in to here
   3.633 + */
   3.634 +void
   3.635 +VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fnPtr, void *initData )
   3.636 + { VCilkSemEnv *semEnv;
   3.637 +   VirtProcr *seedPr;
   3.638 +
   3.639 +   #ifdef SEQUENTIAL
   3.640 +   VCilk__init_Seq();  //debug sequential exe
   3.641 +   #else
   3.642 +   VCilk__init();      //normal multi-thd
   3.643 +   #endif
   3.644 +   semEnv = _VMSMasterEnv->semanticEnv;
   3.645 +
   3.646 +      //VCilk starts with one processor, which is put into initial environ,
   3.647 +      // and which then calls create() to create more, thereby expanding work
   3.648 +   seedPr = (VirtProcr*)VCilk__create_procr_helper( fnPtr, initData, NULL, semEnv, -1 );
   3.649 +   resume_procr( seedPr, semEnv );
   3.650 +
   3.651 +   #ifdef SEQUENTIAL
   3.652 +   VMS__start_the_work_then_wait_until_done_Seq();  //debug sequential exe
   3.653 +   #else
   3.654 +   VMS__start_the_work_then_wait_until_done();      //normal multi-thd
   3.655 +   #endif
   3.656 +
   3.657 +   VCilk__cleanup_at_end_of_shutdown();
   3.658 + }
   3.659 +
   3.660 +
   3.661 +int32 inline
   3.662 +VCilk__giveMinWorkUnitCycles( float32 percentOverhead )
   3.663 + {
   3.664 +   return MIN_WORK_UNIT_CYCLES;
   3.665 + }
   3.666 +
   3.667 +int32
   3.668 +VCilk__giveIdealNumWorkUnits()
   3.669 + {
   3.670 +   return NUM_SCHED_SLOTS * NUM_CORES;
   3.671 + }
   3.672 +
   3.673 +/*To measure how long a primitive operation takes, when calculating number of
   3.674 + * sub-tasks to divide into.
   3.675 + * For now, use TSC -- later, make these two macros with assembly that first
   3.676 + * saves jump point, and second jumps back several times to get reliable time
   3.677 + */
   3.678 +void inline
   3.679 +VCilk__start_primitive()
   3.680 + { //int32 *saveAddr;
   3.681 +   //saveAddr = &(((VCilkSemEnv *)(_VMSMasterEnv->semanticEnv))->primitiveStartTime);
   3.682 +   saveLowTimeStampCountInto( (((VCilkSemEnv *)
   3.683 +                        (_VMSMasterEnv->semanticEnv))->primitiveStartTime) );
   3.684 + }
   3.685 +
   3.686 +/*Just quick and dirty for now -- make reliable later
   3.687 + * will want this to jump back several times -- to be sure cache is warm
   3.688 + * because don't want comm time included in calc-time measurement -- and
   3.689 + * also to throw out any "weird" values due to OS interrupt or TSC rollover
   3.690 + */
   3.691 +int32 inline
   3.692 +VCilk__end_primitive_and_give_cycles()
   3.693 + { int32 endTime, startTime;
   3.694 +   //TODO: fix by repeating time-measurement
   3.695 +   saveLowTimeStampCountInto( endTime );
   3.696 +   startTime = ( (VCilkSemEnv *)
   3.697 +                 (_VMSMasterEnv->semanticEnv))->primitiveStartTime;
   3.698 +   return (endTime - startTime);
   3.699 + }
   3.700 +
   3.701 +//===========================================================================
   3.702 +//
   3.703 +/*Initializes all the data-structures for a VCilk system -- but doesn't
   3.704 + * start it running yet!
   3.705 + *
   3.706 + *This and its callees run in main thread outside VMS
   3.707 + * 
   3.708 + *This sets up the semantic layer over the VMS system
   3.709 + *
   3.710 + *First, calls VMS_Setup, then creates own environment, making it ready
   3.711 + * for creating the seed processor and then starting the work.
   3.712 + */
   3.713 +void
   3.714 +VCilk__init()
   3.715 + {
   3.716 +   VMS__init();
   3.717 +      //masterEnv, a global var, now is partially set up by init_VMS
   3.718 +
   3.719 +   VCilk__init_Helper();
   3.720 + }
   3.721 +
   3.722 +void
   3.723 +VCilk__init_Seq()
   3.724 + {
   3.725 +   VMS__init_Seq();
   3.726 +      //masterEnv, a global var, now is partially set up by init_VMS
   3.727 +
   3.728 +   VCilk__init_Helper();
   3.729 + }
   3.730 +
   3.731 +/*Runs in main thread before VMS system starts
   3.732 + */
   3.733 +void
   3.734 +VCilk__init_Helper()
   3.735 + { VCilkSemEnv     *semanticEnv;
   3.736 +   PrivQueueStruc **readyVPQs;
   3.737 +   int              coreIdx;
   3.738 + 
   3.739 +      //Hook up the semantic layer's plug-ins to the Master virt procr
   3.740 +   _VMSMasterEnv->requestHandler = &VCilk__Request_Handler;
   3.741 +   _VMSMasterEnv->slaveScheduler = &VCilk__schedule_virt_procr;
   3.742 +
   3.743 +      //create the semantic layer's environment (all its data) and add to
   3.744 +      // the master environment
   3.745 +   semanticEnv = VMS__malloc( sizeof( VCilkSemEnv ) );
   3.746 +   _VMSMasterEnv->semanticEnv = semanticEnv;
   3.747 +
   3.748 +      //create the ready queue, hash tables used for pairing send to receive
   3.749 +      // and so forth
   3.750 +      //TODO: add hash tables for pairing sends with receives, and
   3.751 +      // initialize the data ownership system
   3.752 +   readyVPQs = VMS__malloc( NUM_CORES * sizeof(PrivQueueStruc *) );
   3.753 +
   3.754 +   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   3.755 +    {
   3.756 +      readyVPQs[ coreIdx ] = makeVMSPrivQ();
   3.757 +    }
   3.758 +   
   3.759 +   semanticEnv->readyVPQs = readyVPQs;
   3.760 +   
   3.761 +   semanticEnv->nextCoreToGetNewPr = 0;
   3.762 +
   3.763 +   //TODO: bug -- turn these arrays into dyn arrays to eliminate limit
   3.764 +   //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( );
   3.765 +   //semanticEnv->transactionStrucs = makeDynArrayInfo( );
   3.766 +   //something like: setHighestIdx( dynArrayInfo, NUM_STRUCS_IN_SEM_ENV )
   3.767 +   int32 i;
   3.768 +   for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ )
   3.769 +    {
   3.770 +      semanticEnv->fnSingletons[i].endInstrAddr      = NULL;
   3.771 +      semanticEnv->fnSingletons[i].hasBeenStarted    = FALSE;
   3.772 +      semanticEnv->fnSingletons[i].hasFinished       = FALSE;
   3.773 +      semanticEnv->fnSingletons[i].waitQ             = makeVMSPrivQ();
   3.774 +      semanticEnv->transactionStrucs[i].waitingVPQ   = makeVMSPrivQ();
   3.775 +    }
   3.776 +
   3.777 + }
   3.778 +
   3.779 +
   3.780 +/*Runs in main thread, outside VMS
   3.781 + *Frees any memory allocated by VCilk__init() then calls VMS's cleanup
   3.782 + */
   3.783 +void
   3.784 +VCilk__cleanup_at_end_of_shutdown()
   3.785 + { VCilkSemEnv *semanticEnv;
   3.786 + 
   3.787 +   semanticEnv = _VMSMasterEnv->semanticEnv;
   3.788 +
   3.789 +   /*
   3.790 +   int32 coreIdx;
   3.791 +   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   3.792 +    {
   3.793 +      VMS__free( semanticEnv->readyVPQs[coreIdx]->startOfData );
   3.794 +      VMS__free( semanticEnv->readyVPQs[coreIdx] );
   3.795 +    }
   3.796 +   VMS__free( semanticEnv->readyVPQs );
   3.797 +   
   3.798 +   VMS__free( _VMSMasterEnv->semanticEnv );
   3.799 +    */
   3.800 +   VMS__cleanup_at_end_of_shutdown();
   3.801 + }
   3.802 +
   3.803 +
   3.804 +//===========================================================================
   3.805 +
   3.806 +
   3.807 +/*Spawn involves allocating mem as well as creating processor which itself
   3.808 + * allocates, so has to be done inside master
   3.809 + */
   3.810 +void inline
   3.811 +VCilk__spawn( int32  coreToSpawnOnto, VirtProcrFnPtr  fnPtr,
   3.812 +              void  *initData,        VirtProcr      *requestingPr )
   3.813 + { VCilkSemReq reqData;
   3.814 +
   3.815 +      //the semantic request data is on the stack and disappears when this
   3.816 +      // call returns -- it's guaranteed to remain in the VP's stack for as
   3.817 +      // long as the VP is suspended.
   3.818 +   reqData.reqType         = 0; //know it's type because in a VMS create req
   3.819 +   reqData.coreToSpawnOnto = coreToSpawnOnto;
   3.820 +   reqData.fnPtr           = fnPtr;
   3.821 +   reqData.initData        = initData;
   3.822 +   reqData.requestingPr    = requestingPr;
   3.823 +
   3.824 +   VMS__send_create_procr_req( &reqData, requestingPr );
   3.825 + } 
   3.826 +
   3.827 +
   3.828 +int32
   3.829 +VCilk__give_number_of_cores_to_spawn_onto()
   3.830 + {
   3.831 +   return NUM_CORES;
   3.832 + }
   3.833 +
   3.834 +
   3.835 +
   3.836 +/*This runs inside slave VP, so can't do any freeing -- have to do in plugin
   3.837 + */
   3.838 +void inline
   3.839 +VCilk__dissipate_procr( VirtProcr *procrToDissipate )
   3.840 + { 
   3.841 +
   3.842 +   VMS__send_dissipate_req( procrToDissipate );
   3.843 + }
   3.844 +
   3.845 +//===========================================================================
   3.846 +
   3.847 +void
   3.848 +VCilk__sync( VirtProcr *animPr )
   3.849 + { VCilkSemReq reqData;
   3.850 + 
   3.851 +   reqData.reqType      = syncReq;
   3.852 +   reqData.requestingPr = animPr;
   3.853 +
   3.854 +   VMS__send_sem_request( &reqData, animPr );
   3.855 + }
   3.856 +
   3.857 +
   3.858 +
   3.859 +void *
   3.860 +VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr )
   3.861 + { VCilkSemReq reqData;
   3.862 +
   3.863 +   reqData.reqType      = mallocReq;
   3.864 +   reqData.requestingPr = animPr;
   3.865 +   reqData.sizeToMalloc = sizeToMalloc;
   3.866 +
   3.867 +   VMS__send_sem_request( &reqData, animPr );
   3.868 +
   3.869 +   return animPr->dataRetFromReq;
   3.870 + }
   3.871 +
   3.872 +
   3.873 +/*Sends request to Master, which does the work of freeing
   3.874 + */
   3.875 +void
   3.876 +VCilk__free( void *ptrToFree, VirtProcr *animPr )
   3.877 + { VCilkSemReq reqData;
   3.878 +
   3.879 +   reqData.reqType      = freeReq;
   3.880 +   reqData.requestingPr = animPr;
   3.881 +   reqData.ptrToFree    = ptrToFree;
   3.882 +
   3.883 +   VMS__send_sem_request( &reqData, animPr );
   3.884 + }
   3.885 +
   3.886 +//===========================================================================
   3.887 +//
   3.888 +/*A function singleton is a function whose body executes exactly once, on a
   3.889 + * single core, no matter how many times the fuction is called and no
   3.890 + * matter how many cores or the timing of cores calling it.
   3.891 + *
   3.892 + *A data singleton is a ticket attached to data.  That ticket can be used
   3.893 + * to get the data through the function exactly once, no matter how many
   3.894 + * times the data is given to the function, and no matter the timing of
   3.895 + * trying to get the data through from different cores.
   3.896 + */
   3.897 +
   3.898 +/*Fn singleton uses ID as index into array of singleton structs held in the
   3.899 + * semantic environment.
   3.900 + */
   3.901 +void
   3.902 +VCilk__start_fn_singleton( int32 singletonID,   VirtProcr *animPr )
   3.903 + {
   3.904 +   VCilkSemReq  reqData;
   3.905 +
   3.906 +      //
   3.907 +   reqData.reqType     = singleton_fn_start;
   3.908 +   reqData.singletonID = singletonID;
   3.909 +
   3.910 +   VMS__send_sem_request( &reqData, animPr );
   3.911 +   if( animPr->dataRetFromReq ) //will be 0 or addr of label in end singleton
   3.912 +    {
   3.913 +      asm volatile("movl         %0,      %%eax;  \
   3.914 +                    jmp                  *%%eax"  \
   3.915 +      /* outputs */ :                             \
   3.916 +      /* inputs  */ : "g"(animPr->dataRetFromReq) \
   3.917 +      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   3.918 +                   );
   3.919 +    }
   3.920 + }
   3.921 +
   3.922 +/*Data singleton hands addr of loc holding a pointer to a singleton struct.
   3.923 + * The start_data_singleton makes the structure and puts its addr into the
   3.924 + * location.
   3.925 + */
   3.926 +void
   3.927 +VCilk__start_data_singleton( VCilkSingleton **singletonAddr,  VirtProcr *animPr )
   3.928 + {
   3.929 +   VCilkSemReq  reqData;
   3.930 +
   3.931 +   if( *singletonAddr && (*singletonAddr)->hasFinished )
   3.932 +      goto JmpToEndSingleton;
   3.933 +      //
   3.934 +   reqData.reqType       = singleton_data_start;
   3.935 +   reqData.singletonPtrAddr = singletonAddr;
   3.936 +
   3.937 +   VMS__send_sem_request( &reqData, animPr );
   3.938 +   if( animPr->dataRetFromReq ) //either 0 or end singleton's return addr
   3.939 +    {    //Assembly code changes the return addr on the stack to the one
   3.940 +         // saved into the singleton by the end-singleton-fn
   3.941 +         //The return addr is at 0x4(%%ebp)
   3.942 +      JmpToEndSingleton:
   3.943 +      asm volatile("movl        %0,      %%eax;   \
   3.944 +                    movl    (%%eax),     %%ebx;   \
   3.945 +                    movl    (%%ebx),     %%eax;   \
   3.946 +                    movl     %%eax,  0x4(%%ebp);" \
   3.947 +      /* outputs */ :                             \
   3.948 +      /* inputs  */ : "m"(singletonAddr) \
   3.949 +      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
   3.950 +                   );
   3.951 +    }
   3.952 +   //now, simply return
   3.953 +   //will exit either from the start singleton call or the end-singleton call
   3.954 + }
   3.955 +
   3.956 +/*Uses ID as index into array of flags.  If flag already set, resumes from
   3.957 + * end-label.  Else, sets flag and resumes normally.
   3.958 + *
   3.959 + *Note, this call cannot be inlined because the instr addr at the label
   3.960 + * inside is shared by all invocations of a given singleton ID.
   3.961 + */
   3.962 +void
   3.963 +VCilk__end_fn_singleton( int32 singletonID, VirtProcr *animPr )
   3.964 + {
   3.965 +   VCilkSemReq  reqData;
   3.966 +
   3.967 +      //don't need this addr until after at least one singleton has reached
   3.968 +      // this function
   3.969 +   VCilkSemEnv *semEnv = VMS__give_sem_env_for( animPr );
   3.970 +   semEnv->fnSingletons[ singletonID].endInstrAddr = &&EndSingletonInstrAddr;
   3.971 +
   3.972 +   reqData.reqType     = singleton_fn_end;
   3.973 +   reqData.singletonID = singletonID;
   3.974 +
   3.975 +   VMS__send_sem_request( &reqData, animPr );
   3.976 +
   3.977 +EndSingletonInstrAddr:
   3.978 +   return;
   3.979 + }
   3.980 +
   3.981 +void
   3.982 +VCilk__end_data_singleton(  VCilkSingleton **singletonPtrAddr, VirtProcr *animPr )
   3.983 + {
   3.984 +   VCilkSemReq  reqData;
   3.985 +
   3.986 +      //don't need this addr until after singleton struct has reached
   3.987 +      // this function for first time
   3.988 +      //do assembly that saves the return addr of this fn call into the
   3.989 +      // data singleton -- that data-singleton can only be given to exactly
   3.990 +      // one instance in the code of this function.  However, can use this
   3.991 +      // function in different places for different data-singletons.
   3.992 +//   (*(singletonAddr))->endInstrAddr =  &&EndDataSingletonInstrAddr;
   3.993 +
   3.994 +         //Assembly code takes the return addr off the stack and saves
   3.995 +         // into the singleton.  The first field in the singleton is the
   3.996 +         // "endInstrAddr" field, and the return addr is at 0x4(%%ebp)
   3.997 +      asm volatile("movl 0x4(%%ebp),     %%eax;   \
   3.998 +                    movl        %0,      %%ebx;   \
   3.999 +                    movl    (%%ebx),     %%ecx;   \
  3.1000 +                    movl     %%eax,     (%%ecx);" \
  3.1001 +      /* outputs */ :                             \
  3.1002 +      /* inputs  */ : "m"(singletonPtrAddr) \
  3.1003 +      /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\
  3.1004 +                   );
  3.1005 +
  3.1006 +   reqData.reqType          = singleton_data_end;
  3.1007 +   reqData.singletonPtrAddr = singletonPtrAddr;
  3.1008 +
  3.1009 +   VMS__send_sem_request( &reqData, animPr );
  3.1010 + }
  3.1011 +
  3.1012 +/*This executes the function in the masterVP, so it executes in isolation
  3.1013 + * from any other copies -- only one copy of the function can ever execute
  3.1014 + * at a time.
  3.1015 + *
  3.1016 + *It suspends to the master, and the request handler takes the function
  3.1017 + * pointer out of the request and calls it, then resumes the VP.
  3.1018 + *Only very short functions should be called this way -- for longer-running
  3.1019 + * isolation, use transaction-start and transaction-end, which run the code
  3.1020 + * between as work-code.
  3.1021 + */
  3.1022 +void
  3.1023 +VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
  3.1024 +                                    void *data, VirtProcr *animPr )
  3.1025 + {
  3.1026 +   VCilkSemReq  reqData;
  3.1027 +
  3.1028 +      //
  3.1029 +   reqData.reqType          = atomic;
  3.1030 +   reqData.fnToExecInMaster = ptrToFnToExecInMaster;
  3.1031 +   reqData.dataForFn        = data;
  3.1032 +
  3.1033 +   VMS__send_sem_request( &reqData, animPr );
  3.1034 + }
  3.1035 +
  3.1036 +
  3.1037 +/*This suspends to the master.
  3.1038 + *First, it looks at the VP's data, to see the highest transactionID that VP
  3.1039 + * already has entered.  If the current ID is not larger, it throws an
  3.1040 + * exception stating a bug in the code.  Otherwise it puts the current ID
  3.1041 + * there, and adds the ID to a linked list of IDs entered -- the list is
  3.1042 + * used to check that exits are properly ordered.
  3.1043 + *Next it is uses transactionID as index into an array of transaction
  3.1044 + * structures.
  3.1045 + *If the "VP_currently_executing" field is non-null, then put requesting VP
  3.1046 + * into queue in the struct.  (At some point a holder will request
  3.1047 + * end-transaction, which will take this VP from the queue and resume it.)
  3.1048 + *If NULL, then write requesting into the field and resume.
  3.1049 + */
  3.1050 +void
  3.1051 +VCilk__start_transaction( int32 transactionID, VirtProcr *animPr )
  3.1052 + {
  3.1053 +   VCilkSemReq  reqData;
  3.1054 +
  3.1055 +      //
  3.1056 +   reqData.reqType     = trans_start;
  3.1057 +   reqData.transID     = transactionID;
  3.1058 +
  3.1059 +   VMS__send_sem_request( &reqData, animPr );
  3.1060 + }
  3.1061 +
  3.1062 +/*This suspends to the master, then uses transactionID as index into an
  3.1063 + * array of transaction structures.
  3.1064 + *It looks at VP_currently_executing to be sure it's same as requesting VP.
  3.1065 + * If different, throws an exception, stating there's a bug in the code.
  3.1066 + *Next it looks at the queue in the structure.
  3.1067 + *If it's empty, it sets VP_currently_executing field to NULL and resumes.
  3.1068 + *If something in, gets it, sets VP_currently_executing to that VP, then
  3.1069 + * resumes both.
  3.1070 + */
  3.1071 +void
  3.1072 +VCilk__end_transaction( int32 transactionID, VirtProcr *animPr )
  3.1073 + {
  3.1074 +   VCilkSemReq  reqData;
  3.1075 +
  3.1076 +      //
  3.1077 +   reqData.reqType     = trans_end;
  3.1078 +   reqData.transID     = transactionID;
  3.1079 +
  3.1080 +   VMS__send_sem_request( &reqData, animPr );
  3.1081 + }