Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > SSR_impls > SSR__MC_shared_impl
changeset 0:35b53e6de714
Initial add -- up on sourceforge now
| author | Me |
|---|---|
| date | Sat, 22 May 2010 19:33:11 -0700 |
| parents | |
| children | 06ca89bafbb8 |
| files | VMSHW.h VMSHW_PluginFns.c VMSHW_lib.c |
| diffstat | 3 files changed, 417 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/VMSHW.h Sat May 22 19:33:11 2010 -0700 1.3 @@ -0,0 +1,46 @@ 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 _VMSHW_H 1.13 +#define _VMSHW_H 1.14 + 1.15 +#include "VMS/VMS_primitive_data_types.h" 1.16 +#include "VMS/Queue_impl/BlockingQueue.h" 1.17 + 1.18 +/*This header defines everything specific to the VMSHW semantic plug-in 1.19 + */ 1.20 +typedef struct VMSHWReqData VMSHWReqData; 1.21 + 1.22 +typedef struct 1.23 + { 1.24 + } 1.25 +VMSHWProcr; 1.26 + 1.27 +/*Semantic layer-specific data sent inside a request from lib called in app 1.28 + * to request handler called in MasterLoop 1.29 + */ 1.30 +enum VMSHW_ReqType 1.31 + { 1.32 + receive, 1.33 + send, 1.34 + create 1.35 + }; 1.36 + 1.37 +struct VMSHWReqData 1.38 + { VMSHW_ReqType reqType; 1.39 + 1.40 + }; 1.41 + 1.42 +typedef struct 1.43 + { 1.44 + 1.45 + } 1.46 +VMSHWSemanticEnv; 1.47 + 1.48 +#endif /* _VMSHW_H */ 1.49 +
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/VMSHW_PluginFns.c Sat May 22 19:33:11 2010 -0700 2.3 @@ -0,0 +1,141 @@ 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 +#include <malloc.h> 2.13 + 2.14 +#include "VMS/VMS.h" 2.15 +#include "VMS/Queue_impl/PrivateQueue.h" 2.16 +#include "VMSHW.h" 2.17 + 2.18 + 2.19 +/*Will get requests to send, to receive, and to create new processors. 2.20 + * Upon send, check the hash to see if a receive is waiting. 2.21 + * Upon receive, check hash to see if a send has already happened. 2.22 + * When other is not there, put in. When other is there, the comm. 2.23 + * completes, which means the receiver P gets a new work-unit generated 2.24 + * that picks up right after the receive request. So make the work-unit 2.25 + * and put it into the queue of work-units ready to go. 2.26 + * Other request is create a new Processor, with the function to run in the 2.27 + * Processor, and initial data. 2.28 + */ 2.29 + 2.30 +/*Old idea, but want to keep around: 2.31 + * give pointer to initialization function to create-processor call, in 2.32 + * addition to the work-function and initial data 2.33 + * Then, make the initialization be a work-unit, that places the created 2.34 + * processor-struc, and an initial work-unit for that processor in a 2.35 + * request that comes to the req handler when done. The initial work-unit 2.36 + * has the pointer to a special VMS code snippet that 2.37 + * the function to run in the Processor is pointed to by the work-unit 2.38 + * code pointer, and the initial data as the work-unit's data-pointer. 2.39 + * Another request is the result of create-processor request. It has a new 2.40 + * Processor, and the processor's inital work-unit. Add the Processor to 2.41 + * the data-structures that track Processors, and put the work-unit into the 2.42 + * queue of ready-to-go work-units. 2.43 + * The reason to make the create-processor work-unit return the new 2.44 + * processor and its initial work unit, is that only the MasterLoop 2.45 + * work-unit owns the semantic environment, with the Processor-tracking 2.46 + * data-structures, and only it can put work-units into or take out of 2.47 + * the ready-to-go work-unit queue. 2.48 + */ 2.49 +void 2.50 +VMSHW__Request_Handler( VMSProcr *slave, void *semanticEnv ) 2.51 + { VMSHWEnviron semEnv; 2.52 + 2.53 + semEnv = (VMSHWEnviron *)semanticEnv; 2.54 + 2.55 + req = slave->requestsToMaster; 2.56 + while( req != NULL ) 2.57 + { 2.58 + //TODO: figure out better separation -- maybe MasterLoop gives 2.59 + // request payloads one at a time to this handler 2.60 + if( req->type == VMSInternal ) /*do something*/; 2.61 + else //request is to be handled by VMSHW 2.62 + { 2.63 + semanticReq = req->reqPayload; //TODO: make sure not NULL in creator 2.64 + switch( semanticReq->type ) 2.65 + { 2.66 + case sendFromName: handleSendFromName( semanticReq, semEnv); 2.67 + break; 2.68 + case sendToPort: handleSendToPort( semanticReq, semEnv); 2.69 + break; 2.70 + case receiveFromName: handleReceiveFromName(semanticReq, semEnv); 2.71 + break; 2.72 + case receiveOnPort: handleReceiveOnPort( semanticReq, semEnv); 2.73 + break; 2.74 + case create: handleCreate( semanticReq, semEnv); 2.75 + break; 2.76 + } 2.77 + } 2.78 + req = req->next; 2.79 + } 2.80 + } 2.81 + 2.82 +/*The payload has the receiving processor and its port 2.83 + * 2.84 + *Note one value in this approach: without the extra (VMS) virtual layer, 2.85 + * the send and receive would happen in real time instead of virtual time, 2.86 + * which would waste real time while one of them waited for other 2.87 + */ 2.88 + void 2.89 +handleSendToPort( VMSHWRequest *reqPayload, VMSHWEnviron *semEnv ) 2.90 + { 2.91 + reqProcr = reqPayload->reqProcr; 2.92 + receivePr = reqPayload->receivePr; 2.93 + 2.94 + key = receivePr->keys[ reqPayload->portNum ]; 2.95 + value = getValueFromTable( key, semEnv->commHash ); 2.96 + if( value == NULL ) 2.97 + { 2.98 + //TODO: is hash entry really just a flag -- empty? Want work-unit? No 2.99 + // 'cause want to make an entry when only a send, no receive yet 2.100 + value = malloc( sizeof(CommHashFlag) ); 2.101 + putValueIntoTable( key, value, semEnv->commHash ); 2.102 + } 2.103 + else //receive waiting for this send 2.104 + { 2.105 + workUPayload = malloc( sizeof(VMSHWWorkUnit) ); 2.106 + workUPayload->owningProcr = receivePr; 2.107 + newWorkUnit = VMS__create_workUnit( workUPayload ); 2.108 + 2.109 + writePrivQ( newWorkUnit, semEnv->readyWorkUnitQ ); 2.110 + 2.111 + //NOTE: this is sequential! Don't have to worry about sharing or syncs 2.112 + //in semantic environment -- even though shared by work units, slaves, 2.113 + // and virtual processors -- all the sharing is in virtual time, and 2.114 + // mapped onto safe sequence in physical time by VMS 2.115 + 2.116 + } 2.117 + } 2.118 + 2.119 + 2.120 +/*For VMSHW, scheduling a slave simply takes the next work-unit off the 2.121 + * ready-to-go work-unit queue and assigns it to the slaveToSched. 2.122 + *If the ready-to-go work-unit queue is empty, then nothing to schedule 2.123 + * to the slave -- return FALSE to let Master loop know scheduling that 2.124 + * slave failed. 2.125 + */ 2.126 +bool8 2.127 +VMSHW__schedule_slave( VMSProcr *slaveToSched, void *semanticEnv ) 2.128 + { PrivQueueStruc *readyWorkUnitQ; 2.129 + WorkUnit *workUnitToSched; 2.130 + VMSHWSemanticEnv *semEnv; 2.131 + 2.132 + semEnv = (VMSHWSemanticEnv *)semanticEnv; 2.133 + 2.134 + //Note, using a non-blocking queue -- it returns NULL if queue empty 2.135 + readyWorkUnitQ = semEnv->readyWorkUnitQ; 2.136 + 2.137 + workUnitToSched = readPrivQ( readyWorkUnitQ ); 2.138 + if( readQ == NULL ) return FALSE; 2.139 + 2.140 + slaveToSched->workUnitToDo = workUnitToSched; 2.141 + workUnitToSched->slaveAssignedTo = slaveToSched; 2.142 + 2.143 + return TRUE; 2.144 + }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/VMSHW_lib.c Sat May 22 19:33:11 2010 -0700 3.3 @@ -0,0 +1,230 @@ 3.4 +/* 3.5 + * Copyright 2010 OpenSourceCodeStewardshipFoundation 3.6 + * 3.7 + * Licensed under BSD 3.8 + */ 3.9 + 3.10 +#include <stdio.h> 3.11 +#include <stdlib.h> 3.12 +#include <malloc.h> 3.13 + 3.14 +#include "../VMS/VMS.h" 3.15 +#include "VMSHW.h" 3.16 +#include "../VMS/Queue_impl/NonBlockingQueue.h" 3.17 + 3.18 + 3.19 +/*These are the library functions *called in the application* 3.20 + *They all run in the virtual slaves, never in the virtual master. 3.21 + * 3.22 + *There's a pattern for the outside sequential code to interact with the 3.23 + * VMSHW code. 3.24 + *The VMSHW system is inside a boundary.. every VMSHW system is in its 3.25 + * own directory that contains the functions for each of the processor types. 3.26 + * One of the processor types is the "seed" processor that starts the 3.27 + * cascade of creating all the processors that do the work. 3.28 + *So, in the directory is a file called "EntryPoint.c" that contains the 3.29 + * function, named appropriately to the work performed, that the outside 3.30 + * sequential code calls. This function follows a pattern: 3.31 + *1) it calls VMSHW__init() 3.32 + *2) it creates the initial data for the seed processor, which is passed 3.33 + * in to the function 3.34 + *3) it creates the seed VMSHW processor, with the data to start it with. 3.35 + *4) it calls startVMSHWThenWaitUntilWorkDone 3.36 + *5) it gets the returnValue from the transfer struc and returns that 3.37 + * from the function 3.38 + * 3.39 + *For now, a new VMSHW system has to be created via VMSHW__init every 3.40 + * time an entry point function is called -- later, might add letting the 3.41 + * VMSHW system be created once, and let all the entry points just reuse 3.42 + * it -- want to be as simple as possible now, and see by using what makes 3.43 + * sense for later.. 3.44 + */ 3.45 + 3.46 + 3.47 +/*Initializes all the data-structures for a VMSHW system -- but doesn't 3.48 + * start it running yet! 3.49 + * 3.50 + * 3.51 + *This sets up the semantic layer over the VMS system 3.52 + * 3.53 + *First, calls VMS_Setup, then creates own environment, making it ready 3.54 + * for creating the seed processor. 3.55 + */ 3.56 + void 3.57 +VMSHW__init() 3.58 + { VMSHWEnv *semanticEnv; 3.59 + 3.60 + init_VMS(); 3.61 + 3.62 + //masterEnv, a global var, now is partially set up by init_VMS 3.63 + semanticEnv = malloc( sizeof( VMSHWEnv ) ); 3.64 + masterEnv->semanticEnv = semanticEnv; 3.65 + 3.66 + semanticEnv->readyWorkUnitsQ = mareadyWorkUnitsQkePrivQ(); 3.67 + } 3.68 + 3.69 + 3.70 +/*This is the entry point to the VMSHW system from the sequential part of 3.71 + * the app.. 3.72 + * 3.73 + *Calling this starts the VMS system, passing it the input data given to 3.74 + * this, then waits for the work to finish, and returns whatever pointer 3.75 + * the final VMSHW call said to return to the outside via the 3.76 + * VMSHW__transfer_out_as_result call 3.77 + */ 3.78 + 3.79 +VMSHW__start_then_wait_until_work_done() 3.80 + { 3.81 + VMS__start(); 3.82 + 3.83 + //Wait for work to complete 3.84 + //Use PThreads to put the main thread to sleep until something executes 3.85 + // a notify(), which is the last thing VMS does when work is done 3.86 + 3.87 + 3.88 + //This will suspend the main PThread until all VMSHW processors have 3.89 + // performed dissipate_self(), at which point the VMSHW system will 3.90 + // shut itself down, then shut VMS down then call notify to make this 3.91 + // wait wake up the main thread again. 3.92 + status = 3.93 + pthread_cond_wait( &VMS_Environ->doneCondition/*,&VMS_Environ->doneLock*/); 3.94 + if (status != 0){perror("Error waiting for work to finish\n"); exit(1);} 3.95 + 3.96 + //signal like this: pthread_cond_signal( &VMS_Environ->doneCondition ); 3.97 + 3.98 + } 3.99 + 3.100 +/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR 3.101 + * (still want to do FoR, with time-lines as syntax, could be super cool) 3.102 + * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate 3.103 + * among library, DKU, WT, FoR -- all the patterns in terms of work-units, 3.104 + * so Master picks which work-units from which portions of app onto which 3.105 + * Slaves 3.106 + *Might even do one master plus several slaves for each core -- allows 3.107 + * single-reader-single-writer sync everywhere -- no atomic primitives 3.108 + * Might have the different schedulers talk to each other, to negotiate 3.109 + * larger-grain sharing of resources, according to predicted critical 3.110 + * path, and expansion of work 3.111 + */ 3.112 + 3.113 + 3.114 + 3.115 +/*Causes the VMSHW system to remove internal ownership, so data won't be 3.116 + * freed when VMSHW shuts down, and will persist in the external program. 3.117 + */ 3.118 +void 3.119 +VMSHW__transfer_to_external( void *data ) 3.120 + { 3.121 + 3.122 + } 3.123 + 3.124 +void 3.125 +VMSHW__create_seed_processor_then_wait_until_work_done 3.126 + ( VMSHWProcrFnPtr fn, void *data ) 3.127 + { VMSHWEnviron semEnv; 3.128 + 3.129 + VMSHW__init(); 3.130 + semEnv = masterEnv->semanticEnv; 3.131 + 3.132 + //VMSHW starts with one processor, which is put into initial environ, 3.133 + // and, which then calls create() to create more thereby expanding work 3.134 + firstVirtProcr = VMSHW__create_processor( ); 3.135 + 3.136 + firstWorkUnit = 3.137 + 3.138 + writePrivQ( firstWorkUnit, semEnv->readyWorkUnitsQ ); 3.139 + 3.140 + //start the VMSHW system then wait for work to end 3.141 + //NOTE: no Threads should exist in the outside program that might touch 3.142 + // any of the data reachable from the params given to the seed procr 3.143 + VMSHW__start_then_wait_until_work_done(); 3.144 + } 3.145 + 3.146 +void 3.147 +VMSHW__create_processor( ) 3.148 + { 3.149 + firstWorkUnit = firstVirtProcr->latestWorkUnit; 3.150 + 3.151 + writePrivQ( firstWorkUnit, semanticEnv->readyWorkUnitsQ ); 3.152 + 3.153 + return firstVirtProcr; 3.154 + } 3.155 + 3.156 +VMSHWProcrFnPtr 3.157 + VMSHWProcr * VMSHW__create_processor( &calcVector, vectParams ); 3.158 + void * VMSHW__malloc( sizeof( VectorParams ) ); 3.159 + VMSHW__transfer_to_outside( resultMatrix ); 3.160 + VMSHW__dissipate_self(); //all processors have to dissipate self at end 3.161 + VMSHW__send( result, resultPr ); 3.162 + resultsParams->dividerPr = VMSHW__self(); 3.163 + VMSHW__start_then_wait_until_work_done(); 3.164 + VMSHW__create_seed_processor( ÷IntoVectors, dividerParams ); 3.165 +VMSHWProcr 3.166 + 3.167 + void * VMSHW__receive_from( self, resultPr ); 3.168 + void * VMSHW__receive_from_any_but( self, dividerPr ); 3.169 + void * VMSHW__receive_on_port( self, VECTOR_PORT ); 3.170 + 3.171 + VMSHW__transfer_ownership_from_to( resultMatrix, self, dividerPr ); 3.172 + 3.173 +void * 3.174 +VMSHW__receive_from( VMSHWProcr *callingPr, VMSHWProcr *sendingPr ) 3.175 + { VMSRequest *req; 3.176 + VMSHWReq reqPayload; 3.177 + 3.178 + //hash on the caller, 'cause always know it, but sometimes want to 3.179 + // receive from anonymous sender 3.180 + //Q: what happens if no "receive" is outstanding for one sender, but 3.181 + // do have an outstanding for a different sender? 3.182 + //need to treat each "from" as a separate port in the hash table 3.183 + 3.184 + reqPayload = malloc( sizeof(VMSHWReq) ); 3.185 + reqPayload->type = receive_from; 3.186 + reqPayload->key = callingPr->ID ^ sendingPr->ID << 16; //65K max procrs 3.187 + reqPayload->procr = callingPr; 3.188 + 3.189 + req = VMS__create_request( reqPayload ); 3.190 + VMS__add_request_to_slave( req, callingPr ); 3.191 + VMS__save_ret_and_jump_to_CoreLoop( callingPr ); 3.192 + } 3.193 + 3.194 + 3.195 + 3.196 +//=========================================================================== 3.197 + void 3.198 +freeParamStruc( ParamStruc * param ) 3.199 + { if( param->type == STRING_PARAM_TYPE ) free( param->strValue ); 3.200 + free( param ); 3.201 + } 3.202 + 3.203 + 3.204 + ParamStruc * 3.205 +makeParamStruc() 3.206 + { ParamStruc *retStruc; 3.207 + retStruc = malloc( sizeof( ParamStruc ) ); 3.208 + retStruc->floatValue = 0.0; 3.209 + retStruc->intValue = 0; 3.210 + retStruc->strValue = NULL; 3.211 + } 3.212 + 3.213 + ParamStruc * 3.214 +makeParamFromStrs( char * type, char *value ) 3.215 + { ParamStruc *retParam; 3.216 + retParam = makeParamStruc(); 3.217 + switch(*type) 3.218 + { case 'i': 3.219 + { retParam->type = INT_PARAM_TYPE; 3.220 + retParam->intValue = atoi( value ); 3.221 + } break; 3.222 + case 's': 3.223 + { retParam->type = STRING_PARAM_TYPE; 3.224 + retParam->strValue = malloc( strlen(value) + 1); 3.225 + strcpy( retParam->strValue, value ); 3.226 + } break; 3.227 + case 'f': 3.228 + { retParam->type = FLOAT_PARAM_TYPE; 3.229 + retParam->floatValue = atof( value ); 3.230 + } break; 3.231 + } 3.232 + return retParam; 3.233 + }
