comparison VMS.c @ 8:9a1b7de19e39

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