| rev |
line source |
|
Me@0
|
1 /*
|
|
Me@0
|
2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
|
|
Me@0
|
3 *
|
|
Me@0
|
4 * Licensed under BSD
|
|
Me@0
|
5 */
|
|
Me@0
|
6
|
|
Me@0
|
7
|
|
Me@0
|
8
|
|
Me@0
|
9 #include <stdio.h>
|
|
Me@0
|
10 #include <malloc.h>
|
|
Me@9
|
11 #include <stddef.h>
|
|
Me@0
|
12
|
|
Me@0
|
13 #include "VMS.h"
|
|
Me@0
|
14
|
|
Me@0
|
15
|
|
Me@0
|
16
|
|
Me@0
|
17 /*This code is animated by the virtual Master processor.
|
|
Me@0
|
18 *
|
|
Me@11
|
19 *Polls each sched slot exactly once, hands any requests made by a newly
|
|
Me@11
|
20 * done slave to the "request handler" plug-in function
|
|
Me@0
|
21 *
|
|
Me@11
|
22 *Any slots that need a virt procr assigned are given to the "schedule"
|
|
Me@11
|
23 * plug-in function, which tries to assign a virt procr (slave) to it.
|
|
Me@0
|
24 *
|
|
Me@11
|
25 *When all slots needing a processor have been given to the schedule plug-in,
|
|
Me@11
|
26 * a fraction of the procrs successfully scheduled are put into the
|
|
Me@11
|
27 * work queue, then a continuation of this function is put in, then the rest
|
|
Me@11
|
28 * of the virt procrs that were successfully scheduled.
|
|
Me@0
|
29 *
|
|
Me@11
|
30 *The first thing the continuation does is busy-wait until the previous
|
|
Me@11
|
31 * animation completes. This is because an (unlikely) continuation may
|
|
Me@11
|
32 * sneak through queue before previous continuation is done putting second
|
|
Me@11
|
33 * part of scheduled slaves in, which is the only race condition.
|
|
Me@0
|
34 *
|
|
Me@0
|
35 */
|
|
Me@0
|
36
|
|
Me@4
|
37 /*May 29, 2010 -- birth a Master during init so that first core loop to
|
|
Me@11
|
38 * start running gets it and does all the stuff for a newly born --
|
|
Me@11
|
39 * from then on, will be doing continuation, but do suspension self
|
|
Me@4
|
40 * directly at end of master loop
|
|
Me@4
|
41 *So VMS__init just births the master virtual processor same way it births
|
|
Me@4
|
42 * all the others -- then does any extra setup needed and puts it into the
|
|
Me@4
|
43 * work queue.
|
|
Me@4
|
44 *However means have to make masterEnv a global static volatile the same way
|
|
Me@4
|
45 * did with workQ in core loop. -- for performance, put the
|
|
Me@11
|
46 * jump to the core loop directly in here, and have it directly jump back.
|
|
Me@4
|
47 */
|
|
Me@4
|
48 void masterLoop( void *initData, VirtProcr *masterPr )
|
|
Me@21
|
49 {
|
|
Me@26
|
50 int slotIdx, numFilled, filledSlotIdx, masterHasBeenQueued;
|
|
Me@21
|
51 VirtProcr *schedVirtPr;
|
|
Me@4
|
52 SchedSlot *currSlot, **schedSlots, **filledSlots;
|
|
Me@0
|
53 MasterEnv *masterEnv;
|
|
Me@26
|
54 VMSQueueStruc *workQ;
|
|
Me@21
|
55 void *jmpPt, *stackPtrAddr, *framePtrAddr, *stillRunningAddr;
|
|
Me@21
|
56 void *coreLoopFramePtr, *coreLoopStackPtr, *semanticEnv;
|
|
Me@4
|
57
|
|
Me@0
|
58 SlaveScheduler slaveScheduler;
|
|
Me@0
|
59 RequestHandler requestHandler;
|
|
Me@0
|
60
|
|
Me@4
|
61 //this will run as the first virt processor in workQ, and will be a
|
|
Me@4
|
62 // new born -- so will do all the GCC-generated allocating space on
|
|
Me@4
|
63 // the stack owned by master virt procr -- and will run this last bit
|
|
Me@4
|
64 // of setup code..
|
|
Me@4
|
65 masterPr->nextInstrPt = &&masterLoopStartPt;
|
|
Me@0
|
66
|
|
Me@26
|
67 //The second time MasterVP comes out of queue, the first animation of
|
|
Me@26
|
68 // it hasn't written the stackPtr and framePtr yet -- but the second
|
|
Me@26
|
69 // animation has already had its stackPtr and framePtr set to the old
|
|
Me@26
|
70 // value by the coreLoop. Fix this by writing the correct stack and
|
|
Me@26
|
71 // frame pointers here, at which point they're correct in the first
|
|
Me@26
|
72 // animation of MasterVP.
|
|
Me@26
|
73 //TODO: remove writing stackPtr and framePtr at the bottom, for eff
|
|
Me@26
|
74 stackPtrAddr = &(masterPr->stackPtr);
|
|
Me@26
|
75 framePtrAddr = &(masterPr->framePtr);
|
|
Me@26
|
76
|
|
Me@26
|
77 asm volatile("movl %0, %%eax; \
|
|
Me@26
|
78 movl %%esp, (%%eax); \
|
|
Me@26
|
79 movl %1, %%eax; \
|
|
Me@26
|
80 movl %%ebp, (%%eax); "
|
|
Me@26
|
81 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr) \
|
|
Me@26
|
82 /* inputs */ : \
|
|
Me@26
|
83 /* clobber */ : "memory", "%eax", "%ebx" \
|
|
Me@26
|
84 );
|
|
Me@26
|
85
|
|
Me@26
|
86
|
|
Me@4
|
87 masterLoopStartPt:
|
|
Me@0
|
88
|
|
Me@4
|
89 //if another reference to same Master VirtProcr still going, busy-wait
|
|
Me@4
|
90 //Could put this lower, but don't want to think about shared stack..
|
|
Me@21
|
91 while( _VMSMasterEnv->stillRunning ) /*busy wait*/ ;
|
|
Me@4
|
92 //TODO: want to do busy-wait as assembly, to be sure stack not touched?
|
|
Me@4
|
93
|
|
Me@4
|
94 //this is the only master running now, set flag again
|
|
Me@21
|
95 _VMSMasterEnv->stillRunning = TRUE;
|
|
Me@21
|
96 masterEnv = _VMSMasterEnv;
|
|
Me@4
|
97
|
|
Me@4
|
98 //TODO: gdb -- check that a volatile _VMSMasterEnv and _VMSWorkQ means
|
|
Me@4
|
99 // all these will be re-filled every time jump here..
|
|
Me@4
|
100 workQ = _VMSWorkQ;
|
|
Me@0
|
101 requestHandler = masterEnv->requestHandler;
|
|
Me@0
|
102 slaveScheduler = masterEnv->slaveScheduler;
|
|
Me@4
|
103 schedSlots = masterEnv->schedSlots;
|
|
Me@4
|
104 filledSlots = masterEnv->filledSlots;
|
|
Me@11
|
105 masterPr = masterEnv->masterVirtPr; //post-jmp clobbered, re-load
|
|
Me@21
|
106 semanticEnv = masterEnv->semanticEnv;
|
|
Me@0
|
107
|
|
Me@0
|
108 //prepare for scheduling
|
|
Me@26
|
109 numFilled = 0;
|
|
Me@26
|
110 masterHasBeenQueued = FALSE;
|
|
Me@0
|
111
|
|
Me@21
|
112 //Poll each slot's Done flag -- slot 0 reserved for master, start at 1
|
|
Me@26
|
113 for( slotIdx = 0; slotIdx < NUM_SCHED_SLOTS; slotIdx++)
|
|
Me@0
|
114 {
|
|
Me@4
|
115 currSlot = schedSlots[ slotIdx ];
|
|
Me@0
|
116
|
|
Me@4
|
117 if( currSlot->workIsDone )
|
|
Me@0
|
118 {
|
|
Me@4
|
119 currSlot->workIsDone = FALSE;
|
|
Me@4
|
120 currSlot->needsProcrAssigned = TRUE;
|
|
Me@0
|
121
|
|
Me@0
|
122 //process requests from slave to master
|
|
Me@21
|
123 (*requestHandler)( currSlot->procrAssignedToSlot, semanticEnv );
|
|
Me@0
|
124 }
|
|
Me@4
|
125 if( currSlot->needsProcrAssigned )
|
|
Me@4
|
126 { //give slot a new virt procr
|
|
Me@21
|
127 schedVirtPr =
|
|
Me@21
|
128 (*slaveScheduler)( semanticEnv );
|
|
Me@0
|
129
|
|
Me@21
|
130 if( schedVirtPr != NULL )
|
|
Me@21
|
131 { currSlot->procrAssignedToSlot = schedVirtPr;
|
|
Me@26
|
132 schedVirtPr->schedSlot = currSlot;
|
|
Me@26
|
133 currSlot->needsProcrAssigned = FALSE;
|
|
Me@4
|
134
|
|
Me@26
|
135 filledSlots[ numFilled ] = currSlot;
|
|
Me@26
|
136 numFilled += 1;
|
|
Me@4
|
137
|
|
Me@26
|
138 writeVMSQ( schedVirtPr, workQ );
|
|
Me@26
|
139 if( numFilled == masterEnv->numToPrecede )
|
|
Me@26
|
140 {
|
|
Me@26
|
141 writeVMSQ( masterEnv->masterVirtPr, workQ );
|
|
Me@26
|
142 masterHasBeenQueued = TRUE;
|
|
Me@26
|
143 }
|
|
Me@26
|
144
|
|
Me@0
|
145 }
|
|
Me@0
|
146 }
|
|
Me@0
|
147 }
|
|
Me@0
|
148
|
|
Me@26
|
149 if( !masterHasBeenQueued )
|
|
Me@26
|
150 {
|
|
Me@26
|
151 writeVMSQ( masterEnv->masterVirtPr, workQ );
|
|
Me@26
|
152 }
|
|
Me@26
|
153
|
|
Me@26
|
154 //Adjust the number to precede, for next round -- assume rate of
|
|
Me@26
|
155 // finishing work is stable -- which is a bad assumption! But, just
|
|
Me@26
|
156 // want something working for the moment, look at dynamic behavior
|
|
Me@26
|
157 // later
|
|
Me@26
|
158 //TODO: look at dynamic behavior -- time-average numToPrecede or something
|
|
Me@26
|
159 if( numFilled < NUM_CORES - 1 )
|
|
Me@26
|
160 {
|
|
Me@26
|
161 masterEnv->numToPrecede = 0;
|
|
Me@26
|
162 }
|
|
Me@26
|
163 else
|
|
Me@26
|
164 { masterEnv->numToPrecede = numFilled - NUM_CORES + 1;
|
|
Me@26
|
165 }
|
|
Me@26
|
166 /*
|
|
Me@21
|
167 //put some scheduled slaves in, then Master continuation, then rest
|
|
Me@21
|
168 //Adjust position of master such that it maintains close to a fixed
|
|
Me@21
|
169 // ratio --> make NUM_CORES - 1 slots or fewer come after the master
|
|
Me@26
|
170
|
|
Me@21
|
171 for( filledSlotIdx = 0; filledSlotIdx < numPrecede; filledSlotIdx++)
|
|
Me@0
|
172 {
|
|
Me@26
|
173 writeVMSQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
|
|
Me@0
|
174 }
|
|
Me@0
|
175
|
|
Me@0
|
176 //enqueue continuation of this loop
|
|
Me@0
|
177 // note that After this enqueue, continuation might sneak through
|
|
Me@26
|
178 writeVMSQ( masterEnv->masterVirtPr, workQ );
|
|
Me@21
|
179
|
|
Me@21
|
180 for( filledSlotIdx = numPrecede;
|
|
Me@21
|
181 filledSlotIdx < numFilled;
|
|
Me@4
|
182 filledSlotIdx++)
|
|
Me@0
|
183 {
|
|
Me@26
|
184 writeVMSQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
|
|
Me@0
|
185 }
|
|
Me@0
|
186
|
|
Me@4
|
187 masterEnv->numFilled = 0;
|
|
Me@26
|
188 */
|
|
Me@4
|
189
|
|
Me@4
|
190 //Save stack ptr and frame -- don't need to, take out later, but safe
|
|
Me@4
|
191 // Also, wait to set stillRunning to FALSE until just before jump, to
|
|
Me@21
|
192 // be safe -- although the two simulatneously animated MasterLoops
|
|
Me@21
|
193 // are on different cores, so have different stacks, so no worries
|
|
Me@21
|
194 // there.
|
|
Me@21
|
195 //Restore CoreLoop's stack frame (and stack pointer, to be safe)
|
|
Me@21
|
196 //TODO: cafefully verify don't need to force saving anything to stack
|
|
Me@21
|
197 // before jumping back to core loop.
|
|
Me@21
|
198 stackPtrAddr = &(masterPr->stackPtr);
|
|
Me@21
|
199 framePtrAddr = &(masterPr->framePtr);
|
|
Me@21
|
200 stillRunningAddr = &(_VMSMasterEnv->stillRunning); //when race condition
|
|
Me@21
|
201 //arises, stillRunning is shared between the two cores both animating
|
|
Me@21
|
202 // MasterLoop -- but those two cores have different esp & ebp, so safe
|
|
Me@21
|
203 // to change stack and frame pointer here, without one messing up other
|
|
Me@21
|
204 // one
|
|
Me@21
|
205
|
|
Me@21
|
206 jmpPt = masterPr->coreLoopStartPt;
|
|
Me@21
|
207 coreLoopFramePtr = masterPr->coreLoopFramePtr;//need this only
|
|
Me@21
|
208 coreLoopStackPtr = masterPr->coreLoopStackPtr;//shouldn't need -- safety
|
|
Me@21
|
209
|
|
Me@21
|
210 asm volatile("movl %0, %%eax; \
|
|
Me@21
|
211 movl %%esp, (%%eax); \
|
|
Me@21
|
212 movl %1, %%eax; \
|
|
Me@21
|
213 movl %%ebp, (%%eax); \
|
|
Me@21
|
214 movl %2, %%ebx; \
|
|
Me@21
|
215 movl %3, %%eax; \
|
|
Me@21
|
216 movl %4, %%esp; \
|
|
Me@21
|
217 movl %5, %%ebp; \
|
|
Me@21
|
218 movl $0x0, (%%ebx); \
|
|
Me@21
|
219 jmp %%eax " \
|
|
Me@21
|
220 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr), \
|
|
Me@21
|
221 "=g"(stillRunningAddr) \
|
|
Me@21
|
222 /* inputs */ : "g" (jmpPt), "g"(coreLoopStackPtr), "g"(coreLoopFramePtr)\
|
|
Me@21
|
223 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" \
|
|
Me@21
|
224 );//can probably make clobber list empty -- but safe for now
|
|
Me@0
|
225 }
|
|
Me@0
|
226
|
|
Me@0
|
227
|