view MasterLoop.c @ 24:2b161e1a50ee

1st working version -- as far as can tell due to SEH bugs
author Me
date Wed, 07 Jul 2010 13:15:54 -0700
parents e2de204909bf
children 668278fa7a63
line source
1 /*
2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
3 *
4 * Licensed under BSD
5 */
9 #include <windows.h>
10 #include <stdio.h>
11 #include <malloc.h>
12 #include <stddef.h>
14 #include "VMS.h"
18 /*This code is animated by the virtual Master processor.
19 *
20 *Polls each sched slot exactly once, hands any requests made by a newly
21 * done slave to the "request handler" plug-in function
22 *
23 *Any slots that need a virt procr assigned are given to the "schedule"
24 * plug-in function, which tries to assign a virt procr (slave) to it.
25 *
26 *When all slots needing a processor have been given to the schedule plug-in,
27 * a fraction of the procrs successfully scheduled are put into the
28 * work queue, then a continuation of this function is put in, then the rest
29 * of the virt procrs that were successfully scheduled.
30 *
31 *The first thing the continuation does is busy-wait until the previous
32 * animation completes. This is because an (unlikely) continuation may
33 * sneak through queue before previous continuation is done putting second
34 * part of scheduled slaves in, which is the only race condition.
35 *
36 */
38 /*May 29, 2010 -- birth a Master during init so that first core loop to
39 * start running gets it and does all the stuff for a newly born --
40 * from then on, will be doing continuation, but do suspension self
41 * directly at end of master loop
42 *So VMS__init just births the master virtual processor same way it births
43 * all the others -- then does any extra setup needed and puts it into the
44 * work queue.
45 *However means have to make masterEnv a global static volatile the same way
46 * did with workQ in core loop. -- for performance, put the
47 * jump to the core loop directly in here, and have it directly jump back.
48 */
49 void masterLoop( void *initData, VirtProcr *masterPr )
50 {
51 int slotIdx, numFilled, numInFirstChunk, filledSlotIdx;
52 VirtProcr *schedVirtPr;
53 SchedSlot *currSlot, **schedSlots, **filledSlots;
54 MasterEnv *masterEnv;
55 CASQueueStruc *workQ;
56 void *jmpPt, *stackPtrAddr, *framePtrAddr, *stillRunningAddr;
57 void *coreLoopFramePtr, *coreLoopStackPtr, *semanticEnv;
59 SlaveScheduler slaveScheduler;
60 RequestHandler requestHandler;
62 //this will run as the first virt processor in workQ, and will be a
63 // new born -- so will do all the GCC-generated allocating space on
64 // the stack owned by master virt procr -- and will run this last bit
65 // of setup code..
66 masterPr->nextInstrPt = &&masterLoopStartPt;
69 masterLoopStartPt:
71 //if another reference to same Master VirtProcr still going, busy-wait
72 //Could put this lower, but don't want to think about shared stack..
73 while( _VMSMasterEnv->stillRunning ) /*busy wait*/ ;
74 //TODO: want to do busy-wait as assembly, to be sure stack not touched?
76 //this is the only master running now, set flag again
77 _VMSMasterEnv->stillRunning = TRUE;
78 masterEnv = _VMSMasterEnv;
80 //TODO: gdb -- check that a volatile _VMSMasterEnv and _VMSWorkQ means
81 // all these will be re-filled every time jump here..
82 workQ = _VMSWorkQ;
83 requestHandler = masterEnv->requestHandler;
84 slaveScheduler = masterEnv->slaveScheduler;
85 schedSlots = masterEnv->schedSlots;
86 filledSlots = masterEnv->filledSlots;
87 masterPr = masterEnv->masterVirtPr; //post-jmp clobbered, re-load
88 semanticEnv = masterEnv->semanticEnv;
90 //prepare for scheduling
91 masterEnv->numFilled = 0;
93 //Poll each slot's Done flag -- slot 0 reserved for master, start at 1
94 for( slotIdx = 1; slotIdx < NUM_SCHED_SLOTS; slotIdx++)
95 {
96 currSlot = schedSlots[ slotIdx ];
98 if( currSlot->workIsDone )
99 {
100 currSlot->workIsDone = FALSE;
101 currSlot->needsProcrAssigned = TRUE;
103 //process requests from slave to master
104 (*requestHandler)( currSlot->procrAssignedToSlot, semanticEnv );
105 }
106 if( currSlot->needsProcrAssigned )
107 { //give slot a new virt procr
108 schedVirtPr =
109 (*slaveScheduler)( semanticEnv );
111 if( schedVirtPr != NULL )
112 { currSlot->procrAssignedToSlot = schedVirtPr;
113 schedVirtPr->schedSlot = currSlot;
115 filledSlots[ masterEnv->numFilled ] = currSlot;
116 masterEnv->numFilled += 1;
118 currSlot->needsProcrAssigned = FALSE;
119 }
120 }
121 }
123 //put some scheduled slaves in, then Master continuation, then rest
124 //Adjust position of master such that it maintains close to a fixed
125 // ratio --> make NUM_CORES - 1 slots or fewer come after the master
126 numFilled = masterEnv->numFilled;
128 int numPrecede = numFilled;
129 int numFollow = NUM_CORES - 1;
131 if( numFilled < numFollow )
132 { numFollow = numFilled;
133 numPrecede = 0;
134 }
135 else
136 { numPrecede -= numFollow;
137 }
139 for( filledSlotIdx = 0; filledSlotIdx < numPrecede; filledSlotIdx++)
140 {
141 writeCASQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
142 }
144 //enqueue continuation of this loop
145 // note that After this enqueue, continuation might sneak through
146 writeCASQ( masterEnv->masterVirtPr, workQ );
148 for( filledSlotIdx = numPrecede;
149 filledSlotIdx < numFilled;
150 filledSlotIdx++)
151 {
152 writeCASQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
153 }
155 masterEnv->numFilled = 0;
158 //Save stack ptr and frame -- don't need to, take out later, but safe
159 // Also, wait to set stillRunning to FALSE until just before jump, to
160 // be safe -- although the two simulatneously animated MasterLoops
161 // are on different cores, so have different stacks, so no worries
162 // there.
163 //Restore CoreLoop's stack frame (and stack pointer, to be safe)
164 //TODO: cafefully verify don't need to force saving anything to stack
165 // before jumping back to core loop.
166 stackPtrAddr = &(masterPr->stackPtr);
167 framePtrAddr = &(masterPr->framePtr);
168 stillRunningAddr = &(_VMSMasterEnv->stillRunning); //when race condition
169 //arises, stillRunning is shared between the two cores both animating
170 // MasterLoop -- but those two cores have different esp & ebp, so safe
171 // to change stack and frame pointer here, without one messing up other
172 // one
174 jmpPt = masterPr->coreLoopStartPt;
175 coreLoopFramePtr = masterPr->coreLoopFramePtr;//need this only
176 coreLoopStackPtr = masterPr->coreLoopStackPtr;//shouldn't need -- safety
178 asm volatile("movl %0, %%eax; \
179 movl %%esp, (%%eax); \
180 movl %1, %%eax; \
181 movl %%ebp, (%%eax); \
182 movl %2, %%ebx; \
183 movl %3, %%eax; \
184 movl %4, %%esp; \
185 movl %5, %%ebp; \
186 movl $0x0, (%%ebx); \
187 jmp %%eax " \
188 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr), \
189 "=g"(stillRunningAddr) \
190 /* inputs */ : "g" (jmpPt), "g"(coreLoopStackPtr), "g"(coreLoopFramePtr)\
191 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" \
192 );//can probably make clobber list empty -- but safe for now
193 }