Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VCilk_impls > VCilk__MC_shared_impl
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 + }