| 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 #include <stdio.h>
|
|
Me@0
|
8 #include <stdlib.h>
|
|
Me@0
|
9 #include <malloc.h>
|
|
Me@0
|
10
|
|
Me@0
|
11 #include "VMS.h"
|
|
Me@0
|
12 #include "Queue_impl/BlockingQueue.h"
|
|
Me@0
|
13
|
|
Me@0
|
14
|
|
Me@0
|
15 /*Setup has two phases:
|
|
Me@0
|
16 * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts
|
|
Me@0
|
17 * the master work-unit into the work-queue
|
|
Me@0
|
18 * 2) Semantic layer then does its own init, which creates the initial
|
|
Me@0
|
19 * work-units inside the semantic layer, ready to schedule them when
|
|
Me@0
|
20 * asked by the first run of the masterLoop.
|
|
Me@0
|
21 *
|
|
Me@0
|
22 *This part is bit weird because VMS really wants to be "always there", and
|
|
Me@0
|
23 * have applications attach and detach.. for now, this VMS is part of
|
|
Me@0
|
24 * the app, so the VMS system starts up as part of running the app.
|
|
Me@0
|
25 *
|
|
Me@0
|
26 *The semantic layer is fully isolated from the VMS internasl by
|
|
Me@0
|
27 * making the semantic layer setup into a state that it's ready with its
|
|
Me@0
|
28 * initial work-units, ready to schedule them to slaves when the masterLoop
|
|
Me@0
|
29 * asks. Without this pattern, the semantic layer's setup would
|
|
Me@0
|
30 * have to modify slaves directly to assign the initial work-units, and put
|
|
Me@0
|
31 * them into the workQ itself, breaking the isolation completely.
|
|
Me@0
|
32 *
|
|
Me@0
|
33 *
|
|
Me@0
|
34 *The semantic layer creates the initial work-unit(s), and adds its
|
|
Me@0
|
35 * own environment data to masterEnv, and fills in the pointers to
|
|
Me@0
|
36 * the requestHandler and slaveScheduler plug-in functions
|
|
Me@0
|
37 *
|
|
Me@0
|
38 *This allocates VMS data structures, populates the master VMSProc,
|
|
Me@0
|
39 * and master environment, and returns the master environment to the semantic
|
|
Me@0
|
40 * layer.
|
|
Me@0
|
41 */
|
|
Me@0
|
42 //Global vars are all inside VMS.h
|
|
Me@0
|
43 MasterEnv *
|
|
Me@1
|
44 VMS__init( )
|
|
Me@1
|
45 { MasterEnv *masterEnv;
|
|
Me@1
|
46 QueueStruc *workQ;
|
|
Me@1
|
47
|
|
Me@0
|
48 //Make the central work-queue
|
|
Me@1
|
49 _VMSWorkQ = makeQ();
|
|
Me@1
|
50 workQ = _VMSWorkQ;
|
|
Me@0
|
51
|
|
Me@1
|
52 _VMSMasterEnv = malloc( sizeof(MasterEnv) );
|
|
Me@1
|
53 masterEnv = _VMSMasterEnv;
|
|
Me@0
|
54
|
|
Me@0
|
55 create_master( masterEnv );
|
|
Me@0
|
56
|
|
Me@1
|
57 create_sched_slots( masterEnv );
|
|
Me@0
|
58
|
|
Me@1
|
59 masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //never checked
|
|
Me@1
|
60 masterEnv->schedSlots[0]->workIsDone = FALSE; //never checked
|
|
Me@1
|
61 masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr;
|
|
Me@1
|
62
|
|
Me@1
|
63 //First core loop to start up gets this, which will schedule seed Pr
|
|
Me@1
|
64 //TODO: debug: check address of masterVirtPr
|
|
Me@1
|
65 writeQ( &(masterEnv->masterVirtPr), workQ );
|
|
Me@0
|
66 }
|
|
Me@0
|
67
|
|
Me@0
|
68
|
|
Me@0
|
69
|
|
Me@1
|
70 /*Fill up the master VirtProcr data structure, which is already alloc'd
|
|
Me@1
|
71 * in the masterEnv.
|
|
Me@1
|
72 * The coreLoop treats master virt pr same as the slave virt processors
|
|
Me@1
|
73 *
|
|
Me@1
|
74 *The first time it runs, will jump to the function ptr so have to, in here,
|
|
Me@1
|
75 * create the stack, which will be used by the plug-in functions, and set
|
|
Me@1
|
76 * up __cdecl just like do for the other virtual processors.
|
|
Me@0
|
77 */
|
|
Me@0
|
78 void
|
|
Me@0
|
79 create_master( MasterEnv *masterEnv )
|
|
Me@1
|
80 { VirtProcr masterPr;
|
|
Me@1
|
81 char * stackLocs, stackPtr;
|
|
Me@0
|
82
|
|
Me@1
|
83 //TODO: debug this to be sure got addr of struct in masterEnv correctly
|
|
Me@1
|
84 masterPr = &(masterEnv->masterVirtPr);
|
|
Me@1
|
85 masterPr->initialData = masterEnv;
|
|
Me@1
|
86
|
|
Me@1
|
87 masterPr->nextInstrPt = &masterLoop;
|
|
Me@1
|
88
|
|
Me@1
|
89 //alloc stack locations, make stackPtr be the last addr in the locs,
|
|
Me@1
|
90 // minus room for the two parameters. Put initData at stackPtr,
|
|
Me@1
|
91 // animatingPr just above
|
|
Me@1
|
92 stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size
|
|
Me@1
|
93 stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 );
|
|
Me@1
|
94 masterPr->stackPtr = stackPtr;
|
|
Me@1
|
95 masterPr->framePtr = stackPtr;
|
|
Me@1
|
96 asm volatile("movl %0, %%esp;
|
|
Me@1
|
97 movl %1, (%%esp);
|
|
Me@1
|
98 movl %2, $0x4(%%esp);
|
|
Me@1
|
99 movl %%esp, %%ebp; " /*framePtr in ebp never used*/
|
|
Me@1
|
100 /* outputs */ :
|
|
Me@1
|
101 /* inputs */ : "g" (stackPtr), "g" (initData), "g" (animPr)
|
|
Me@1
|
102 /* clobber */ :
|
|
Me@1
|
103 );
|
|
Me@0
|
104 }
|
|
Me@0
|
105
|
|
Me@0
|
106 void
|
|
Me@1
|
107 create_sched_slots( MasterEnv *masterEnv )
|
|
Me@1
|
108 { SchedSlot *slots;
|
|
Me@0
|
109 int i;
|
|
Me@0
|
110
|
|
Me@1
|
111 slots = masterEnv->schedSlots; //TODO: make sure this is right
|
|
Me@1
|
112 for( i = 0; i < NUM_SCHED_SLOTS; i++ )
|
|
Me@0
|
113 {
|
|
Me@1
|
114 //Set state to mean "handling requests done, slot needs filling"
|
|
Me@1
|
115 slots[i].workIsDone = FALSE;
|
|
Me@1
|
116 slots[i].needsProcrAssigned = TRUE;
|
|
Me@0
|
117 }
|
|
Me@0
|
118 }
|
|
Me@0
|
119
|
|
Me@0
|
120 /*Semantic layer calls this when it want the system to start running..
|
|
Me@0
|
121 *
|
|
Me@0
|
122 *This creates the core loops, pins them to physical cores, gives them the
|
|
Me@0
|
123 * pointer to the workQ, and starts them running.
|
|
Me@0
|
124 */
|
|
Me@0
|
125 void
|
|
Me@0
|
126 VMS__start()
|
|
Me@0
|
127 { int retCode, coreIdx;
|
|
Me@0
|
128
|
|
Me@0
|
129 //TODO: still just skeleton code -- figure out right way to do this
|
|
Me@0
|
130
|
|
Me@0
|
131 //Create the PThread loops that take from work-queue, and start them
|
|
Me@0
|
132 for( coreIdx=0; coreIdx < NUM_WORKERS; coreIdx++ )
|
|
Me@0
|
133 {
|
|
Me@0
|
134 thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) );
|
|
Me@1
|
135 thdParams[coreIdx]->workQ = _VMSWorkQ;
|
|
Me@0
|
136 thdParams[coreIdx]->id = coreIdx;
|
|
Me@0
|
137
|
|
Me@0
|
138 //Now make and start thd.. the coreLoopThds entry
|
|
Me@0
|
139 // has all the info needed to later stop the thread.
|
|
Me@0
|
140 retCode =
|
|
Me@0
|
141 pthread_create( &(coreLoopThds[coreIdx]), thdAttrs, &coreLoop,
|
|
Me@0
|
142 (void *)(thdParams[coreIdx]) );
|
|
Me@0
|
143 if( retCode != 0 )
|
|
Me@0
|
144 { //error
|
|
Me@0
|
145 printf("ERROR creating coreLoop %d, code: %d\n", coreIdx, retCode);
|
|
Me@0
|
146 exit(-1);
|
|
Me@0
|
147 }
|
|
Me@0
|
148
|
|
Me@0
|
149 pinThdToCore( ); //figure out how to specify this..
|
|
Me@0
|
150
|
|
Me@0
|
151 startThd(); //look up PThread call to start the thread running, if it's
|
|
Me@0
|
152 // not automatic
|
|
Me@0
|
153 }
|
|
Me@0
|
154 }
|
|
Me@0
|
155
|
|
Me@0
|
156 /*there is a label inside this function -- save the addr of this label in
|
|
Me@0
|
157 * the callingPr struc, as the pick-up point from which to start the next
|
|
Me@0
|
158 * work-unit for that procr. If turns out have to save registers, then
|
|
Me@0
|
159 * save them in the procr struc too. Then do assembly jump to the CoreLoop's
|
|
Me@0
|
160 * "done with work-unit" label. The procr struc is in the request in the
|
|
Me@0
|
161 * slave that animated the just-ended work-unit, so all the state is saved
|
|
Me@0
|
162 * there, and will get passed along, inside the request handler, to the
|
|
Me@0
|
163 * next work-unit for that procr.
|
|
Me@0
|
164 */
|
|
Me@1
|
165 VMS__suspend_processor( VirtProcr *callingPr )
|
|
Me@1
|
166 { void *jmpPt;
|
|
Me@0
|
167
|
|
Me@1
|
168 callingPr->nextInstrPt = &&ResumePt;
|
|
Me@1
|
169
|
|
Me@1
|
170 //return ownership of the virt procr and sched slot to Master virt pr
|
|
Me@1
|
171 callingPr->schedSlot->workIsDone = TRUE;
|
|
Me@1
|
172
|
|
Me@1
|
173 jmpPt = callingPr->coreLoopStartPt;
|
|
Me@1
|
174
|
|
Me@1
|
175 //put all regs in the clobber list to make sure GCC has saved all
|
|
Me@1
|
176 // so safe to jump to core loop, where they *will* get clobbered
|
|
Me@1
|
177 asm volatile("movl %%esp, %0;
|
|
Me@1
|
178 movl %%ebp, %1;
|
|
Me@1
|
179 jmp %2 "
|
|
Me@1
|
180 /* outputs */ : "=m" (currPr->stackPtr), "=m" (currPr->framePtr)
|
|
Me@1
|
181 /* inputs */ : "g" (jmpPt)
|
|
Me@1
|
182 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi"
|
|
Me@1
|
183 );
|
|
Me@1
|
184
|
|
Me@1
|
185 ResumePt:
|
|
Me@0
|
186 return;
|
|
Me@0
|
187 }
|
|
Me@0
|
188
|
|
Me@0
|
189
|
|
Me@1
|
190 /*Create stack, then create __cdecl structure on it and put initialData and
|
|
Me@1
|
191 * pointer to the new structure instance into the parameter positions on
|
|
Me@1
|
192 * the stack
|
|
Me@1
|
193 *Then put function pointer into nextInstrPt -- the stack is setup in std
|
|
Me@1
|
194 * call structure, so jumping to function ptr is same as a GCC generated
|
|
Me@1
|
195 * function call
|
|
Me@1
|
196 *No need to save registers on old stack frame, because there's no old
|
|
Me@1
|
197 * animator state to return to --
|
|
Me@1
|
198 *
|
|
Me@1
|
199 */
|
|
Me@1
|
200 VirtProcr *
|
|
Me@1
|
201 VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
|
|
Me@1
|
202 { VirtProcr newPr;
|
|
Me@1
|
203
|
|
Me@1
|
204 newPr = malloc( sizeof(VirtProcr) );
|
|
Me@1
|
205 newPr->nextInstrPt = fnPtr;
|
|
Me@1
|
206 newPr->initialData = initialData;
|
|
Me@1
|
207 newPr->stackPtr = createNewStack();
|
|
Me@1
|
208 newPr->framePtr = newPr->stackPtr;
|
|
Me@1
|
209 put params onto stack and setup __cdecl call structure
|
|
Me@1
|
210
|
|
Me@1
|
211 return newPr;
|
|
Me@1
|
212 }
|
|
Me@1
|
213
|
|
Me@1
|
214
|
|
Me@0
|
215 /*The semantic virt procr is available in the request sent from the slave
|
|
Me@0
|
216 *
|
|
Me@0
|
217 * The request handler has to add the work-unit created to the semantic
|
|
Me@0
|
218 * virtual processor the work-unit is a section of its time-line -- does this when create the
|
|
Me@0
|
219 * work-unit -- means the procr data struc is available in the request sent
|
|
Me@0
|
220 * from the slave, from which the new work-unit is generated..
|
|
Me@0
|
221 */
|
|
Me@1
|
222 inline void
|
|
Me@1
|
223 VMS__add_request_to_slave( SlaveReqst req, VirtProcr callingPr )
|
|
Me@1
|
224 {
|
|
Me@1
|
225 req->nextRequest = callingPr->requests;
|
|
Me@1
|
226 callingPr->requests = req;
|
|
Me@0
|
227 }
|
|
Me@0
|
228
|
|
Me@0
|
229
|
|
Me@0
|
230
|