Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VCilk_impls > VCilk__MC_shared_impl
changeset 5:5494943ed3a4
Seans development tree
author | Merten Sach <msach@mailbox.tu-berlin.de> |
---|---|
date | Wed, 11 May 2011 15:29:58 +0200 |
parents | 96420af6b7e8 |
children | 58d0c2b1d6a4 |
files | .hgignore VCilk.h VCilk_PluginFns.c VCilk__DESIGN_NOTES.txt VCilk_lib.c |
diffstat | 5 files changed, 1323 insertions(+), 1102 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Wed May 11 15:29:58 2011 +0200 1.3 @@ -0,0 +1,1 @@ 1.4 +glob:.hgtags
2.1 --- a/VCilk.h Tue Nov 16 15:59:23 2010 +0100 2.2 +++ b/VCilk.h Wed May 11 15:29:58 2011 +0200 2.3 @@ -1,178 +1,200 @@ 2.4 -/* 2.5 - * Copyright 2009 OpenSourceStewardshipFoundation.org 2.6 - * Licensed under GNU General Public License version 2 2.7 - * 2.8 - * Author: seanhalle@yahoo.com 2.9 - * 2.10 - */ 2.11 - 2.12 -#ifndef _VCilk_H 2.13 -#define _VCilk_H 2.14 - 2.15 -#include "VMS/Queue_impl/PrivateQueue.h" 2.16 -#include "VMS/Hash_impl/PrivateHash.h" 2.17 -#include "VMS/VMS.h" 2.18 - 2.19 - 2.20 - 2.21 -/*This header defines everything specific to the VCilk semantic plug-in 2.22 - */ 2.23 - 2.24 -//=========================================================================== 2.25 -#define NUM_STRUCS_IN_SEM_ENV 1000 2.26 - 2.27 -//=========================================================================== 2.28 -typedef struct _VCilkSemReq VCilkSemReq; 2.29 -typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master 2.30 - 2.31 -//=========================================================================== 2.32 - 2.33 - 2.34 -/*Semantic layer-specific data sent inside a request from lib called in app 2.35 - * to request handler called in MasterLoop 2.36 - */ 2.37 -enum VCilkReqType 2.38 - { 2.39 - syncReq = 1, 2.40 - mallocReq, 2.41 - freeReq, 2.42 - singleton, 2.43 - atomic, 2.44 - trans_start, 2.45 - trans_end 2.46 - }; 2.47 - 2.48 -struct _VCilkSemReq 2.49 - { enum VCilkReqType reqType; 2.50 - VirtProcr *requestingPr; 2.51 - 2.52 - int32 sizeToMalloc; 2.53 - void *ptrToFree; 2.54 - 2.55 - VirtProcrFnPtr fnPtr; 2.56 - void *initData; 2.57 - int32 coreToSpawnOnto; 2.58 - 2.59 - int32 singletonID; 2.60 - void *endJumpPt; 2.61 - 2.62 - PtrToAtomicFn fnToExecInMaster; 2.63 - void *dataForFn; 2.64 - 2.65 - int32 transID; 2.66 - } 2.67 -/* VCilkSemReq */; 2.68 - 2.69 -typedef struct 2.70 - { 2.71 - VirtProcr *VPCurrentlyExecuting; 2.72 - PrivQueueStruc *waitingVPQ; 2.73 - } 2.74 -VCilkTrans; 2.75 - 2.76 -typedef struct 2.77 - { 2.78 - PrivQueueStruc **readyVPQs; 2.79 - HashTable *commHashTbl; 2.80 - int32 numVirtPr; 2.81 - int32 nextCoreToGetNewPr; 2.82 - int32 primitiveStartTime; 2.83 - 2.84 - //fix limit on num with dynArray 2.85 - int32 singletonHasBeenExecutedFlags[NUM_STRUCS_IN_SEM_ENV]; 2.86 - VCilkTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; 2.87 - } 2.88 -VCilkSemEnv; 2.89 - 2.90 -typedef struct _TransListElem TransListElem; 2.91 -struct _TransListElem 2.92 - { 2.93 - int32 transID; 2.94 - TransListElem *nextTrans; 2.95 - }; 2.96 -//TransListElem 2.97 - 2.98 -typedef struct 2.99 - { 2.100 - int32 syncPending; 2.101 - int32 numLiveChildren; 2.102 - VirtProcr *parentPr; 2.103 - 2.104 - int32 highestTransEntered; 2.105 - TransListElem *lastTransEntered; 2.106 - } 2.107 -VCilkSemData; 2.108 - 2.109 -//=========================================================================== 2.110 - 2.111 -void 2.112 -VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fn, void *initData ); 2.113 - 2.114 -int32 2.115 -VCilk__giveMinWorkUnitCycles( float32 percentOverhead ); 2.116 - 2.117 -void inline 2.118 -VCilk__start_primitive(); 2.119 - 2.120 -int32 inline 2.121 -VCilk__end_primitive_and_give_cycles(); 2.122 - 2.123 -int32 2.124 -VCilk__giveIdealNumWorkUnits(); 2.125 - 2.126 -//======================= 2.127 - 2.128 -void 2.129 -VCilk__init(); 2.130 - 2.131 -void 2.132 -VCilk__cleanup_at_end_of_shutdown(); 2.133 - 2.134 -//======================= 2.135 - 2.136 -void inline 2.137 -VCilk__spawn( int32 coreToSpawnOnto, VirtProcrFnPtr fnPtr, 2.138 - void *initData, VirtProcr *creatingPr ); 2.139 - 2.140 -int32 2.141 -VCilk__give_number_of_cores_to_spawn_onto(); 2.142 - 2.143 -void 2.144 -VCilk__sync( VirtProcr *animatingPr ); 2.145 - 2.146 -void * 2.147 -VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr ); 2.148 - 2.149 -void 2.150 -VCilk__free( void *ptrToFree, VirtProcr *animPr ); 2.151 - 2.152 -void 2.153 -VCilk__dissipate_procr( VirtProcr *procrToDissipate ); 2.154 - 2.155 - 2.156 -//======================= Concurrency Stuff ====================== 2.157 -void 2.158 -VCilk__start_singleton( int32 singletonID, void *endSingletonLabelAddr, 2.159 - VirtProcr *animPr ); 2.160 - 2.161 -void 2.162 -VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 2.163 - void *data, VirtProcr *animPr ); 2.164 - 2.165 -void 2.166 -VCilk__start_transaction( int32 transactionID, VirtProcr *animPr ); 2.167 - 2.168 -void 2.169 -VCilk__end_transaction( int32 transactionID, VirtProcr *animPr ); 2.170 - 2.171 - 2.172 -//========================= Internal use only ============================= 2.173 -void 2.174 -VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv ); 2.175 - 2.176 -VirtProcr * 2.177 -VCilk__schedule_virt_procr( void *_semEnv, int coreNum ); 2.178 - 2.179 - 2.180 -#endif /* _VCilk_H */ 2.181 - 2.182 +/* 2.183 + * Copyright 2009 OpenSourceStewardshipFoundation.org 2.184 + * Licensed under GNU General Public License version 2 2.185 + * 2.186 + * Author: seanhalle@yahoo.com 2.187 + * 2.188 + */ 2.189 + 2.190 +#ifndef _VCilk_H 2.191 +#define _VCilk_H 2.192 + 2.193 +#include "VMS/Queue_impl/PrivateQueue.h" 2.194 +#include "VMS/Hash_impl/PrivateHash.h" 2.195 +#include "VMS/VMS.h" 2.196 + 2.197 + 2.198 + 2.199 +/*This header defines everything specific to the VCilk semantic plug-in 2.200 + */ 2.201 + 2.202 +//=========================================================================== 2.203 +#define NUM_STRUCS_IN_SEM_ENV 1000 2.204 + 2.205 +//=========================================================================== 2.206 +typedef struct _VCilkSemReq VCilkSemReq; 2.207 +typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master 2.208 + 2.209 +//=========================================================================== 2.210 + 2.211 + 2.212 +/*WARNING: assembly hard-codes position of endInstrAddr as first field 2.213 + */ 2.214 +typedef struct 2.215 + { 2.216 + void *endInstrAddr; 2.217 + int32 hasBeenStarted; 2.218 + int32 hasFinished; 2.219 + PrivQueueStruc *waitQ; 2.220 + } 2.221 +VCilkSingleton; 2.222 + 2.223 +/*Semantic layer-specific data sent inside a request from lib called in app 2.224 + * to request handler called in MasterLoop 2.225 + */ 2.226 +enum VCilkReqType 2.227 + { 2.228 + syncReq = 1, 2.229 + mallocReq, 2.230 + freeReq, 2.231 + singleton_fn_start, 2.232 + singleton_fn_end, 2.233 + singleton_data_start, 2.234 + singleton_data_end, 2.235 + atomic, 2.236 + trans_start, 2.237 + trans_end 2.238 + }; 2.239 + 2.240 +struct _VCilkSemReq 2.241 + { enum VCilkReqType reqType; 2.242 + VirtProcr *requestingPr; 2.243 + 2.244 + int32 sizeToMalloc; 2.245 + void *ptrToFree; 2.246 + 2.247 + VirtProcrFnPtr fnPtr; 2.248 + void *initData; 2.249 + int32 coreToSpawnOnto; 2.250 + 2.251 + int32 singletonID; 2.252 + VCilkSingleton **singletonPtrAddr; 2.253 + 2.254 + PtrToAtomicFn fnToExecInMaster; 2.255 + void *dataForFn; 2.256 + 2.257 + int32 transID; 2.258 + } 2.259 +/* VCilkSemReq */; 2.260 + 2.261 +typedef struct 2.262 + { 2.263 + VirtProcr *VPCurrentlyExecuting; 2.264 + PrivQueueStruc *waitingVPQ; 2.265 + } 2.266 +VCilkTrans; 2.267 + 2.268 +typedef struct 2.269 + { 2.270 + PrivQueueStruc **readyVPQs; 2.271 + HashTable *commHashTbl; 2.272 + int32 numVirtPr; 2.273 + int32 nextCoreToGetNewPr; 2.274 + int32 primitiveStartTime; 2.275 + 2.276 + //fix limit on num with dynArray 2.277 + VCilkSingleton fnSingletons[NUM_STRUCS_IN_SEM_ENV]; 2.278 + VCilkTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; 2.279 + } 2.280 +VCilkSemEnv; 2.281 + 2.282 +typedef struct _TransListElem TransListElem; 2.283 +struct _TransListElem 2.284 + { 2.285 + int32 transID; 2.286 + TransListElem *nextTrans; 2.287 + }; 2.288 +//TransListElem 2.289 + 2.290 +typedef struct 2.291 + { 2.292 + int32 syncPending; 2.293 + int32 numLiveChildren; 2.294 + VirtProcr *parentPr; 2.295 + 2.296 + int32 highestTransEntered; 2.297 + TransListElem *lastTransEntered; 2.298 + } 2.299 +VCilkSemData; 2.300 + 2.301 +//=========================================================================== 2.302 + 2.303 +void 2.304 +VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fn, void *initData ); 2.305 + 2.306 +int32 2.307 +VCilk__giveMinWorkUnitCycles( float32 percentOverhead ); 2.308 + 2.309 +void inline 2.310 +VCilk__start_primitive(); 2.311 + 2.312 +int32 inline 2.313 +VCilk__end_primitive_and_give_cycles(); 2.314 + 2.315 +int32 2.316 +VCilk__giveIdealNumWorkUnits(); 2.317 + 2.318 +//======================= 2.319 + 2.320 +void 2.321 +VCilk__init(); 2.322 + 2.323 +void 2.324 +VCilk__cleanup_at_end_of_shutdown(); 2.325 + 2.326 +//======================= 2.327 + 2.328 +void inline 2.329 +VCilk__spawn( int32 coreToSpawnOnto, VirtProcrFnPtr fnPtr, 2.330 + void *initData, VirtProcr *creatingPr ); 2.331 + 2.332 +int32 2.333 +VCilk__give_number_of_cores_to_spawn_onto(); 2.334 + 2.335 +void 2.336 +VCilk__sync( VirtProcr *animatingPr ); 2.337 + 2.338 +void * 2.339 +VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr ); 2.340 + 2.341 +void 2.342 +VCilk__free( void *ptrToFree, VirtProcr *animPr ); 2.343 + 2.344 +void 2.345 +VCilk__dissipate_procr( VirtProcr *procrToDissipate ); 2.346 + 2.347 + 2.348 +//======================= Concurrency Stuff ====================== 2.349 +void 2.350 +VCilk__start_fn_singleton( int32 singletonID, VirtProcr *animPr ); 2.351 + 2.352 +void 2.353 +VCilk__end_fn_singleton( int32 singletonID, VirtProcr *animPr ); 2.354 + 2.355 +void 2.356 +VCilk__start_data_singleton( VCilkSingleton **singeltonAddr, VirtProcr *animPr ); 2.357 + 2.358 +void 2.359 +VCilk__end_data_singleton( VCilkSingleton **singletonAddr, VirtProcr *animPr ); 2.360 + 2.361 +void 2.362 +VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 2.363 + void *data, VirtProcr *animPr ); 2.364 + 2.365 +void 2.366 +VCilk__start_transaction( int32 transactionID, VirtProcr *animPr ); 2.367 + 2.368 +void 2.369 +VCilk__end_transaction( int32 transactionID, VirtProcr *animPr ); 2.370 + 2.371 + 2.372 +//========================= Internal use only ============================= 2.373 +void 2.374 +VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv ); 2.375 + 2.376 +VirtProcr * 2.377 +VCilk__schedule_virt_procr( void *_semEnv, int coreNum ); 2.378 + 2.379 + 2.380 +#endif /* _VCilk_H */ 2.381 +
3.1 --- a/VCilk_PluginFns.c Tue Nov 16 15:59:23 2010 +0100 3.2 +++ b/VCilk_PluginFns.c Wed May 11 15:29:58 2011 +0200 3.3 @@ -1,467 +1,555 @@ 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/Queue_impl/PrivateQueue.h" 3.14 -#include "VCilk.h" 3.15 - 3.16 - 3.17 - 3.18 -//=========================================================================== 3.19 -void inline 3.20 -handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv ); 3.21 - 3.22 -void inline 3.23 -handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.24 - VCilkSemEnv *semEnv ); 3.25 -void inline 3.26 -handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.27 - VCilkSemEnv *semEnv ); 3.28 -void inline 3.29 -handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv ); 3.30 - 3.31 -void inline 3.32 -handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv ); 3.33 - 3.34 -void inline 3.35 -dispatchSemReq( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv); 3.36 - 3.37 -void inline 3.38 -handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.39 - VCilkSemEnv*semEnv); 3.40 -void inline 3.41 -handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.42 - VCilkSemEnv *semEnv ); 3.43 -void inline 3.44 -handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.45 - VCilkSemEnv *semEnv); 3.46 -void inline 3.47 -handleSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.48 - VCilkSemEnv *semEnv ); 3.49 - 3.50 -void inline 3.51 -resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv ); 3.52 - 3.53 -//=========================================================================== 3.54 - 3.55 - 3.56 -//============================== Scheduler ================================== 3.57 -// 3.58 -/*For VCilk, scheduling a slave simply takes the next work-unit off the 3.59 - * ready-to-go work-unit queue and assigns it to the slaveToSched. 3.60 - *If the ready-to-go work-unit queue is empty, then nothing to schedule 3.61 - * to the slave -- return FALSE to let Master loop know scheduling that 3.62 - * slave failed. 3.63 - */ 3.64 -VirtProcr * 3.65 -VCilk__schedule_virt_procr( void *_semEnv, int coreNum ) 3.66 - { VirtProcr *schedPr; 3.67 - VCilkSemEnv *semEnv; 3.68 - 3.69 - semEnv = (VCilkSemEnv *)_semEnv; 3.70 - 3.71 - schedPr = readPrivQ( semEnv->readyVPQs[coreNum] ); 3.72 - //Note, using a non-blocking queue -- it returns NULL if queue empty 3.73 - 3.74 - return( schedPr ); 3.75 - } 3.76 - 3.77 - 3.78 -//=========================== Request Handler ============================= 3.79 -// 3.80 -/*Will get requests to send, to receive, and to create new processors. 3.81 - * Upon send, check the hash to see if a receive is waiting. 3.82 - * Upon receive, check hash to see if a send has already happened. 3.83 - * When other is not there, put in. When other is there, the comm. 3.84 - * completes, which means the receiver P gets scheduled and 3.85 - * picks up right after the receive request. So make the work-unit 3.86 - * and put it into the queue of work-units ready to go. 3.87 - * Other request is create a new Processor, with the function to run in the 3.88 - * Processor, and initial data. 3.89 - */ 3.90 -void 3.91 -VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv ) 3.92 - { VCilkSemEnv *semEnv; 3.93 - VMSReqst *req; 3.94 - VCilkSemReq *semReq; 3.95 - 3.96 - //============================= MEASUREMENT STUFF ======================== 3.97 - #ifdef MEAS__TIME_PLUGIN 3.98 - int32 startStamp, endStamp; 3.99 - saveLowTimeStampCountInto( startStamp ); 3.100 - #endif 3.101 - //======================================================================== 3.102 - 3.103 - semEnv = (VCilkSemEnv *)_semEnv; 3.104 - 3.105 - req = VMS__take_next_request_out_of( requestingPr ); 3.106 - 3.107 - while( req != NULL ) 3.108 - { 3.109 - switch( req->reqType ) 3.110 - { case semantic: dispatchSemReq( req, requestingPr, semEnv ); 3.111 - break; 3.112 - case createReq: //create request has to come as a VMS request, 3.113 - // to allow MasterLoop to do stuff before gets 3.114 - // here, and maybe also stuff after all requests 3.115 - // done -- however, can still attach semantic 3.116 - // req data to req. 3.117 - handleSpawn( req, requestingPr, semEnv); 3.118 - break; 3.119 - case dissipate: handleDissipate( requestingPr, semEnv); 3.120 - break; 3.121 - case VMSSemantic: VMS__handle_VMSSemReq(req, requestingPr, semEnv, 3.122 - &resume_procr); 3.123 - break; 3.124 - default: 3.125 - break; 3.126 - } 3.127 - 3.128 - DoneHandlingReqst: 3.129 - 3.130 - req = VMS__take_next_request_out_of( requestingPr ); 3.131 - } //while( req != NULL ) 3.132 - 3.133 - //============================= MEASUREMENT STUFF ======================== 3.134 - #ifdef MEAS__TIME_PLUGIN 3.135 - saveLowTimeStampCountInto( endStamp ); 3.136 - addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->pluginLowTimeHist ); 3.137 - addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->pluginHighTimeHist ); 3.138 - #endif 3.139 - //======================================================================== 3.140 - } 3.141 - 3.142 -void inline 3.143 -dispatchSemReq( VMSReqst *req, VirtProcr *reqPr, VCilkSemEnv *semEnv ) 3.144 - { VCilkSemReq *semReq; 3.145 - 3.146 - semReq = VMS__take_sem_reqst_from(req); 3.147 - 3.148 - if( semReq == NULL ) return; 3.149 - switch( semReq->reqType ) 3.150 - { 3.151 - case syncReq: handleSync( reqPr, semEnv ); 3.152 - break; 3.153 - case mallocReq: handleMalloc( semReq, reqPr, semEnv ); 3.154 - break; 3.155 - case freeReq: handleFree( semReq, reqPr, semEnv ); 3.156 - break; 3.157 - case singleton: handleSingleton( semReq, reqPr, semEnv ); 3.158 - break; 3.159 - case atomic: handleAtomic( semReq, reqPr, semEnv ); 3.160 - break; 3.161 - case trans_start: handleTransStart( semReq, reqPr, semEnv ); 3.162 - break; 3.163 - case trans_end: handleTransEnd( semReq, reqPr, semEnv ); 3.164 - break; 3.165 - } 3.166 - //NOTE: semantic request data strucs allocated on stack in VCilk Lib calls 3.167 - } 3.168 - 3.169 - 3.170 - 3.171 -//=========================== Request Handlers ============================== 3.172 -void inline 3.173 -resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv ) 3.174 - { 3.175 - writePrivQ( procr, semEnv->readyVPQs[ procr->coreAnimatedBy] ); 3.176 - } 3.177 - 3.178 - 3.179 - 3.180 - 3.181 -/* check if list of live children is empty. 3.182 - * If yes, then resume. 3.183 - * If no, then set sync-pending flag. 3.184 - */ 3.185 -void 3.186 -handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv ) 3.187 - { 3.188 - if(((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren == 0 ) 3.189 - { //no live children to wait for 3.190 - resume_procr( requestingPr, semEnv ); 3.191 - } 3.192 - else 3.193 - { 3.194 - ((VCilkSemData *)(requestingPr->semanticData))->syncPending = TRUE; 3.195 - } 3.196 - } 3.197 - 3.198 -/* 3.199 - */ 3.200 -void 3.201 -handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.202 - VCilkSemEnv *semEnv ) 3.203 - { void *ptr; 3.204 - 3.205 - ptr = VMS__malloc( semReq->sizeToMalloc ); 3.206 - requestingPr->dataRetFromReq = ptr; 3.207 - resume_procr( requestingPr, semEnv ); 3.208 - } 3.209 - 3.210 -/* 3.211 - */ 3.212 -void inline 3.213 -handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.214 - VCilkSemEnv *semEnv ) 3.215 - { 3.216 - VMS__free( semReq->ptrToFree ); 3.217 - resume_procr( requestingPr, semEnv ); 3.218 - } 3.219 - 3.220 - 3.221 -//============================== VMS requests =============================== 3.222 -/*Re-use this in the entry-point fn 3.223 - */ 3.224 -inline VirtProcr * 3.225 -VCilk__create_procr_helper( VirtProcrFnPtr fnPtr, void *initData, 3.226 - VirtProcr *requestingPr, VCilkSemEnv *semEnv, int32 coreToScheduleOnto ) 3.227 - { VirtProcr *newPr; 3.228 - VCilkSemData *semData; 3.229 - 3.230 - //This is running in master, so use internal version 3.231 - newPr = VMS__create_procr( fnPtr, initData ); 3.232 - 3.233 - semData = VMS__malloc( sizeof(VCilkSemData) ); 3.234 - 3.235 - semData->numLiveChildren = 0; 3.236 - semData->parentPr = requestingPr; 3.237 - semData->syncPending = FALSE; 3.238 - 3.239 - semData->highestTransEntered = -1; 3.240 - semData->lastTransEntered = NULL; 3.241 - 3.242 - newPr->semanticData = semData; 3.243 - 3.244 - /* increase the number of live children of requester. 3.245 - */ 3.246 - if( requestingPr != NULL ) //NULL when creating seed procr 3.247 - ((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren +=1; 3.248 - 3.249 - semEnv->numVirtPr += 1; 3.250 - 3.251 - //=================== Assign new processor to a core ===================== 3.252 - #ifdef SEQUENTIAL 3.253 - newPr->coreAnimatedBy = 0; 3.254 - 3.255 - #else 3.256 - 3.257 - if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES ) 3.258 - { //out-of-range, so round-robin assignment 3.259 - newPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr; 3.260 - 3.261 - if( semEnv->nextCoreToGetNewPr >= NUM_CORES - 1 ) 3.262 - semEnv->nextCoreToGetNewPr = 0; 3.263 - else 3.264 - semEnv->nextCoreToGetNewPr += 1; 3.265 - } 3.266 - else //core num in-range, so use it 3.267 - { newPr->coreAnimatedBy = coreToScheduleOnto; 3.268 - } 3.269 - #endif 3.270 - //======================================================================== 3.271 - 3.272 - return newPr; 3.273 - } 3.274 - 3.275 - 3.276 -void inline 3.277 -handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv ) 3.278 - { VCilkSemReq *semReq; 3.279 - VirtProcr *newPr; 3.280 - 3.281 - semReq = VMS__take_sem_reqst_from( req ); 3.282 - 3.283 - newPr = VCilk__create_procr_helper( semReq->fnPtr, semReq->initData, 3.284 - requestingPr, semEnv, semReq->coreToSpawnOnto ); 3.285 - 3.286 - //For VPThread, caller needs ptr to created processor returned to it 3.287 - requestingPr->dataRetFromReq = newPr; 3.288 - 3.289 - resume_procr( newPr, semEnv ); 3.290 - resume_procr( requestingPr, semEnv ); 3.291 - } 3.292 - 3.293 - 3.294 - 3.295 -/*get parentVP & remove dissipator from parent's live children. 3.296 - *If this was last live child, check "sync pending" flag 3.297 - *-- if set, then resume the parentVP. 3.298 - */ 3.299 -void inline 3.300 -handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv ) 3.301 - { 3.302 - VirtProcr * 3.303 - parentPr = ((VCilkSemData *) 3.304 - (requestingPr->semanticData))->parentPr; 3.305 - if( parentPr == NULL ) //means this is seed processor being dissipated 3.306 - { //Just act normally, except don't deal with parent 3.307 - // VMS__Free is implemented to ignore requests to free data from 3.308 - // outside VMS, so all this processor's non-VMS allocated data will 3.309 - // remain and be cleaned up outside 3.310 - } 3.311 - else 3.312 - { 3.313 - ((VCilkSemData *)(parentPr->semanticData))->numLiveChildren -= 1; 3.314 - if( ((VCilkSemData *) 3.315 - (parentPr->semanticData))->numLiveChildren <= 0 ) 3.316 - { //this was last live child of parent 3.317 - if( ((VCilkSemData *) 3.318 - (parentPr->semanticData))->syncPending == TRUE ) 3.319 - { //was waiting for last child to dissipate, so resume it 3.320 - ((VCilkSemData *) 3.321 - (parentPr->semanticData))->syncPending = FALSE; 3.322 - resume_procr( parentPr, semEnv ); 3.323 - } 3.324 - } 3.325 - } 3.326 - 3.327 - VMS__free( requestingPr->semanticData ); 3.328 - 3.329 - //Now do normal dissipate 3.330 - 3.331 - //call VMS to free_all AppVP state -- stack and so on 3.332 - VMS__dissipate_procr( requestingPr ); 3.333 - 3.334 - semEnv->numVirtPr -= 1; 3.335 - if( semEnv->numVirtPr == 0 ) 3.336 - { //no more work, so shutdown 3.337 - VMS__shutdown(); 3.338 - } 3.339 - } 3.340 - 3.341 - 3.342 -//=============================== Atomic ==================================== 3.343 -// 3.344 -/*Uses ID as index into array of flags. If flag already set, resumes from 3.345 - * end-label. Else, sets flag and resumes normally. 3.346 - */ 3.347 -void inline 3.348 -handleSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.349 - VCilkSemEnv *semEnv ) 3.350 - { 3.351 - if( semEnv->singletonHasBeenExecutedFlags[ semReq->singletonID ] ) 3.352 - requestingPr->nextInstrPt = semReq->endJumpPt; 3.353 - else 3.354 - semEnv->singletonHasBeenExecutedFlags[ semReq->singletonID ] = TRUE; 3.355 - 3.356 - resume_procr( requestingPr, semEnv ); 3.357 - } 3.358 - 3.359 - 3.360 -/*This executes the function in the masterVP, take the function 3.361 - * pointer out of the request and call it, then resume the VP. 3.362 - */ 3.363 -void inline 3.364 -handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.365 - VCilkSemEnv *semEnv ) 3.366 - { 3.367 - semReq->fnToExecInMaster( semReq->dataForFn ); 3.368 - resume_procr( requestingPr, semEnv ); 3.369 - } 3.370 - 3.371 -/*First, it looks at the VP's semantic data, to see the highest transactionID 3.372 - * that VP 3.373 - * already has entered. If the current ID is not larger, it throws an 3.374 - * exception stating a bug in the code. 3.375 - *Otherwise it puts the current ID 3.376 - * there, and adds the ID to a linked list of IDs entered -- the list is 3.377 - * used to check that exits are properly ordered. 3.378 - *Next it is uses transactionID as index into an array of transaction 3.379 - * structures. 3.380 - *If the "VP_currently_executing" field is non-null, then put requesting VP 3.381 - * into queue in the struct. (At some point a holder will request 3.382 - * end-transaction, which will take this VP from the queue and resume it.) 3.383 - *If NULL, then write requesting into the field and resume. 3.384 - */ 3.385 -void inline 3.386 -handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.387 - VCilkSemEnv *semEnv ) 3.388 - { VCilkSemData *semData; 3.389 - TransListElem *nextTransElem; 3.390 - 3.391 - //check ordering of entering transactions is correct 3.392 - semData = requestingPr->semanticData; 3.393 - if( semData->highestTransEntered > semReq->transID ) 3.394 - { //throw VMS exception, which shuts down VMS. 3.395 - VMS__throw_exception( "transID smaller than prev", requestingPr, NULL); 3.396 - } 3.397 - //add this trans ID to the list of transactions entered -- check when 3.398 - // end a transaction 3.399 - semData->highestTransEntered = semReq->transID; 3.400 - nextTransElem = VMS__malloc( sizeof(TransListElem) ); 3.401 - nextTransElem->transID = semReq->transID; 3.402 - nextTransElem->nextTrans = semData->lastTransEntered; 3.403 - semData->lastTransEntered = nextTransElem; 3.404 - 3.405 - //get the structure for this transaction ID 3.406 - VCilkTrans * 3.407 - transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 3.408 - 3.409 - if( transStruc->VPCurrentlyExecuting == NULL ) 3.410 - { 3.411 - transStruc->VPCurrentlyExecuting = requestingPr; 3.412 - resume_procr( requestingPr, semEnv ); 3.413 - } 3.414 - else 3.415 - { //note, might make future things cleaner if save request with VP and 3.416 - // add this trans ID to the linked list when gets out of queue. 3.417 - // but don't need for now, and lazy.. 3.418 - writePrivQ( requestingPr, transStruc->waitingVPQ ); 3.419 - } 3.420 - } 3.421 - 3.422 - 3.423 -/*Use the trans ID to get the transaction structure from the array. 3.424 - *Look at VP_currently_executing to be sure it's same as requesting VP. 3.425 - * If different, throw an exception, stating there's a bug in the code. 3.426 - *Next, take the first element off the list of entered transactions. 3.427 - * Check to be sure the ending transaction is the same ID as the next on 3.428 - * the list. If not, incorrectly nested so throw an exception. 3.429 - * 3.430 - *Next, get from the queue in the structure. 3.431 - *If it's empty, set VP_currently_executing field to NULL and resume 3.432 - * requesting VP. 3.433 - *If get somethine, set VP_currently_executing to the VP from the queue, then 3.434 - * resume both. 3.435 - */ 3.436 -void inline 3.437 -handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.438 - VCilkSemEnv *semEnv ) 3.439 - { VCilkSemData *semData; 3.440 - VirtProcr *waitingPr; 3.441 - VCilkTrans *transStruc; 3.442 - TransListElem *lastTrans; 3.443 - 3.444 - transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 3.445 - 3.446 - //make sure transaction ended in same VP as started it. 3.447 - if( transStruc->VPCurrentlyExecuting != requestingPr ) 3.448 - { 3.449 - VMS__throw_exception( "trans ended in diff VP", requestingPr, NULL ); 3.450 - } 3.451 - 3.452 - //make sure nesting is correct -- last ID entered should == this ID 3.453 - semData = requestingPr->semanticData; 3.454 - lastTrans = semData->lastTransEntered; 3.455 - if( lastTrans->transID != semReq->transID ) 3.456 - { 3.457 - VMS__throw_exception( "trans incorrectly nested", requestingPr, NULL ); 3.458 - } 3.459 - 3.460 - semData->lastTransEntered = semData->lastTransEntered->nextTrans; 3.461 - 3.462 - 3.463 - waitingPr = readPrivQ( transStruc->waitingVPQ ); 3.464 - transStruc->VPCurrentlyExecuting = waitingPr; 3.465 - 3.466 - if( waitingPr != NULL ) 3.467 - resume_procr( waitingPr, semEnv ); 3.468 - 3.469 - resume_procr( requestingPr, semEnv ); 3.470 - } 3.471 +/* 3.472 + * Copyright 2010 OpenSourceCodeStewardshipFoundation 3.473 + * 3.474 + * Licensed under BSD 3.475 + */ 3.476 + 3.477 +#include <stdio.h> 3.478 +#include <stdlib.h> 3.479 + 3.480 +#include "VMS/Queue_impl/PrivateQueue.h" 3.481 +#include "VCilk.h" 3.482 + 3.483 + 3.484 + 3.485 +//=========================================================================== 3.486 +void inline 3.487 +handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv ); 3.488 + 3.489 +void inline 3.490 +handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.491 + VCilkSemEnv *semEnv ); 3.492 +void inline 3.493 +handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.494 + VCilkSemEnv *semEnv ); 3.495 +void inline 3.496 +handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv ); 3.497 + 3.498 +void inline 3.499 +handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv ); 3.500 + 3.501 +void inline 3.502 +dispatchSemReq( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv); 3.503 + 3.504 +void inline 3.505 +handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.506 + VCilkSemEnv*semEnv); 3.507 +void inline 3.508 +handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.509 + VCilkSemEnv *semEnv ); 3.510 +void inline 3.511 +handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.512 + VCilkSemEnv *semEnv); 3.513 +inline void 3.514 +handleStartFnSingleton( VCilkSemReq *semReq, VirtProcr *reqstingPr, 3.515 + VCilkSemEnv *semEnv ); 3.516 +inline void 3.517 +handleEndFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.518 + VCilkSemEnv *semEnv ); 3.519 +inline void 3.520 +handleStartDataSingleton( VCilkSemReq *semReq, VirtProcr *reqstingPr, 3.521 + VCilkSemEnv *semEnv ); 3.522 +inline void 3.523 +handleEndDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.524 + VCilkSemEnv *semEnv ); 3.525 + 3.526 +void inline 3.527 +resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv ); 3.528 + 3.529 +//=========================================================================== 3.530 + 3.531 + 3.532 +//============================== Scheduler ================================== 3.533 +// 3.534 +/*For VCilk, scheduling a slave simply takes the next work-unit off the 3.535 + * ready-to-go work-unit queue and assigns it to the slaveToSched. 3.536 + *If the ready-to-go work-unit queue is empty, then nothing to schedule 3.537 + * to the slave -- return FALSE to let Master loop know scheduling that 3.538 + * slave failed. 3.539 + */ 3.540 +VirtProcr * 3.541 +VCilk__schedule_virt_procr( void *_semEnv, int coreNum ) 3.542 + { VirtProcr *schedPr; 3.543 + VCilkSemEnv *semEnv; 3.544 + 3.545 + semEnv = (VCilkSemEnv *)_semEnv; 3.546 + 3.547 + schedPr = readPrivQ( semEnv->readyVPQs[coreNum] ); 3.548 + //Note, using a non-blocking queue -- it returns NULL if queue empty 3.549 + 3.550 + return( schedPr ); 3.551 + } 3.552 + 3.553 + 3.554 +//=========================== Request Handler ============================= 3.555 +// 3.556 +/*Will get requests to send, to receive, and to create new processors. 3.557 + * Upon send, check the hash to see if a receive is waiting. 3.558 + * Upon receive, check hash to see if a send has already happened. 3.559 + * When other is not there, put in. When other is there, the comm. 3.560 + * completes, which means the receiver P gets scheduled and 3.561 + * picks up right after the receive request. So make the work-unit 3.562 + * and put it into the queue of work-units ready to go. 3.563 + * Other request is create a new Processor, with the function to run in the 3.564 + * Processor, and initial data. 3.565 + */ 3.566 +void 3.567 +VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv ) 3.568 + { VCilkSemEnv *semEnv; 3.569 + VMSReqst *req; 3.570 + VCilkSemReq *semReq; 3.571 + 3.572 + 3.573 + semEnv = (VCilkSemEnv *)_semEnv; 3.574 + 3.575 + req = VMS__take_next_request_out_of( requestingPr ); 3.576 + 3.577 + while( req != NULL ) 3.578 + { 3.579 + switch( req->reqType ) 3.580 + { case semantic: dispatchSemReq( req, requestingPr, semEnv ); 3.581 + break; 3.582 + case createReq: //create request has to come as a VMS request, 3.583 + // to allow MasterLoop to do stuff before gets 3.584 + // here, and maybe also stuff after all requests 3.585 + // done -- however, can still attach semantic 3.586 + // req data to req. 3.587 + handleSpawn( req, requestingPr, semEnv); 3.588 + break; 3.589 + case dissipate: handleDissipate( requestingPr, semEnv); 3.590 + break; 3.591 + case VMSSemantic: VMS__handle_VMSSemReq(req, requestingPr, semEnv, 3.592 + &resume_procr); 3.593 + break; 3.594 + default: 3.595 + break; 3.596 + } 3.597 + 3.598 + DoneHandlingReqst: 3.599 + 3.600 + req = VMS__take_next_request_out_of( requestingPr ); 3.601 + } //while( req != NULL ) 3.602 + } 3.603 + 3.604 +void inline 3.605 +dispatchSemReq( VMSReqst *req, VirtProcr *reqPr, VCilkSemEnv *semEnv ) 3.606 + { VCilkSemReq *semReq; 3.607 + 3.608 + semReq = VMS__take_sem_reqst_from(req); 3.609 + 3.610 + if( semReq == NULL ) return; 3.611 + switch( semReq->reqType ) 3.612 + { 3.613 + case syncReq: handleSync( reqPr, semEnv ); 3.614 + break; 3.615 + case mallocReq: handleMalloc( semReq, reqPr, semEnv ); 3.616 + break; 3.617 + case freeReq: handleFree( semReq, reqPr, semEnv ); 3.618 + break; 3.619 + case singleton_fn_start: handleStartFnSingleton(semReq, reqPr, semEnv); 3.620 + break; 3.621 + case singleton_fn_end: handleEndFnSingleton( semReq, reqPr, semEnv); 3.622 + break; 3.623 + case singleton_data_start:handleStartDataSingleton(semReq,reqPr,semEnv); 3.624 + break; 3.625 + case singleton_data_end: handleEndDataSingleton(semReq, reqPr, semEnv); 3.626 + break; 3.627 + case atomic: handleAtomic( semReq, reqPr, semEnv ); 3.628 + break; 3.629 + case trans_start: handleTransStart( semReq, reqPr, semEnv ); 3.630 + break; 3.631 + case trans_end: handleTransEnd( semReq, reqPr, semEnv ); 3.632 + break; 3.633 + } 3.634 + //NOTE: semantic request data strucs allocated on stack in VCilk Lib calls 3.635 + } 3.636 + 3.637 + 3.638 + 3.639 +//=========================== Request Handlers ============================== 3.640 +void inline 3.641 +resume_procr( VirtProcr *procr, VCilkSemEnv *semEnv ) 3.642 + { 3.643 + writePrivQ( procr, semEnv->readyVPQs[ procr->coreAnimatedBy] ); 3.644 + } 3.645 + 3.646 + 3.647 + 3.648 + 3.649 +/* check if list of live children is empty. 3.650 + * If yes, then resume. 3.651 + * If no, then set sync-pending flag. 3.652 + */ 3.653 +inline void 3.654 +handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv ) 3.655 + { 3.656 + Meas_startSync 3.657 + if(((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren == 0 ) 3.658 + { //no live children to wait for 3.659 + resume_procr( requestingPr, semEnv ); 3.660 + } 3.661 + else 3.662 + { 3.663 + ((VCilkSemData *)(requestingPr->semanticData))->syncPending = TRUE; 3.664 + } 3.665 + Meas_endSync 3.666 + } 3.667 + 3.668 +/* 3.669 + */ 3.670 +inline void 3.671 +handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.672 + VCilkSemEnv *semEnv ) 3.673 + { void *ptr; 3.674 + 3.675 + ptr = VMS__malloc( semReq->sizeToMalloc ); 3.676 + requestingPr->dataRetFromReq = ptr; 3.677 + resume_procr( requestingPr, semEnv ); 3.678 + } 3.679 + 3.680 +/* 3.681 + */ 3.682 +void inline 3.683 +handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.684 + VCilkSemEnv *semEnv ) 3.685 + { 3.686 + VMS__free( semReq->ptrToFree ); 3.687 + resume_procr( requestingPr, semEnv ); 3.688 + } 3.689 + 3.690 + 3.691 +//============================== VMS requests =============================== 3.692 +/*Re-use this in the entry-point fn 3.693 + */ 3.694 +inline VirtProcr * 3.695 +VCilk__create_procr_helper( VirtProcrFnPtr fnPtr, void *initData, 3.696 + VirtProcr *requestingPr, VCilkSemEnv *semEnv, int32 coreToScheduleOnto ) 3.697 + { VirtProcr *newPr; 3.698 + VCilkSemData *semData; 3.699 + 3.700 + //This is running in master, so use internal version 3.701 + newPr = VMS__create_procr( fnPtr, initData ); 3.702 + 3.703 + semData = VMS__malloc( sizeof(VCilkSemData) ); 3.704 + 3.705 + semData->numLiveChildren = 0; 3.706 + semData->parentPr = requestingPr; 3.707 + semData->syncPending = FALSE; 3.708 + 3.709 + semData->highestTransEntered = -1; 3.710 + semData->lastTransEntered = NULL; 3.711 + 3.712 + newPr->semanticData = semData; 3.713 + 3.714 + /* increase the number of live children of requester. 3.715 + */ 3.716 + if( requestingPr != NULL ) //NULL when creating seed procr 3.717 + ((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren +=1; 3.718 + 3.719 + semEnv->numVirtPr += 1; 3.720 + 3.721 + //=================== Assign new processor to a core ===================== 3.722 + #ifdef SEQUENTIAL 3.723 + newPr->coreAnimatedBy = 0; 3.724 + 3.725 + #else 3.726 + 3.727 + if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES ) 3.728 + { //out-of-range, so round-robin assignment 3.729 + newPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr; 3.730 + 3.731 + if( semEnv->nextCoreToGetNewPr >= NUM_CORES - 1 ) 3.732 + semEnv->nextCoreToGetNewPr = 0; 3.733 + else 3.734 + semEnv->nextCoreToGetNewPr += 1; 3.735 + } 3.736 + else //core num in-range, so use it 3.737 + { newPr->coreAnimatedBy = coreToScheduleOnto; 3.738 + } 3.739 + #endif 3.740 + //======================================================================== 3.741 + 3.742 + return newPr; 3.743 + } 3.744 + 3.745 + 3.746 +void inline 3.747 +handleSpawn( VMSReqst *req, VirtProcr *requestingPr, VCilkSemEnv *semEnv ) 3.748 + { VCilkSemReq *semReq; 3.749 + VirtProcr *newPr; 3.750 + 3.751 + Meas_startSpawn 3.752 + semReq = VMS__take_sem_reqst_from( req ); 3.753 + 3.754 + newPr = VCilk__create_procr_helper( semReq->fnPtr, semReq->initData, 3.755 + requestingPr, semEnv, semReq->coreToSpawnOnto ); 3.756 + 3.757 + //For VPThread, caller needs ptr to created processor returned to it 3.758 + requestingPr->dataRetFromReq = newPr; 3.759 + 3.760 + resume_procr( newPr, semEnv ); 3.761 + resume_procr( requestingPr, semEnv ); 3.762 + Meas_endSpawn 3.763 + } 3.764 + 3.765 + 3.766 + 3.767 +/*get parentVP & remove dissipator from parent's live children. 3.768 + *If this was last live child, check "sync pending" flag 3.769 + *-- if set, then resume the parentVP. 3.770 + */ 3.771 +void inline 3.772 +handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv ) 3.773 + { 3.774 + VirtProcr * 3.775 + parentPr = ((VCilkSemData *) 3.776 + (requestingPr->semanticData))->parentPr; 3.777 + if( parentPr == NULL ) //means this is seed processor being dissipated 3.778 + { //Just act normally, except don't deal with parent 3.779 + // VMS__Free is implemented to ignore requests to free data from 3.780 + // outside VMS, so all this processor's non-VMS allocated data will 3.781 + // remain and be cleaned up outside 3.782 + } 3.783 + else 3.784 + { 3.785 + ((VCilkSemData *)(parentPr->semanticData))->numLiveChildren -= 1; 3.786 + if( ((VCilkSemData *) 3.787 + (parentPr->semanticData))->numLiveChildren <= 0 ) 3.788 + { //this was last live child of parent 3.789 + if( ((VCilkSemData *) 3.790 + (parentPr->semanticData))->syncPending == TRUE ) 3.791 + { //was waiting for last child to dissipate, so resume it 3.792 + ((VCilkSemData *) 3.793 + (parentPr->semanticData))->syncPending = FALSE; 3.794 + resume_procr( parentPr, semEnv ); 3.795 + } 3.796 + } 3.797 + } 3.798 + 3.799 + VMS__free( requestingPr->semanticData ); 3.800 + 3.801 + //Now do normal dissipate 3.802 + 3.803 + //call VMS to free_all AppVP state -- stack and so on 3.804 + VMS__dissipate_procr( requestingPr ); 3.805 + 3.806 + semEnv->numVirtPr -= 1; 3.807 + if( semEnv->numVirtPr == 0 ) 3.808 + { //no more work, so shutdown 3.809 + VMS__shutdown(); 3.810 + } 3.811 + } 3.812 + 3.813 + 3.814 +//=============================== Atomic ==================================== 3.815 +// 3.816 +/*Uses ID as index into array of flags. If flag already set, resumes from 3.817 + * end-label. Else, sets flag and resumes normally. 3.818 + */ 3.819 +void inline 3.820 +handleStartSingleton_helper( VCilkSingleton *singleton, VirtProcr *reqstingPr, 3.821 + VCilkSemEnv *semEnv ) 3.822 + { 3.823 + if( singleton->hasFinished ) 3.824 + { //the code that sets the flag to true first sets the end instr addr 3.825 + reqstingPr->dataRetFromReq = singleton->endInstrAddr; 3.826 + resume_procr( reqstingPr, semEnv ); 3.827 + return; 3.828 + } 3.829 + else if( singleton->hasBeenStarted ) 3.830 + { //singleton is in-progress in a diff slave, so wait for it to finish 3.831 + writePrivQ(reqstingPr, singleton->waitQ ); 3.832 + return; 3.833 + } 3.834 + else 3.835 + { //hasn't been started, so this is the first attempt at the singleton 3.836 + singleton->hasBeenStarted = TRUE; 3.837 + reqstingPr->dataRetFromReq = 0x0; 3.838 + resume_procr( reqstingPr, semEnv ); 3.839 + return; 3.840 + } 3.841 + } 3.842 +void inline 3.843 +handleStartFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.844 + VCilkSemEnv *semEnv ) 3.845 + { VCilkSingleton *singleton; 3.846 + 3.847 + singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); 3.848 + handleStartSingleton_helper( singleton, requestingPr, semEnv ); 3.849 + } 3.850 +void inline 3.851 +handleStartDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.852 + VCilkSemEnv *semEnv ) 3.853 + { VCilkSingleton *singleton; 3.854 + 3.855 + if( *(semReq->singletonPtrAddr) == NULL ) 3.856 + { singleton = VMS__malloc( sizeof(VCilkSingleton) ); 3.857 + singleton->waitQ = makeVMSPrivQ(); 3.858 + singleton->endInstrAddr = 0x0; 3.859 + singleton->hasBeenStarted = FALSE; 3.860 + singleton->hasFinished = FALSE; 3.861 + *(semReq->singletonPtrAddr) = singleton; 3.862 + } 3.863 + else 3.864 + singleton = *(semReq->singletonPtrAddr); 3.865 + handleStartSingleton_helper( singleton, requestingPr, semEnv ); 3.866 + } 3.867 + 3.868 + 3.869 +void inline 3.870 +handleEndSingleton_helper( VCilkSingleton *singleton, VirtProcr *requestingPr, 3.871 + VCilkSemEnv *semEnv ) 3.872 + { PrivQueueStruc *waitQ; 3.873 + int32 numWaiting, i; 3.874 + VirtProcr *resumingPr; 3.875 + 3.876 + if( singleton->hasFinished ) 3.877 + { //by definition, only one slave should ever be able to run end singleton 3.878 + // so if this is true, is an error 3.879 + //VMS__throw_exception( "singleton code ran twice", requestingPr, NULL); 3.880 + } 3.881 + 3.882 + singleton->hasFinished = TRUE; 3.883 + waitQ = singleton->waitQ; 3.884 + numWaiting = numInPrivQ( waitQ ); 3.885 + for( i = 0; i < numWaiting; i++ ) 3.886 + { //they will resume inside start singleton, then jmp to end singleton 3.887 + resumingPr = readPrivQ( waitQ ); 3.888 + resumingPr->dataRetFromReq = singleton->endInstrAddr; 3.889 + resume_procr( resumingPr, semEnv ); 3.890 + } 3.891 + 3.892 + resume_procr( requestingPr, semEnv ); 3.893 + 3.894 +} 3.895 +void inline 3.896 +handleEndFnSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.897 + VCilkSemEnv *semEnv ) 3.898 + { 3.899 + VCilkSingleton *singleton; 3.900 + 3.901 + singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); 3.902 + handleEndSingleton_helper( singleton, requestingPr, semEnv ); 3.903 + } 3.904 +void inline 3.905 +handleEndDataSingleton( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.906 + VCilkSemEnv *semEnv ) 3.907 + { 3.908 + VCilkSingleton *singleton; 3.909 + 3.910 + singleton = *(semReq->singletonPtrAddr); 3.911 + handleEndSingleton_helper( singleton, requestingPr, semEnv ); 3.912 + } 3.913 + 3.914 + 3.915 +/*This executes the function in the masterVP, take the function 3.916 + * pointer out of the request and call it, then resume the VP. 3.917 + */ 3.918 +void inline 3.919 +handleAtomic( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.920 + VCilkSemEnv *semEnv ) 3.921 + { 3.922 + semReq->fnToExecInMaster( semReq->dataForFn ); 3.923 + resume_procr( requestingPr, semEnv ); 3.924 + } 3.925 + 3.926 +/*First, it looks at the VP's semantic data, to see the highest transactionID 3.927 + * that VP 3.928 + * already has entered. If the current ID is not larger, it throws an 3.929 + * exception stating a bug in the code. 3.930 + *Otherwise it puts the current ID 3.931 + * there, and adds the ID to a linked list of IDs entered -- the list is 3.932 + * used to check that exits are properly ordered. 3.933 + *Next it is uses transactionID as index into an array of transaction 3.934 + * structures. 3.935 + *If the "VP_currently_executing" field is non-null, then put requesting VP 3.936 + * into queue in the struct. (At some point a holder will request 3.937 + * end-transaction, which will take this VP from the queue and resume it.) 3.938 + *If NULL, then write requesting into the field and resume. 3.939 + */ 3.940 +void inline 3.941 +handleTransStart( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.942 + VCilkSemEnv *semEnv ) 3.943 + { VCilkSemData *semData; 3.944 + TransListElem *nextTransElem; 3.945 + 3.946 + //check ordering of entering transactions is correct 3.947 + semData = requestingPr->semanticData; 3.948 + if( semData->highestTransEntered > semReq->transID ) 3.949 + { //throw VMS exception, which shuts down VMS. 3.950 + VMS__throw_exception( "transID smaller than prev", requestingPr, NULL); 3.951 + } 3.952 + //add this trans ID to the list of transactions entered -- check when 3.953 + // end a transaction 3.954 + semData->highestTransEntered = semReq->transID; 3.955 + nextTransElem = VMS__malloc( sizeof(TransListElem) ); 3.956 + nextTransElem->transID = semReq->transID; 3.957 + nextTransElem->nextTrans = semData->lastTransEntered; 3.958 + semData->lastTransEntered = nextTransElem; 3.959 + 3.960 + //get the structure for this transaction ID 3.961 + VCilkTrans * 3.962 + transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 3.963 + 3.964 + if( transStruc->VPCurrentlyExecuting == NULL ) 3.965 + { 3.966 + transStruc->VPCurrentlyExecuting = requestingPr; 3.967 + resume_procr( requestingPr, semEnv ); 3.968 + } 3.969 + else 3.970 + { //note, might make future things cleaner if save request with VP and 3.971 + // add this trans ID to the linked list when gets out of queue. 3.972 + // but don't need for now, and lazy.. 3.973 + writePrivQ( requestingPr, transStruc->waitingVPQ ); 3.974 + } 3.975 + } 3.976 + 3.977 + 3.978 +/*Use the trans ID to get the transaction structure from the array. 3.979 + *Look at VP_currently_executing to be sure it's same as requesting VP. 3.980 + * If different, throw an exception, stating there's a bug in the code. 3.981 + *Next, take the first element off the list of entered transactions. 3.982 + * Check to be sure the ending transaction is the same ID as the next on 3.983 + * the list. If not, incorrectly nested so throw an exception. 3.984 + * 3.985 + *Next, get from the queue in the structure. 3.986 + *If it's empty, set VP_currently_executing field to NULL and resume 3.987 + * requesting VP. 3.988 + *If get somethine, set VP_currently_executing to the VP from the queue, then 3.989 + * resume both. 3.990 + */ 3.991 +void inline 3.992 +handleTransEnd( VCilkSemReq *semReq, VirtProcr *requestingPr, 3.993 + VCilkSemEnv *semEnv ) 3.994 + { VCilkSemData *semData; 3.995 + VirtProcr *waitingPr; 3.996 + VCilkTrans *transStruc; 3.997 + TransListElem *lastTrans; 3.998 + 3.999 + transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 3.1000 + 3.1001 + //make sure transaction ended in same VP as started it. 3.1002 + if( transStruc->VPCurrentlyExecuting != requestingPr ) 3.1003 + { 3.1004 + VMS__throw_exception( "trans ended in diff VP", requestingPr, NULL ); 3.1005 + } 3.1006 + 3.1007 + //make sure nesting is correct -- last ID entered should == this ID 3.1008 + semData = requestingPr->semanticData; 3.1009 + lastTrans = semData->lastTransEntered; 3.1010 + if( lastTrans->transID != semReq->transID ) 3.1011 + { 3.1012 + VMS__throw_exception( "trans incorrectly nested", requestingPr, NULL ); 3.1013 + } 3.1014 + 3.1015 + semData->lastTransEntered = semData->lastTransEntered->nextTrans; 3.1016 + 3.1017 + 3.1018 + waitingPr = readPrivQ( transStruc->waitingVPQ ); 3.1019 + transStruc->VPCurrentlyExecuting = waitingPr; 3.1020 + 3.1021 + if( waitingPr != NULL ) 3.1022 + resume_procr( waitingPr, semEnv ); 3.1023 + 3.1024 + resume_procr( requestingPr, semEnv ); 3.1025 + }
4.1 --- a/VCilk__DESIGN_NOTES.txt Tue Nov 16 15:59:23 2010 +0100 4.2 +++ b/VCilk__DESIGN_NOTES.txt Wed May 11 15:29:58 2011 +0200 4.3 @@ -1,28 +1,28 @@ 4.4 - 4.5 - 4.6 - 4.7 - the design: 4.8 - 4.9 -Only has the spawn and sync calls, nothing else. 4.10 - 4.11 -For spawn, creates a new VP 4.12 - 4.13 -For sync, waits for all VPs created by itself to dissipate. 4.14 - 4.15 -To implement these, in request handler: 4.16 -For spawn: 4.17 - create new virtual processor 4.18 - In requester, add newly created to the list of live children 4.19 - In newly created, add pointer to requester, as the parentVP 4.20 - 4.21 -For Dissipate: 4.22 - remove dissipator from its parent's list of live children. 4.23 - If this was last in list, check "sync pending" flag 4.24 - -- if set, then resume the parentVP. 4.25 - 4.26 -For Sync: 4.27 - check if list of live of children is empty. 4.28 - If yes, then resume. 4.29 - If no, then set sync-pending flag and remain suspended 4.30 - 4.31 -That's it. Quick and simple, 4.32 + 4.33 4.34 + 4.35 4.36 + 4.37 4.38 + the design: 4.39 4.40 + 4.41 4.42 +Only has the spawn and sync calls, nothing else. 4.43 4.44 + 4.45 4.46 +For spawn, creates a new VP 4.47 4.48 + 4.49 4.50 +For sync, waits for all VPs created by itself to dissipate. 4.51 4.52 + 4.53 4.54 +To implement these, in request handler: 4.55 4.56 +For spawn: 4.57 4.58 + create new virtual processor 4.59 4.60 + In requester, add newly created to the list of live children 4.61 4.62 + In newly created, add pointer to requester, as the parentVP 4.63 4.64 + 4.65 4.66 +For Dissipate: 4.67 4.68 + remove dissipator from its parent's list of live children. 4.69 4.70 + If this was last in list, check "sync pending" flag 4.71 4.72 + -- if set, then resume the parentVP. 4.73 4.74 + 4.75 4.76 +For Sync: 4.77 4.78 + check if list of live of children is empty. 4.79 4.80 + If yes, then resume. 4.81 4.82 + If no, then set sync-pending flag and remain suspended 4.83 4.84 + 4.85 4.86 +That's it. Quick and simple, 4.87
5.1 --- a/VCilk_lib.c Tue Nov 16 15:59:23 2010 +0100 5.2 +++ b/VCilk_lib.c Wed May 11 15:29:58 2011 +0200 5.3 @@ -1,429 +1,539 @@ 5.4 -/* 5.5 - * Copyright 2010 OpenSourceCodeStewardshipFoundation 5.6 - * 5.7 - * Licensed under BSD 5.8 - */ 5.9 - 5.10 -#include <stdio.h> 5.11 -#include <stdlib.h> 5.12 - 5.13 -#include "VMS/VMS.h" 5.14 -#include "VCilk.h" 5.15 -#include "VMS/Queue_impl/PrivateQueue.h" 5.16 -#include "VMS/Hash_impl/PrivateHash.h" 5.17 - 5.18 - 5.19 -//========================================================================== 5.20 - 5.21 -void 5.22 -VCilk__init(); 5.23 - 5.24 -void 5.25 -VCilk__init_Seq(); 5.26 - 5.27 -void 5.28 -VCilk__init_Helper(); 5.29 -//========================================================================== 5.30 - 5.31 - 5.32 -/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR 5.33 - * (still want to do FoR, with time-lines as syntax, could be super cool) 5.34 - * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate 5.35 - * among library, DKU, WT, FoR -- all the patterns in terms of virtual 5.36 - * processors (or equivalently work-units), so Master picks which virt procr 5.37 - * from which portions of app (DKU, WT, FoR) onto which sched slots 5.38 - *Might even do hierarchy of masters -- group of sched slots for each core 5.39 - * has its own master, that keeps generated work local 5.40 - * single-reader-single-writer sync everywhere -- no atomic primitives (but 5.41 - * memory fences on architectures that need them) 5.42 - * Might have the different schedulers talk to each other, to negotiate 5.43 - * larger-grain sharing of resources, according to predicted critical 5.44 - * path, and expansion of work 5.45 - */ 5.46 - 5.47 - 5.48 - 5.49 -//=========================================================================== 5.50 - 5.51 - 5.52 -/*These are the library functions *called in the application* 5.53 - * 5.54 - *There's a pattern for the outside sequential code to interact with the 5.55 - * VMS_HW code. 5.56 - *The VMS_HW system is inside a boundary.. every VCilk system is in its 5.57 - * own directory that contains the functions for each of the processor types. 5.58 - * One of the processor types is the "seed" processor that starts the 5.59 - * cascade of creating all the processors that do the work. 5.60 - *So, in the directory is a file called "EntryPoint.c" that contains the 5.61 - * function, named appropriately to the work performed, that the outside 5.62 - * sequential code calls. This function follows a pattern: 5.63 - *1) it calls VCilk__init() 5.64 - *2) it creates the initial data for the seed processor, which is passed 5.65 - * in to the function 5.66 - *3) it creates the seed VCilk processor, with the data to start it with. 5.67 - *4) it calls startVCilkThenWaitUntilWorkDone 5.68 - *5) it gets the returnValue from the transfer struc and returns that 5.69 - * from the function 5.70 - * 5.71 - *For now, a new VCilk system has to be created via VCilk__init every 5.72 - * time an entry point function is called -- later, might add letting the 5.73 - * VCilk system be created once, and let all the entry points just reuse 5.74 - * it -- want to be as simple as possible now, and see by using what makes 5.75 - * sense for later.. 5.76 - */ 5.77 - 5.78 - 5.79 - 5.80 -//=========================================================================== 5.81 - 5.82 -/*This is the "border crossing" function -- the thing that crosses from the 5.83 - * outside world, into the VMS_HW world. It initializes and starts up the 5.84 - * VMS system, then creates one processor from the specified function and 5.85 - * puts it into the readyQ. From that point, that one function is resp. 5.86 - * for creating all the other processors, that then create others, and so 5.87 - * forth. 5.88 - *When all the processors, including the seed, have dissipated, then this 5.89 - * function returns. The results will have been written by side-effect via 5.90 - * pointers read from, or written into initData. 5.91 - * 5.92 - *NOTE: no Threads should exist in the outside program that might touch 5.93 - * any of the data reachable from initData passed in to here 5.94 - */ 5.95 -void 5.96 -VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fnPtr, void *initData ) 5.97 - { VCilkSemEnv *semEnv; 5.98 - VirtProcr *seedPr; 5.99 - 5.100 - #ifdef SEQUENTIAL 5.101 - VCilk__init_Seq(); //debug sequential exe 5.102 - #else 5.103 - VCilk__init(); //normal multi-thd 5.104 - #endif 5.105 - semEnv = _VMSMasterEnv->semanticEnv; 5.106 - 5.107 - //VCilk starts with one processor, which is put into initial environ, 5.108 - // and which then calls create() to create more, thereby expanding work 5.109 - seedPr = VCilk__create_procr_helper( fnPtr, initData, NULL, semEnv, -1 ); 5.110 - resume_procr( seedPr, semEnv ); 5.111 - 5.112 - #ifdef SEQUENTIAL 5.113 - VMS__start_the_work_then_wait_until_done_Seq(); //debug sequential exe 5.114 - #else 5.115 - VMS__start_the_work_then_wait_until_done(); //normal multi-thd 5.116 - #endif 5.117 - 5.118 - VCilk__cleanup_at_end_of_shutdown(); 5.119 - } 5.120 - 5.121 - 5.122 -int32 inline 5.123 -VCilk__giveMinWorkUnitCycles( float32 percentOverhead ) 5.124 - { 5.125 - return MIN_WORK_UNIT_CYCLES; 5.126 - } 5.127 - 5.128 -int32 5.129 -VCilk__giveIdealNumWorkUnits() 5.130 - { 5.131 - return NUM_SCHED_SLOTS * NUM_CORES; 5.132 - } 5.133 - 5.134 -/*To measure how long a primitive operation takes, when calculating number of 5.135 - * sub-tasks to divide into. 5.136 - * For now, use TSC -- later, make these two macros with assembly that first 5.137 - * saves jump point, and second jumps back several times to get reliable time 5.138 - */ 5.139 -void inline 5.140 -VCilk__start_primitive() 5.141 - { //int32 *saveAddr; 5.142 - //saveAddr = &(((VCilkSemEnv *)(_VMSMasterEnv->semanticEnv))->primitiveStartTime); 5.143 - saveLowTimeStampCountInto( (((VCilkSemEnv *) 5.144 - (_VMSMasterEnv->semanticEnv))->primitiveStartTime) ); 5.145 - } 5.146 - 5.147 -/*Just quick and dirty for now -- make reliable later 5.148 - * will want this to jump back several times -- to be sure cache is warm 5.149 - * because don't want comm time included in calc-time measurement -- and 5.150 - * also to throw out any "weird" values due to OS interrupt or TSC rollover 5.151 - */ 5.152 -int32 inline 5.153 -VCilk__end_primitive_and_give_cycles() 5.154 - { int32 endTime, startTime; 5.155 - //TODO: fix by repeating time-measurement 5.156 - saveLowTimeStampCountInto( endTime ); 5.157 - startTime = ( (VCilkSemEnv *) 5.158 - (_VMSMasterEnv->semanticEnv))->primitiveStartTime; 5.159 - return (endTime - startTime); 5.160 - } 5.161 - 5.162 -//=========================================================================== 5.163 -// 5.164 -/*Initializes all the data-structures for a VCilk system -- but doesn't 5.165 - * start it running yet! 5.166 - * 5.167 - *This and its callees run in main thread outside VMS 5.168 - * 5.169 - *This sets up the semantic layer over the VMS system 5.170 - * 5.171 - *First, calls VMS_Setup, then creates own environment, making it ready 5.172 - * for creating the seed processor and then starting the work. 5.173 - */ 5.174 -void 5.175 -VCilk__init() 5.176 - { 5.177 - VMS__init(); 5.178 - //masterEnv, a global var, now is partially set up by init_VMS 5.179 - 5.180 - VCilk__init_Helper(); 5.181 - } 5.182 - 5.183 -void 5.184 -VCilk__init_Seq() 5.185 - { 5.186 - VMS__init_Seq(); 5.187 - //masterEnv, a global var, now is partially set up by init_VMS 5.188 - 5.189 - VCilk__init_Helper(); 5.190 - } 5.191 - 5.192 -/*Runs in main thread before VMS system starts 5.193 - */ 5.194 -void 5.195 -VCilk__init_Helper() 5.196 - { VCilkSemEnv *semanticEnv; 5.197 - PrivQueueStruc **readyVPQs; 5.198 - int coreIdx; 5.199 - 5.200 - //Hook up the semantic layer's plug-ins to the Master virt procr 5.201 - _VMSMasterEnv->requestHandler = &VCilk__Request_Handler; 5.202 - _VMSMasterEnv->slaveScheduler = &VCilk__schedule_virt_procr; 5.203 - 5.204 - //create the semantic layer's environment (all its data) and add to 5.205 - // the master environment 5.206 - semanticEnv = VMS__malloc( sizeof( VCilkSemEnv ) ); 5.207 - _VMSMasterEnv->semanticEnv = semanticEnv; 5.208 - 5.209 - //create the ready queue, hash tables used for pairing send to receive 5.210 - // and so forth 5.211 - //TODO: add hash tables for pairing sends with receives, and 5.212 - // initialize the data ownership system 5.213 - readyVPQs = VMS__malloc( NUM_CORES * sizeof(PrivQueueStruc *) ); 5.214 - 5.215 - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 5.216 - { 5.217 - readyVPQs[ coreIdx ] = makeVMSPrivQ(); 5.218 - } 5.219 - 5.220 - semanticEnv->readyVPQs = readyVPQs; 5.221 - 5.222 - semanticEnv->nextCoreToGetNewPr = 0; 5.223 - 5.224 - //TODO: bug -- turn these arrays into dyn arrays to eliminate limit 5.225 - //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); 5.226 - //semanticEnv->transactionStrucs = makeDynArrayInfo( ); 5.227 - //something like: setHighestIdx( dynArrayInfo, NUM_STRUCS_IN_SEM_ENV ) 5.228 - int32 i; 5.229 - for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) 5.230 - { 5.231 - semanticEnv->singletonHasBeenExecutedFlags[i] = FALSE; 5.232 - semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSPrivQ(); 5.233 - } 5.234 - 5.235 - } 5.236 - 5.237 - 5.238 -/*Runs in main thread, outside VMS 5.239 - *Frees any memory allocated by VCilk__init() then calls VMS's cleanup 5.240 - */ 5.241 -void 5.242 -VCilk__cleanup_at_end_of_shutdown() 5.243 - { VCilkSemEnv *semanticEnv; 5.244 - 5.245 - semanticEnv = _VMSMasterEnv->semanticEnv; 5.246 - 5.247 - /* 5.248 - int32 coreIdx; 5.249 - for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 5.250 - { 5.251 - VMS__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); 5.252 - VMS__free( semanticEnv->readyVPQs[coreIdx] ); 5.253 - } 5.254 - VMS__free( semanticEnv->readyVPQs ); 5.255 - 5.256 - VMS__free( _VMSMasterEnv->semanticEnv ); 5.257 - */ 5.258 - VMS__cleanup_at_end_of_shutdown(); 5.259 - } 5.260 - 5.261 - 5.262 -//=========================================================================== 5.263 - 5.264 - 5.265 -/*Spawn involves allocating mem as well as creating processor which itself 5.266 - * allocates, so has to be done inside master 5.267 - */ 5.268 -void inline 5.269 -VCilk__spawn( int32 coreToSpawnOnto, VirtProcrFnPtr fnPtr, 5.270 - void *initData, VirtProcr *requestingPr ) 5.271 - { VCilkSemReq reqData; 5.272 - 5.273 - //the semantic request data is on the stack and disappears when this 5.274 - // call returns -- it's guaranteed to remain in the VP's stack for as 5.275 - // long as the VP is suspended. 5.276 - reqData.reqType = 0; //know it's type because in a VMS create req 5.277 - reqData.coreToSpawnOnto = coreToSpawnOnto; 5.278 - reqData.fnPtr = fnPtr; 5.279 - reqData.initData = initData; 5.280 - reqData.requestingPr = requestingPr; 5.281 - 5.282 - VMS__send_create_procr_req( &reqData, requestingPr ); 5.283 - } 5.284 - 5.285 - 5.286 -int32 5.287 -VCilk__give_number_of_cores_to_spawn_onto() 5.288 - { 5.289 - return NUM_CORES; 5.290 - } 5.291 - 5.292 - 5.293 - 5.294 -/*This runs inside slave VP, so can't do any freeing -- have to do in plugin 5.295 - */ 5.296 -void inline 5.297 -VCilk__dissipate_procr( VirtProcr *procrToDissipate ) 5.298 - { 5.299 - 5.300 - VMS__send_dissipate_req( procrToDissipate ); 5.301 - } 5.302 - 5.303 -//=========================================================================== 5.304 - 5.305 -void 5.306 -VCilk__sync( VirtProcr *animPr ) 5.307 - { VCilkSemReq reqData; 5.308 - 5.309 - reqData.reqType = syncReq; 5.310 - reqData.requestingPr = animPr; 5.311 - 5.312 - VMS__send_sem_request( &reqData, animPr ); 5.313 - } 5.314 - 5.315 - 5.316 - 5.317 -void * 5.318 -VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr ) 5.319 - { VCilkSemReq reqData; 5.320 - 5.321 - reqData.reqType = mallocReq; 5.322 - reqData.requestingPr = animPr; 5.323 - reqData.sizeToMalloc = sizeToMalloc; 5.324 - 5.325 - VMS__send_sem_request( &reqData, animPr ); 5.326 - 5.327 - return animPr->dataRetFromReq; 5.328 - } 5.329 - 5.330 - 5.331 -/*Sends request to Master, which does the work of freeing 5.332 - */ 5.333 -void 5.334 -VCilk__free( void *ptrToFree, VirtProcr *animPr ) 5.335 - { VCilkSemReq reqData; 5.336 - 5.337 - reqData.reqType = freeReq; 5.338 - reqData.requestingPr = animPr; 5.339 - reqData.ptrToFree = ptrToFree; 5.340 - 5.341 - VMS__send_sem_request( &reqData, animPr ); 5.342 - } 5.343 - 5.344 -//=========================================================================== 5.345 - 5.346 -/*Uses ID as index into array of flags. If flag already set, resumes from 5.347 - * end-label. Else, sets flag and resumes normally. 5.348 - */ 5.349 -void 5.350 -VCilk__start_singleton( int32 singletonID, void *endSingletonLabelAddr, 5.351 - VirtProcr *animPr ) 5.352 - { 5.353 - VCilkSemReq reqData; 5.354 - 5.355 - // 5.356 - reqData.reqType = singleton; 5.357 - reqData.singletonID = singletonID; 5.358 - reqData.endJumpPt = endSingletonLabelAddr; 5.359 - 5.360 - VMS__send_sem_request( &reqData, animPr ); 5.361 - } 5.362 - 5.363 -/*This executes the function in the masterVP, so it executes in isolation 5.364 - * from any other copies -- only one copy of the function can ever execute 5.365 - * at a time. 5.366 - * 5.367 - *It suspends to the master, and the request handler takes the function 5.368 - * pointer out of the request and calls it, then resumes the VP. 5.369 - *Only very short functions should be called this way -- for longer-running 5.370 - * isolation, use transaction-start and transaction-end, which run the code 5.371 - * between as work-code. 5.372 - */ 5.373 -void 5.374 -VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 5.375 - void *data, VirtProcr *animPr ) 5.376 - { 5.377 - VCilkSemReq reqData; 5.378 - 5.379 - // 5.380 - reqData.reqType = atomic; 5.381 - reqData.fnToExecInMaster = ptrToFnToExecInMaster; 5.382 - reqData.dataForFn = data; 5.383 - 5.384 - VMS__send_sem_request( &reqData, animPr ); 5.385 - } 5.386 - 5.387 - 5.388 -/*This suspends to the master. 5.389 - *First, it looks at the VP's data, to see the highest transactionID that VP 5.390 - * already has entered. If the current ID is not larger, it throws an 5.391 - * exception stating a bug in the code. Otherwise it puts the current ID 5.392 - * there, and adds the ID to a linked list of IDs entered -- the list is 5.393 - * used to check that exits are properly ordered. 5.394 - *Next it is uses transactionID as index into an array of transaction 5.395 - * structures. 5.396 - *If the "VP_currently_executing" field is non-null, then put requesting VP 5.397 - * into queue in the struct. (At some point a holder will request 5.398 - * end-transaction, which will take this VP from the queue and resume it.) 5.399 - *If NULL, then write requesting into the field and resume. 5.400 - */ 5.401 -void 5.402 -VCilk__start_transaction( int32 transactionID, VirtProcr *animPr ) 5.403 - { 5.404 - VCilkSemReq reqData; 5.405 - 5.406 - // 5.407 - reqData.reqType = trans_start; 5.408 - reqData.transID = transactionID; 5.409 - 5.410 - VMS__send_sem_request( &reqData, animPr ); 5.411 - } 5.412 - 5.413 -/*This suspends to the master, then uses transactionID as index into an 5.414 - * array of transaction structures. 5.415 - *It looks at VP_currently_executing to be sure it's same as requesting VP. 5.416 - * If different, throws an exception, stating there's a bug in the code. 5.417 - *Next it looks at the queue in the structure. 5.418 - *If it's empty, it sets VP_currently_executing field to NULL and resumes. 5.419 - *If something in, gets it, sets VP_currently_executing to that VP, then 5.420 - * resumes both. 5.421 - */ 5.422 -void 5.423 -VCilk__end_transaction( int32 transactionID, VirtProcr *animPr ) 5.424 - { 5.425 - VCilkSemReq reqData; 5.426 - 5.427 - // 5.428 - reqData.reqType = trans_end; 5.429 - reqData.transID = transactionID; 5.430 - 5.431 - VMS__send_sem_request( &reqData, animPr ); 5.432 - } 5.433 +/* 5.434 + * Copyright 2010 OpenSourceCodeStewardshipFoundation 5.435 + * 5.436 + * Licensed under BSD 5.437 + */ 5.438 + 5.439 +#include <stdio.h> 5.440 +#include <stdlib.h> 5.441 + 5.442 +#include "VMS/VMS.h" 5.443 +#include "VCilk.h" 5.444 +#include "VMS/Queue_impl/PrivateQueue.h" 5.445 +#include "VMS/Hash_impl/PrivateHash.h" 5.446 + 5.447 + 5.448 +//========================================================================== 5.449 + 5.450 +void 5.451 +VCilk__init(); 5.452 + 5.453 +void 5.454 +VCilk__init_Seq(); 5.455 + 5.456 +void 5.457 +VCilk__init_Helper(); 5.458 +//========================================================================== 5.459 + 5.460 + 5.461 +/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR 5.462 + * (still want to do FoR, with time-lines as syntax, could be super cool) 5.463 + * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate 5.464 + * among library, DKU, WT, FoR -- all the patterns in terms of virtual 5.465 + * processors (or equivalently work-units), so Master picks which virt procr 5.466 + * from which portions of app (DKU, WT, FoR) onto which sched slots 5.467 + *Might even do hierarchy of masters -- group of sched slots for each core 5.468 + * has its own master, that keeps generated work local 5.469 + * single-reader-single-writer sync everywhere -- no atomic primitives (but 5.470 + * memory fences on architectures that need them) 5.471 + * Might have the different schedulers talk to each other, to negotiate 5.472 + * larger-grain sharing of resources, according to predicted critical 5.473 + * path, and expansion of work 5.474 + */ 5.475 + 5.476 + 5.477 + 5.478 +//=========================================================================== 5.479 + 5.480 + 5.481 +/*These are the library functions *called in the application* 5.482 + * 5.483 + *There's a pattern for the outside sequential code to interact with the 5.484 + * VMS_HW code. 5.485 + *The VMS_HW system is inside a boundary.. every VCilk system is in its 5.486 + * own directory that contains the functions for each of the processor types. 5.487 + * One of the processor types is the "seed" processor that starts the 5.488 + * cascade of creating all the processors that do the work. 5.489 + *So, in the directory is a file called "EntryPoint.c" that contains the 5.490 + * function, named appropriately to the work performed, that the outside 5.491 + * sequential code calls. This function follows a pattern: 5.492 + *1) it calls VCilk__init() 5.493 + *2) it creates the initial data for the seed processor, which is passed 5.494 + * in to the function 5.495 + *3) it creates the seed VCilk processor, with the data to start it with. 5.496 + *4) it calls startVCilkThenWaitUntilWorkDone 5.497 + *5) it gets the returnValue from the transfer struc and returns that 5.498 + * from the function 5.499 + * 5.500 + *For now, a new VCilk system has to be created via VCilk__init every 5.501 + * time an entry point function is called -- later, might add letting the 5.502 + * VCilk system be created once, and let all the entry points just reuse 5.503 + * it -- want to be as simple as possible now, and see by using what makes 5.504 + * sense for later.. 5.505 + */ 5.506 + 5.507 + 5.508 + 5.509 +//=========================================================================== 5.510 + 5.511 +/*This is the "border crossing" function -- the thing that crosses from the 5.512 + * outside world, into the VMS_HW world. It initializes and starts up the 5.513 + * VMS system, then creates one processor from the specified function and 5.514 + * puts it into the readyQ. From that point, that one function is resp. 5.515 + * for creating all the other processors, that then create others, and so 5.516 + * forth. 5.517 + *When all the processors, including the seed, have dissipated, then this 5.518 + * function returns. The results will have been written by side-effect via 5.519 + * pointers read from, or written into initData. 5.520 + * 5.521 + *NOTE: no Threads should exist in the outside program that might touch 5.522 + * any of the data reachable from initData passed in to here 5.523 + */ 5.524 +void 5.525 +VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fnPtr, void *initData ) 5.526 + { VCilkSemEnv *semEnv; 5.527 + VirtProcr *seedPr; 5.528 + 5.529 + #ifdef SEQUENTIAL 5.530 + VCilk__init_Seq(); //debug sequential exe 5.531 + #else 5.532 + VCilk__init(); //normal multi-thd 5.533 + #endif 5.534 + semEnv = _VMSMasterEnv->semanticEnv; 5.535 + 5.536 + //VCilk starts with one processor, which is put into initial environ, 5.537 + // and which then calls create() to create more, thereby expanding work 5.538 + seedPr = VCilk__create_procr_helper( fnPtr, initData, NULL, semEnv, -1 ); 5.539 + resume_procr( seedPr, semEnv ); 5.540 + 5.541 + #ifdef SEQUENTIAL 5.542 + VMS__start_the_work_then_wait_until_done_Seq(); //debug sequential exe 5.543 + #else 5.544 + VMS__start_the_work_then_wait_until_done(); //normal multi-thd 5.545 + #endif 5.546 + 5.547 + VCilk__cleanup_at_end_of_shutdown(); 5.548 + } 5.549 + 5.550 + 5.551 +int32 inline 5.552 +VCilk__giveMinWorkUnitCycles( float32 percentOverhead ) 5.553 + { 5.554 + return MIN_WORK_UNIT_CYCLES; 5.555 + } 5.556 + 5.557 +int32 5.558 +VCilk__giveIdealNumWorkUnits() 5.559 + { 5.560 + return NUM_SCHED_SLOTS * NUM_CORES; 5.561 + } 5.562 + 5.563 +/*To measure how long a primitive operation takes, when calculating number of 5.564 + * sub-tasks to divide into. 5.565 + * For now, use TSC -- later, make these two macros with assembly that first 5.566 + * saves jump point, and second jumps back several times to get reliable time 5.567 + */ 5.568 +void inline 5.569 +VCilk__start_primitive() 5.570 + { //int32 *saveAddr; 5.571 + //saveAddr = &(((VCilkSemEnv *)(_VMSMasterEnv->semanticEnv))->primitiveStartTime); 5.572 + saveLowTimeStampCountInto( (((VCilkSemEnv *) 5.573 + (_VMSMasterEnv->semanticEnv))->primitiveStartTime) ); 5.574 + } 5.575 + 5.576 +/*Just quick and dirty for now -- make reliable later 5.577 + * will want this to jump back several times -- to be sure cache is warm 5.578 + * because don't want comm time included in calc-time measurement -- and 5.579 + * also to throw out any "weird" values due to OS interrupt or TSC rollover 5.580 + */ 5.581 +int32 inline 5.582 +VCilk__end_primitive_and_give_cycles() 5.583 + { int32 endTime, startTime; 5.584 + //TODO: fix by repeating time-measurement 5.585 + saveLowTimeStampCountInto( endTime ); 5.586 + startTime = ( (VCilkSemEnv *) 5.587 + (_VMSMasterEnv->semanticEnv))->primitiveStartTime; 5.588 + return (endTime - startTime); 5.589 + } 5.590 + 5.591 +//=========================================================================== 5.592 +// 5.593 +/*Initializes all the data-structures for a VCilk system -- but doesn't 5.594 + * start it running yet! 5.595 + * 5.596 + *This and its callees run in main thread outside VMS 5.597 + * 5.598 + *This sets up the semantic layer over the VMS system 5.599 + * 5.600 + *First, calls VMS_Setup, then creates own environment, making it ready 5.601 + * for creating the seed processor and then starting the work. 5.602 + */ 5.603 +void 5.604 +VCilk__init() 5.605 + { 5.606 + VMS__init(); 5.607 + //masterEnv, a global var, now is partially set up by init_VMS 5.608 + 5.609 + VCilk__init_Helper(); 5.610 + } 5.611 + 5.612 +void 5.613 +VCilk__init_Seq() 5.614 + { 5.615 + VMS__init_Seq(); 5.616 + //masterEnv, a global var, now is partially set up by init_VMS 5.617 + 5.618 + VCilk__init_Helper(); 5.619 + } 5.620 + 5.621 +/*Runs in main thread before VMS system starts 5.622 + */ 5.623 +void 5.624 +VCilk__init_Helper() 5.625 + { VCilkSemEnv *semanticEnv; 5.626 + PrivQueueStruc **readyVPQs; 5.627 + int coreIdx; 5.628 + 5.629 + //Hook up the semantic layer's plug-ins to the Master virt procr 5.630 + _VMSMasterEnv->requestHandler = &VCilk__Request_Handler; 5.631 + _VMSMasterEnv->slaveScheduler = &VCilk__schedule_virt_procr; 5.632 + 5.633 + //create the semantic layer's environment (all its data) and add to 5.634 + // the master environment 5.635 + semanticEnv = VMS__malloc( sizeof( VCilkSemEnv ) ); 5.636 + _VMSMasterEnv->semanticEnv = semanticEnv; 5.637 + 5.638 + //create the ready queue, hash tables used for pairing send to receive 5.639 + // and so forth 5.640 + //TODO: add hash tables for pairing sends with receives, and 5.641 + // initialize the data ownership system 5.642 + readyVPQs = VMS__malloc( NUM_CORES * sizeof(PrivQueueStruc *) ); 5.643 + 5.644 + for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 5.645 + { 5.646 + readyVPQs[ coreIdx ] = makeVMSPrivQ(); 5.647 + } 5.648 + 5.649 + semanticEnv->readyVPQs = readyVPQs; 5.650 + 5.651 + semanticEnv->nextCoreToGetNewPr = 0; 5.652 + 5.653 + //TODO: bug -- turn these arrays into dyn arrays to eliminate limit 5.654 + //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); 5.655 + //semanticEnv->transactionStrucs = makeDynArrayInfo( ); 5.656 + //something like: setHighestIdx( dynArrayInfo, NUM_STRUCS_IN_SEM_ENV ) 5.657 + int32 i; 5.658 + for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) 5.659 + { 5.660 + semanticEnv->fnSingletons[i].endInstrAddr = NULL; 5.661 + semanticEnv->fnSingletons[i].hasBeenStarted = FALSE; 5.662 + semanticEnv->fnSingletons[i].hasFinished = FALSE; 5.663 + semanticEnv->fnSingletons[i].waitQ = makeVMSPrivQ(); 5.664 + semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSPrivQ(); 5.665 + } 5.666 + 5.667 + } 5.668 + 5.669 + 5.670 +/*Runs in main thread, outside VMS 5.671 + *Frees any memory allocated by VCilk__init() then calls VMS's cleanup 5.672 + */ 5.673 +void 5.674 +VCilk__cleanup_at_end_of_shutdown() 5.675 + { VCilkSemEnv *semanticEnv; 5.676 + 5.677 + semanticEnv = _VMSMasterEnv->semanticEnv; 5.678 + 5.679 + /* 5.680 + int32 coreIdx; 5.681 + for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 5.682 + { 5.683 + VMS__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); 5.684 + VMS__free( semanticEnv->readyVPQs[coreIdx] ); 5.685 + } 5.686 + VMS__free( semanticEnv->readyVPQs ); 5.687 + 5.688 + VMS__free( _VMSMasterEnv->semanticEnv ); 5.689 + */ 5.690 + VMS__cleanup_at_end_of_shutdown(); 5.691 + } 5.692 + 5.693 + 5.694 +//=========================================================================== 5.695 + 5.696 + 5.697 +/*Spawn involves allocating mem as well as creating processor which itself 5.698 + * allocates, so has to be done inside master 5.699 + */ 5.700 +void inline 5.701 +VCilk__spawn( int32 coreToSpawnOnto, VirtProcrFnPtr fnPtr, 5.702 + void *initData, VirtProcr *requestingPr ) 5.703 + { VCilkSemReq reqData; 5.704 + 5.705 + //the semantic request data is on the stack and disappears when this 5.706 + // call returns -- it's guaranteed to remain in the VP's stack for as 5.707 + // long as the VP is suspended. 5.708 + reqData.reqType = 0; //know it's type because in a VMS create req 5.709 + reqData.coreToSpawnOnto = coreToSpawnOnto; 5.710 + reqData.fnPtr = fnPtr; 5.711 + reqData.initData = initData; 5.712 + reqData.requestingPr = requestingPr; 5.713 + 5.714 + VMS__send_create_procr_req( &reqData, requestingPr ); 5.715 + } 5.716 + 5.717 + 5.718 +int32 5.719 +VCilk__give_number_of_cores_to_spawn_onto() 5.720 + { 5.721 + return NUM_CORES; 5.722 + } 5.723 + 5.724 + 5.725 + 5.726 +/*This runs inside slave VP, so can't do any freeing -- have to do in plugin 5.727 + */ 5.728 +void inline 5.729 +VCilk__dissipate_procr( VirtProcr *procrToDissipate ) 5.730 + { 5.731 + 5.732 + VMS__send_dissipate_req( procrToDissipate ); 5.733 + } 5.734 + 5.735 +//=========================================================================== 5.736 + 5.737 +void 5.738 +VCilk__sync( VirtProcr *animPr ) 5.739 + { VCilkSemReq reqData; 5.740 + 5.741 + reqData.reqType = syncReq; 5.742 + reqData.requestingPr = animPr; 5.743 + 5.744 + VMS__send_sem_request( &reqData, animPr ); 5.745 + } 5.746 + 5.747 + 5.748 + 5.749 +void * 5.750 +VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr ) 5.751 + { VCilkSemReq reqData; 5.752 + 5.753 + reqData.reqType = mallocReq; 5.754 + reqData.requestingPr = animPr; 5.755 + reqData.sizeToMalloc = sizeToMalloc; 5.756 + 5.757 + VMS__send_sem_request( &reqData, animPr ); 5.758 + 5.759 + return animPr->dataRetFromReq; 5.760 + } 5.761 + 5.762 + 5.763 +/*Sends request to Master, which does the work of freeing 5.764 + */ 5.765 +void 5.766 +VCilk__free( void *ptrToFree, VirtProcr *animPr ) 5.767 + { VCilkSemReq reqData; 5.768 + 5.769 + reqData.reqType = freeReq; 5.770 + reqData.requestingPr = animPr; 5.771 + reqData.ptrToFree = ptrToFree; 5.772 + 5.773 + VMS__send_sem_request( &reqData, animPr ); 5.774 + } 5.775 + 5.776 +//=========================================================================== 5.777 +// 5.778 +/*A function singleton is a function whose body executes exactly once, on a 5.779 + * single core, no matter how many times the fuction is called and no 5.780 + * matter how many cores or the timing of cores calling it. 5.781 + * 5.782 + *A data singleton is a ticket attached to data. That ticket can be used 5.783 + * to get the data through the function exactly once, no matter how many 5.784 + * times the data is given to the function, and no matter the timing of 5.785 + * trying to get the data through from different cores. 5.786 + */ 5.787 + 5.788 +/*Fn singleton uses ID as index into array of singleton structs held in the 5.789 + * semantic environment. 5.790 + */ 5.791 +void 5.792 +VCilk__start_fn_singleton( int32 singletonID, VirtProcr *animPr ) 5.793 + { 5.794 + VCilkSemReq reqData; 5.795 + 5.796 + // 5.797 + reqData.reqType = singleton_fn_start; 5.798 + reqData.singletonID = singletonID; 5.799 + 5.800 + VMS__send_sem_request( &reqData, animPr ); 5.801 + if( animPr->dataRetFromReq ) //will be 0 or addr of label in end singleton 5.802 + { 5.803 + asm volatile("movl %0, %%eax; \ 5.804 + jmp *%%eax" \ 5.805 + /* outputs */ : \ 5.806 + /* inputs */ : "g"(animPr->dataRetFromReq) \ 5.807 + /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\ 5.808 + ); 5.809 + } 5.810 + } 5.811 + 5.812 +/*Data singleton hands addr of loc holding a pointer to a singleton struct. 5.813 + * The start_data_singleton makes the structure and puts its addr into the 5.814 + * location. 5.815 + */ 5.816 +void 5.817 +VCilk__start_data_singleton( VCilkSingleton **singletonAddr, VirtProcr *animPr ) 5.818 + { 5.819 + VCilkSemReq reqData; 5.820 + 5.821 + if( *singletonAddr && (*singletonAddr)->hasFinished ) 5.822 + goto JmpToEndSingleton; 5.823 + // 5.824 + reqData.reqType = singleton_data_start; 5.825 + reqData.singletonPtrAddr = singletonAddr; 5.826 + 5.827 + VMS__send_sem_request( &reqData, animPr ); 5.828 + if( animPr->dataRetFromReq ) //either 0 or end singleton's return addr 5.829 + { //Assembly code changes the return addr on the stack to the one 5.830 + // saved into the singleton by the end-singleton-fn 5.831 + //The return addr is at 0x4(%%ebp) 5.832 + JmpToEndSingleton: 5.833 + asm volatile("movl %0, %%eax; \ 5.834 + movl (%%eax), %%ebx; \ 5.835 + movl (%%ebx), %%eax; \ 5.836 + movl %%eax, 0x4(%%ebp);" \ 5.837 + /* outputs */ : \ 5.838 + /* inputs */ : "m"(singletonAddr) \ 5.839 + /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\ 5.840 + ); 5.841 + } 5.842 + //now, simply return 5.843 + //will exit either from the start singleton call or the end-singleton call 5.844 + } 5.845 + 5.846 +/*Uses ID as index into array of flags. If flag already set, resumes from 5.847 + * end-label. Else, sets flag and resumes normally. 5.848 + * 5.849 + *Note, this call cannot be inlined because the instr addr at the label 5.850 + * inside is shared by all invocations of a given singleton ID. 5.851 + */ 5.852 +void 5.853 +VCilk__end_fn_singleton( int32 singletonID, VirtProcr *animPr ) 5.854 + { 5.855 + VCilkSemReq reqData; 5.856 + 5.857 + //don't need this addr until after at least one singleton has reached 5.858 + // this function 5.859 + VCilkSemEnv *semEnv = VMS__give_sem_env_for( animPr ); 5.860 + semEnv->fnSingletons[ singletonID].endInstrAddr = &&EndSingletonInstrAddr; 5.861 + 5.862 + reqData.reqType = singleton_fn_end; 5.863 + reqData.singletonID = singletonID; 5.864 + 5.865 + VMS__send_sem_request( &reqData, animPr ); 5.866 + 5.867 +EndSingletonInstrAddr: 5.868 + return; 5.869 + } 5.870 + 5.871 +void 5.872 +VCilk__end_data_singleton( VCilkSingleton **singletonPtrAddr, VirtProcr *animPr ) 5.873 + { 5.874 + VCilkSemReq reqData; 5.875 + 5.876 + //don't need this addr until after singleton struct has reached 5.877 + // this function for first time 5.878 + //do assembly that saves the return addr of this fn call into the 5.879 + // data singleton -- that data-singleton can only be given to exactly 5.880 + // one instance in the code of this function. However, can use this 5.881 + // function in different places for different data-singletons. 5.882 +// (*(singletonAddr))->endInstrAddr = &&EndDataSingletonInstrAddr; 5.883 + 5.884 + //Assembly code takes the return addr off the stack and saves 5.885 + // into the singleton. The first field in the singleton is the 5.886 + // "endInstrAddr" field, and the return addr is at 0x4(%%ebp) 5.887 + asm volatile("movl 0x4(%%ebp), %%eax; \ 5.888 + movl %0, %%ebx; \ 5.889 + movl (%%ebx), %%ecx; \ 5.890 + movl %%eax, (%%ecx);" \ 5.891 + /* outputs */ : \ 5.892 + /* inputs */ : "m"(singletonPtrAddr) \ 5.893 + /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx","%edi","%esi"\ 5.894 + ); 5.895 + 5.896 + reqData.reqType = singleton_data_end; 5.897 + reqData.singletonPtrAddr = singletonPtrAddr; 5.898 + 5.899 + VMS__send_sem_request( &reqData, animPr ); 5.900 + } 5.901 + 5.902 +/*This executes the function in the masterVP, so it executes in isolation 5.903 + * from any other copies -- only one copy of the function can ever execute 5.904 + * at a time. 5.905 + * 5.906 + *It suspends to the master, and the request handler takes the function 5.907 + * pointer out of the request and calls it, then resumes the VP. 5.908 + *Only very short functions should be called this way -- for longer-running 5.909 + * isolation, use transaction-start and transaction-end, which run the code 5.910 + * between as work-code. 5.911 + */ 5.912 +void 5.913 +VCilk__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 5.914 + void *data, VirtProcr *animPr ) 5.915 + { 5.916 + VCilkSemReq reqData; 5.917 + 5.918 + // 5.919 + reqData.reqType = atomic; 5.920 + reqData.fnToExecInMaster = ptrToFnToExecInMaster; 5.921 + reqData.dataForFn = data; 5.922 + 5.923 + VMS__send_sem_request( &reqData, animPr ); 5.924 + } 5.925 + 5.926 + 5.927 +/*This suspends to the master. 5.928 + *First, it looks at the VP's data, to see the highest transactionID that VP 5.929 + * already has entered. If the current ID is not larger, it throws an 5.930 + * exception stating a bug in the code. Otherwise it puts the current ID 5.931 + * there, and adds the ID to a linked list of IDs entered -- the list is 5.932 + * used to check that exits are properly ordered. 5.933 + *Next it is uses transactionID as index into an array of transaction 5.934 + * structures. 5.935 + *If the "VP_currently_executing" field is non-null, then put requesting VP 5.936 + * into queue in the struct. (At some point a holder will request 5.937 + * end-transaction, which will take this VP from the queue and resume it.) 5.938 + *If NULL, then write requesting into the field and resume. 5.939 + */ 5.940 +void 5.941 +VCilk__start_transaction( int32 transactionID, VirtProcr *animPr ) 5.942 + { 5.943 + VCilkSemReq reqData; 5.944 + 5.945 + // 5.946 + reqData.reqType = trans_start; 5.947 + reqData.transID = transactionID; 5.948 + 5.949 + VMS__send_sem_request( &reqData, animPr ); 5.950 + } 5.951 + 5.952 +/*This suspends to the master, then uses transactionID as index into an 5.953 + * array of transaction structures. 5.954 + *It looks at VP_currently_executing to be sure it's same as requesting VP. 5.955 + * If different, throws an exception, stating there's a bug in the code. 5.956 + *Next it looks at the queue in the structure. 5.957 + *If it's empty, it sets VP_currently_executing field to NULL and resumes. 5.958 + *If something in, gets it, sets VP_currently_executing to that VP, then 5.959 + * resumes both. 5.960 + */ 5.961 +void 5.962 +VCilk__end_transaction( int32 transactionID, VirtProcr *animPr ) 5.963 + { 5.964 + VCilkSemReq reqData; 5.965 + 5.966 + // 5.967 + reqData.reqType = trans_end; 5.968 + reqData.transID = transactionID; 5.969 + 5.970 + VMS__send_sem_request( &reqData, animPr ); 5.971 + }