view VMS.c @ 18:734c665500e4

Kinda have test working -- assembly looks right for saving core loop frame and stack and restoring them But have a bug that looks timing-related, so thinking maybe some threads are going to completion? The whole test isn't quite right yet -- it throws exception because the suspended virtual processors never have a continuation put back into the workQ (is this right? Is that why it throws exception?) Want to move to full code to finish debugging
author Me
date Tue, 22 Jun 2010 12:37:43 -0700
parents 65c8fb2821ee
children 1dbc7f6e3e67
line source
1 /*
2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
3 *
4 * Licensed under BSD
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <malloc.h>
11 #include "VMS.h"
12 #include "Queue_impl/BlockingQueue.h"
15 /*Setup has two phases:
16 * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts
17 * the master virt procr into the work-queue, ready for first "call"
18 * 2) Semantic layer then does its own init, which creates the seed virt
19 * procr inside the semantic layer, ready to schedule it when
20 * asked by the first run of the masterLoop.
21 *
22 *This part is bit weird because VMS really wants to be "always there", and
23 * have applications attach and detach.. for now, this VMS is part of
24 * the app, so the VMS system starts up as part of running the app.
25 *
26 *The semantic layer is isolated from the VMS internals by making the
27 * semantic layer do setup to a state that it's ready with its
28 * initial virt procrs, ready to schedule them to slots when the masterLoop
29 * asks. Without this pattern, the semantic layer's setup would
30 * have to modify slots directly to assign the initial virt-procrs, and put
31 * them into the workQ itself, breaking the isolation completely.
32 *
33 *
34 *The semantic layer creates the initial virt procr(s), and adds its
35 * own environment to masterEnv, and fills in the pointers to
36 * the requestHandler and slaveScheduler plug-in functions
37 */
39 void
40 create_sched_slots( MasterEnv *masterEnv );
43 /*This allocates VMS data structures, populates the master VMSProc,
44 * and master environment, and returns the master environment to the semantic
45 * layer.
46 */
47 void
48 VMS__init()
49 { MasterEnv *masterEnv;
50 CASQueueStruc *workQ;
52 //Make the central work-queue
53 _VMSWorkQ = makeCASQ();
54 workQ = _VMSWorkQ;
56 _VMSMasterEnv = malloc( sizeof(MasterEnv) );
57 masterEnv = _VMSMasterEnv;
59 //create the master virtual processor
60 masterEnv->masterVirtPr = VMS__create_procr( &masterLoop, masterEnv );
62 create_sched_slots( masterEnv );
64 //Set slot 0 to be the master virt procr & set flags just in case
65 masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //says don't touch
66 masterEnv->schedSlots[0]->workIsDone = FALSE; //says don't touch
67 masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr;
69 //First core loop to start up gets this, which will schedule seed Pr
70 //TODO: debug: check address of masterVirtPr
71 //TODO: commented out for debugging -- put it back in!!
72 // writeCASQ( masterEnv->masterVirtPr, workQ );
74 numProcrsCreated = 1;
75 }
78 void
79 create_sched_slots( MasterEnv *masterEnv )
80 { SchedSlot **schedSlots, **filledSlots;
81 int i;
83 schedSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) );
84 filledSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) );
85 masterEnv->schedSlots = schedSlots;
86 masterEnv->filledSlots = filledSlots;
88 for( i = 0; i < NUM_SCHED_SLOTS; i++ )
89 {
90 schedSlots[i] = malloc( sizeof(SchedSlot) );
92 //Set state to mean "handling requests done, slot needs filling"
93 schedSlots[i]->workIsDone = FALSE;
94 schedSlots[i]->needsProcrAssigned = TRUE;
95 }
96 }
99 /*Semantic layer calls this when it want the system to start running..
100 *
101 *This creates the core loops, pins them to physical cores, gives them the
102 * pointer to the workQ, and starts them running.
103 */
104 void
105 VMS__start()
106 { int coreIdx;
108 //TODO: Save "orig" stack pointer and frame ptr -- restore in VMS__end()
109 //Create the win threads that animate the core loops
110 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
111 {
112 coreLoopThdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) );
113 coreLoopThdParams[coreIdx]->coreNum = coreIdx;
115 coreLoopThdHandles[coreIdx] =
116 CreateThread ( NULL, // Security attributes
117 0, // Stack size
118 coreLoop,
119 coreLoopThdParams[coreIdx],
120 CREATE_SUSPENDED,
121 &(coreLoopThdIds[coreIdx])
122 );
123 ResumeThread( coreLoopThdHandles[coreIdx] ); //starts thread
124 }
125 }
129 /*Create stack, then create __cdecl structure on it and put initialData and
130 * pointer to the new structure instance into the parameter positions on
131 * the stack
132 *Then put function pointer into nextInstrPt -- the stack is setup in std
133 * call structure, so jumping to function ptr is same as a GCC generated
134 * function call
135 *No need to save registers on old stack frame, because there's no old
136 * animator state to return to --
137 *
138 */
139 VirtProcr *
140 VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
141 { VirtProcr *newPr;
142 char *stackLocs, *stackPtr;
144 newPr = malloc( sizeof(VirtProcr) );
145 newPr->procrID = numProcrsCreated++;
146 newPr->nextInstrPt = fnPtr;
147 newPr->initialData = initialData;
149 //fnPtr takes two params -- void *initData & void *animProcr
150 //alloc stack locations, make stackPtr be the highest addr minus room
151 // for 2 params + return addr. Return addr (NULL) is in loc pointed to
152 // by stackPtr, initData at stackPtr + 4 bytes, animatingPr just above
153 stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size
154 stackPtr = ( (char *)stackLocs + 0x100000 - 0x10 );
155 //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp
156 *( (int *)stackPtr + 2 ) = (int) newPr; //rightmost param -- 32bit pointer
157 *( (int *)stackPtr + 1 ) = (int) initialData; //next param to left
158 newPr->stackPtr = stackPtr; //core loop will switch to this, then
159 newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr
161 return newPr;
162 }
165 /*This inserts the semantic-layer's data into the standard VMS carrier
166 */
167 inline void
168 VMS__send_sem_request( void *semReqData, VirtProcr *callingPr )
169 { SlaveReqst *req;
171 req = malloc( sizeof(SlaveReqst) );
172 req->slaveFrom = callingPr;
173 req->semReqData = semReqData;
174 req->nextRequest = callingPr->requests;
175 callingPr->requests = req;
176 }
178 /*there is a label inside this function -- save the addr of this label in
179 * the callingPr struc, as the pick-up point from which to start the next
180 * work-unit for that procr. If turns out have to save registers, then
181 * save them in the procr struc too. Then do assembly jump to the CoreLoop's
182 * "done with work-unit" label. The procr struc is in the request in the
183 * slave that animated the just-ended work-unit, so all the state is saved
184 * there, and will get passed along, inside the request handler, to the
185 * next work-unit for that procr.
186 */
187 void
188 VMS__suspend_processor( VirtProcr *callingPr )
189 { void *jmpPt, *stackPtrAddr, *framePtrAddr, *coreLoopStackPtr;
190 void *coreLoopFramePtr;
191 int coreIdx;
193 //The request to master will cause this suspended virt procr to get
194 // scheduled again at some future point -- to resume, core loop jumps
195 // to the resume point (below), which causes restore of saved regs and
196 // "return" from this call.
197 callingPr->nextInstrPt = &&ResumePt;
199 //return ownership of the virt procr and sched slot to Master virt pr
200 callingPr->schedSlot->workIsDone = TRUE;
201 // coreIdx = callingPr->coreAnimatedBy;
203 stackPtrAddr = &(callingPr->stackPtr);
204 framePtrAddr = &(callingPr->framePtr);
206 jmpPt = callingPr->coreLoopStartPt;
207 coreLoopFramePtr = callingPr->coreLoopFramePtr;//need this only
208 coreLoopStackPtr = callingPr->coreLoopStackPtr;//shouldn't need -- safety
210 //Save the virt procr's stack and frame ptrs, restore coreloop's frame
211 // ptr, then jump back to "start" of core loop
212 asm volatile("movl %0, %%eax; \
213 movl %%esp, (%%eax); \
214 movl %1, %%eax; \
215 movl %%ebp, (%%eax); \
216 movl %2, %%eax; \
217 movl %3, %%esp; \
218 movl %4, %%ebp; \
219 jmp %%eax " \
220 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr) \
221 /* inputs */ : "g" (jmpPt), "g"(coreLoopStackPtr), "g"(coreLoopFramePtr)\
222 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi" \
223 ); //list everything as clobbered to force GCC to save all
224 // live vars that are in regs on stack before this
225 // assembly, so that stack pointer is correct, before jmp
227 ResumePt:
228 return;
229 }
231 void
232 VMS__dissipate_animating_processor( VirtProcr *animatingPr )
233 {
235 }
237 /*This runs in main thread -- so can only signal to the core loop to shut
238 * itself down --
239 *
240 *Want the master to decide when to shut down -- when semantic layer tells it
241 * to -- say, when all the application-virtual processors have dissipated.
242 *
243 *Maybe return a special code from scheduling plug-in.. master checks and
244 * when sees, it shuts down the core loops -- does this by scheduling a
245 * special virt processor whose next instr pt is the core-end label.
246 */
247 void
248 VMS__shutdown()
249 { int coreIdx;
250 VirtProcr *shutDownPr;
252 //TODO: restore the "orig" stack pointer and frame ptr saved in VMS__start
253 //create a "special" virtual processor, one for each core loop that has
254 // the "loop end" point as its "next instr" point -- when the core loop
255 // jumps to animate the virt procr, the jump lands it at its own
256 // shut-down code.
257 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
258 {
259 shutDownPr = VMS__create_procr( NULL, NULL );
260 shutDownPr->nextInstrPt = _VMSMasterEnv->coreLoopShutDownPt;
261 }
262 }
266 inline TSCount getTSCount()
267 { unsigned int low, high;
268 TSCount out;
270 saveTimeStampCountInto( low, high );
271 out = high;
272 out = (out << 32) + low;
273 return out;
274 }