Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
diff VMS.c @ 8:9a1b7de19e39
Compiles -- with win thds
| author | Me |
|---|---|
| date | Tue, 01 Jun 2010 05:33:01 -0700 |
| parents | cf5007e51b96 |
| children | d801fe740275 |
line diff
1.1 --- a/VMS.c Tue Jun 01 05:32:41 2010 -0700 1.2 +++ b/VMS.c Tue Jun 01 05:33:01 2010 -0700 1.3 @@ -14,34 +14,38 @@ 1.4 1.5 /*Setup has two phases: 1.6 * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts 1.7 - * the master work-unit into the work-queue 1.8 - * 2) Semantic layer then does its own init, which creates the initial 1.9 - * work-units inside the semantic layer, ready to schedule them when 1.10 + * the master virt procr into the work-queue, ready for first "call" 1.11 + * 2) Semantic layer then does its own init, which creates the seed virt 1.12 + * procr inside the semantic layer, ready to schedule it when 1.13 * asked by the first run of the masterLoop. 1.14 * 1.15 *This part is bit weird because VMS really wants to be "always there", and 1.16 * have applications attach and detach.. for now, this VMS is part of 1.17 * the app, so the VMS system starts up as part of running the app. 1.18 * 1.19 - *The semantic layer is fully isolated from the VMS internasl by 1.20 - * making the semantic layer setup into a state that it's ready with its 1.21 - * initial work-units, ready to schedule them to slaves when the masterLoop 1.22 + *The semantic layer is isolated from the VMS internals by making the 1.23 + * semantic layer do setup to a state that it's ready with its 1.24 + * initial virt procrs, ready to schedule them to slots when the masterLoop 1.25 * asks. Without this pattern, the semantic layer's setup would 1.26 - * have to modify slaves directly to assign the initial work-units, and put 1.27 + * have to modify slots directly to assign the initial virt-procrs, and put 1.28 * them into the workQ itself, breaking the isolation completely. 1.29 * 1.30 * 1.31 - *The semantic layer creates the initial work-unit(s), and adds its 1.32 - * own environment data to masterEnv, and fills in the pointers to 1.33 + *The semantic layer creates the initial virt procr(s), and adds its 1.34 + * own environment to masterEnv, and fills in the pointers to 1.35 * the requestHandler and slaveScheduler plug-in functions 1.36 - * 1.37 - *This allocates VMS data structures, populates the master VMSProc, 1.38 + */ 1.39 + 1.40 +void 1.41 +create_sched_slots( MasterEnv *masterEnv ); 1.42 + 1.43 + 1.44 +/*This allocates VMS data structures, populates the master VMSProc, 1.45 * and master environment, and returns the master environment to the semantic 1.46 * layer. 1.47 */ 1.48 - //Global vars are all inside VMS.h 1.49 -MasterEnv * 1.50 -VMS__init( ) 1.51 +void 1.52 +VMS__init() 1.53 { MasterEnv *masterEnv; 1.54 QueueStruc *workQ; 1.55 1.56 @@ -52,71 +56,43 @@ 1.57 _VMSMasterEnv = malloc( sizeof(MasterEnv) ); 1.58 masterEnv = _VMSMasterEnv; 1.59 1.60 - create_master( masterEnv ); 1.61 + //create the master virtual processor 1.62 + masterEnv->masterVirtPr = VMS__create_procr( &masterLoop, masterEnv ); 1.63 1.64 create_sched_slots( masterEnv ); 1.65 1.66 - masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //never checked 1.67 - masterEnv->schedSlots[0]->workIsDone = FALSE; //never checked 1.68 + //Set slot 0 to be the master virt procr & set flags just in case 1.69 + masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //says don't touch 1.70 + masterEnv->schedSlots[0]->workIsDone = FALSE; //says don't touch 1.71 masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr; 1.72 1.73 //First core loop to start up gets this, which will schedule seed Pr 1.74 //TODO: debug: check address of masterVirtPr 1.75 - writeQ( &(masterEnv->masterVirtPr), workQ ); 1.76 + writeQ( masterEnv->masterVirtPr, workQ ); 1.77 } 1.78 1.79 1.80 - 1.81 -/*Fill up the master VirtProcr data structure, which is already alloc'd 1.82 - * in the masterEnv. 1.83 - * The coreLoop treats master virt pr same as the slave virt processors 1.84 - * 1.85 - *The first time it runs, will jump to the function ptr so have to, in here, 1.86 - * create the stack, which will be used by the plug-in functions, and set 1.87 - * up __cdecl just like do for the other virtual processors. 1.88 - */ 1.89 -void 1.90 -create_master( MasterEnv *masterEnv ) 1.91 - { VirtProcr masterPr; 1.92 - char * stackLocs, stackPtr; 1.93 - 1.94 - //TODO: debug this to be sure got addr of struct in masterEnv correctly 1.95 - masterPr = &(masterEnv->masterVirtPr); 1.96 - masterPr->initialData = masterEnv; 1.97 - 1.98 - masterPr->nextInstrPt = &masterLoop; 1.99 - 1.100 - //alloc stack locations, make stackPtr be the last addr in the locs, 1.101 - // minus room for the two parameters. Put initData at stackPtr, 1.102 - // animatingPr just above 1.103 - stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size 1.104 - stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 ); 1.105 - masterPr->stackPtr = stackPtr; 1.106 - masterPr->framePtr = stackPtr; 1.107 - asm volatile("movl %0, %%esp; 1.108 - movl %1, (%%esp); 1.109 - movl %2, $0x4(%%esp); 1.110 - movl %%esp, %%ebp; " /*framePtr in ebp never used*/ 1.111 - /* outputs */ : 1.112 - /* inputs */ : "g" (stackPtr), "g" (initData), "g" (animPr) 1.113 - /* clobber */ : 1.114 - ); 1.115 - } 1.116 - 1.117 void 1.118 create_sched_slots( MasterEnv *masterEnv ) 1.119 - { SchedSlot *slots; 1.120 + { SchedSlot **schedSlots, **filledSlots; 1.121 int i; 1.122 1.123 - slots = masterEnv->schedSlots; //TODO: make sure this is right 1.124 + schedSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) ); 1.125 + filledSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) ); 1.126 + masterEnv->schedSlots = schedSlots; 1.127 + masterEnv->filledSlots = filledSlots; 1.128 + 1.129 for( i = 0; i < NUM_SCHED_SLOTS; i++ ) 1.130 { 1.131 + schedSlots[i] = malloc( sizeof(SchedSlot) ); 1.132 + 1.133 //Set state to mean "handling requests done, slot needs filling" 1.134 - slots[i].workIsDone = FALSE; 1.135 - slots[i].needsProcrAssigned = TRUE; 1.136 + schedSlots[i]->workIsDone = FALSE; 1.137 + schedSlots[i]->needsProcrAssigned = TRUE; 1.138 } 1.139 } 1.140 1.141 + 1.142 /*Semantic layer calls this when it want the system to start running.. 1.143 * 1.144 *This creates the core loops, pins them to physical cores, gives them the 1.145 @@ -126,31 +102,70 @@ 1.146 VMS__start() 1.147 { int retCode, coreIdx; 1.148 1.149 -//TODO: still just skeleton code -- figure out right way to do this 1.150 + //Create the win threads that animate the core loops 1.151 + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 1.152 + { 1.153 + thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) ); 1.154 + thdParams[coreIdx]->coreNum = coreIdx; 1.155 1.156 - //Create the PThread loops that take from work-queue, and start them 1.157 - for( coreIdx=0; coreIdx < NUM_WORKERS; coreIdx++ ) 1.158 - { 1.159 - thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) ); 1.160 - thdParams[coreIdx]->workQ = _VMSWorkQ; 1.161 - thdParams[coreIdx]->id = coreIdx; 1.162 + coreLoopThds[coreIdx] = 1.163 + CreateThread ( NULL, // Security attributes 1.164 + 0, // Stack size 1.165 + coreLoop, 1.166 + thdParams[coreIdx], 1.167 + CREATE_SUSPENDED, 1.168 + &(thdIds[coreIdx]) 1.169 + ); 1.170 + ResumeThread( coreLoopThds[coreIdx] ); //starts thread 1.171 + } 1.172 + } 1.173 1.174 - //Now make and start thd.. the coreLoopThds entry 1.175 - // has all the info needed to later stop the thread. 1.176 - retCode = 1.177 - pthread_create( &(coreLoopThds[coreIdx]), thdAttrs, &coreLoop, 1.178 - (void *)(thdParams[coreIdx]) ); 1.179 - if( retCode != 0 ) 1.180 - { //error 1.181 - printf("ERROR creating coreLoop %d, code: %d\n", coreIdx, retCode); 1.182 - exit(-1); 1.183 - } 1.184 1.185 - pinThdToCore( ); //figure out how to specify this.. 1.186 1.187 - startThd(); //look up PThread call to start the thread running, if it's 1.188 - // not automatic 1.189 - } 1.190 +/*Create stack, then create __cdecl structure on it and put initialData and 1.191 + * pointer to the new structure instance into the parameter positions on 1.192 + * the stack 1.193 + *Then put function pointer into nextInstrPt -- the stack is setup in std 1.194 + * call structure, so jumping to function ptr is same as a GCC generated 1.195 + * function call 1.196 + *No need to save registers on old stack frame, because there's no old 1.197 + * animator state to return to -- 1.198 + * 1.199 + */ 1.200 +VirtProcr * 1.201 +VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ) 1.202 + { VirtProcr *newPr; 1.203 + char *stackLocs, *stackPtr; 1.204 + 1.205 + newPr = malloc( sizeof(VirtProcr) ); 1.206 + newPr->nextInstrPt = fnPtr; 1.207 + newPr->initialData = initialData; 1.208 + 1.209 + //alloc stack locations, make stackPtr be the highest addr minus room 1.210 + // for 2 params. Put initData at stackPtr, animatingPr just above 1.211 + stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size 1.212 + stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 ); 1.213 + //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp 1.214 + *(stackPtr + 4) = newPr; //rightmost param 1.215 + *stackPtr = initialData; //next param to left 1.216 + newPr->stackPtr = stackPtr; //core loop will switch to this, then 1.217 + newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr 1.218 + 1.219 + return newPr; 1.220 + } 1.221 + 1.222 + 1.223 +/*This inserts the semantic-layer's data into the standard VMS carrier 1.224 + */ 1.225 +inline void 1.226 +VMS__send_sem_request( void *semReqData, VirtProcr *callingPr ) 1.227 + { SlaveReqst *req; 1.228 + 1.229 + req = malloc( sizeof(SlaveReqst) ); 1.230 + req->slaveFrom = callingPr; 1.231 + req->semReqData = semReqData; 1.232 + req->nextRequest = callingPr->requests; 1.233 + callingPr->requests = req; 1.234 } 1.235 1.236 /*there is a label inside this function -- save the addr of this label in 1.237 @@ -162,8 +177,9 @@ 1.238 * there, and will get passed along, inside the request handler, to the 1.239 * next work-unit for that procr. 1.240 */ 1.241 +void 1.242 VMS__suspend_processor( VirtProcr *callingPr ) 1.243 - { void *jmpPt; 1.244 + { void *jmpPt, *stackPtr, *framePtr; 1.245 1.246 callingPr->nextInstrPt = &&ResumePt; 1.247 1.248 @@ -171,13 +187,15 @@ 1.249 callingPr->schedSlot->workIsDone = TRUE; 1.250 1.251 jmpPt = callingPr->coreLoopStartPt; 1.252 + stackPtr = &(callingPr->stackPtr); 1.253 + framePtr = &(callingPr->framePtr); 1.254 1.255 //put all regs in the clobber list to make sure GCC has saved all 1.256 // so safe to jump to core loop, where they *will* get clobbered 1.257 - asm volatile("movl %%esp, %0; 1.258 - movl %%ebp, %1; 1.259 - jmp %2 " 1.260 - /* outputs */ : "=m" (currPr->stackPtr), "=m" (currPr->framePtr) 1.261 + asm volatile("movl %%esp, %0; \ 1.262 + movl %%ebp, %1; \ 1.263 + jmp %2 " 1.264 + /* outputs */ : "=g" (stackPtr), "=g" (framePtr) 1.265 /* inputs */ : "g" (jmpPt) 1.266 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi" 1.267 ); 1.268 @@ -186,45 +204,29 @@ 1.269 return; 1.270 } 1.271 1.272 +void 1.273 +VMS__dissipate_animating_processor( VirtProcr *animatingPr ) 1.274 + { 1.275 1.276 -/*Create stack, then create __cdecl structure on it and put initialData and 1.277 - * pointer to the new structure instance into the parameter positions on 1.278 - * the stack 1.279 - *Then put function pointer into nextInstrPt -- the stack is setup in std 1.280 - * call structure, so jumping to function ptr is same as a GCC generated 1.281 - * function call 1.282 - *No need to save registers on old stack frame, because there's no old 1.283 - * animator state to return to -- 1.284 - * 1.285 - */ 1.286 -VirtProcr * 1.287 -VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ) 1.288 - { VirtProcr newPr; 1.289 - 1.290 - newPr = malloc( sizeof(VirtProcr) ); 1.291 - newPr->nextInstrPt = fnPtr; 1.292 - newPr->initialData = initialData; 1.293 - newPr->stackPtr = createNewStack(); 1.294 - newPr->framePtr = newPr->stackPtr; 1.295 - put params onto stack and setup __cdecl call structure 1.296 - 1.297 - return newPr; 1.298 } 1.299 1.300 +/*This runs in main thread -- so can only signal to the core loop to shut 1.301 + * itself down -- 1.302 + * 1.303 + *Want the master to decide when to shut down -- when semantic layer tells it 1.304 + * to -- say, when all the application-virtual processors have dissipated. 1.305 + * 1.306 + *Maybe return a special code from scheduling plug-in.. master checks and 1.307 + * when sees, it shuts down the core loops -- does this by scheduling a 1.308 + * special virt processor whose next instr pt is the core-end label. 1.309 + */ 1.310 +void 1.311 +VMS__shutdown() 1.312 + { int coreIdx; 1.313 + 1.314 + //Create the win threads that animate the core loops 1.315 + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 1.316 + { 1.317 1.318 -/*The semantic virt procr is available in the request sent from the slave 1.319 - * 1.320 - * The request handler has to add the work-unit created to the semantic 1.321 - * virtual processor the work-unit is a section of its time-line -- does this when create the 1.322 - * work-unit -- means the procr data struc is available in the request sent 1.323 - * from the slave, from which the new work-unit is generated.. 1.324 - */ 1.325 -inline void 1.326 -VMS__add_request_to_slave( SlaveReqst req, VirtProcr callingPr ) 1.327 - { 1.328 - req->nextRequest = callingPr->requests; 1.329 - callingPr->requests = req; 1.330 - } 1.331 - 1.332 - 1.333 - 1.334 + } 1.335 + } 1.336 \ No newline at end of file
