view VMS.c @ 5:6c518bda83fe

About to chg to win thds -- good except for that
author Me
date Mon, 31 May 2010 19:15:14 -0700
parents a5fe730dfc2e
children 9a1b7de19e39
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 work-unit into the work-queue
18 * 2) Semantic layer then does its own init, which creates the initial
19 * work-units inside the semantic layer, ready to schedule them 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 fully isolated from the VMS internasl by
27 * making the semantic layer setup into a state that it's ready with its
28 * initial work-units, ready to schedule them to slaves when the masterLoop
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
31 * them into the workQ itself, breaking the isolation completely.
32 *
33 *
34 *The semantic layer creates the initial work-unit(s), and adds its
35 * own environment data to masterEnv, and fills in the pointers to
36 * the requestHandler and slaveScheduler plug-in functions
37 *
38 *This allocates VMS data structures, populates the master VMSProc,
39 * and master environment, and returns the master environment to the semantic
40 * layer.
41 */
42 //Global vars are all inside VMS.h
43 MasterEnv *
44 VMS__init( )
45 { MasterEnv *masterEnv;
46 QueueStruc *workQ;
48 //Make the central work-queue
49 _VMSWorkQ = makeQ();
50 workQ = _VMSWorkQ;
52 _VMSMasterEnv = malloc( sizeof(MasterEnv) );
53 masterEnv = _VMSMasterEnv;
55 create_master( masterEnv );
57 create_sched_slots( masterEnv );
59 masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //never checked
60 masterEnv->schedSlots[0]->workIsDone = FALSE; //never checked
61 masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr;
63 //First core loop to start up gets this, which will schedule seed Pr
64 //TODO: debug: check address of masterVirtPr
65 writeQ( &(masterEnv->masterVirtPr), workQ );
66 }
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;
83 //TODO: debug this to be sure got addr of struct in masterEnv correctly
84 masterPr = &(masterEnv->masterVirtPr);
85 masterPr->initialData = masterEnv;
87 masterPr->nextInstrPt = &masterLoop;
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 }
106 void
107 create_sched_slots( MasterEnv *masterEnv )
108 { SchedSlot *slots;
109 int i;
111 slots = masterEnv->schedSlots; //TODO: make sure this is right
112 for( i = 0; i < NUM_SCHED_SLOTS; i++ )
113 {
114 //Set state to mean "handling requests done, slot needs filling"
115 slots[i].workIsDone = FALSE;
116 slots[i].needsProcrAssigned = TRUE;
117 }
118 }
120 /*Semantic layer calls this when it want the system to start running..
121 *
122 *This creates the core loops, pins them to physical cores, gives them the
123 * pointer to the workQ, and starts them running.
124 */
125 void
126 VMS__start()
127 { int retCode, coreIdx;
129 //TODO: still just skeleton code -- figure out right way to do this
131 //Create the PThread loops that take from work-queue, and start them
132 for( coreIdx=0; coreIdx < NUM_WORKERS; coreIdx++ )
133 {
134 thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) );
135 thdParams[coreIdx]->workQ = _VMSWorkQ;
136 thdParams[coreIdx]->id = coreIdx;
138 //Now make and start thd.. the coreLoopThds entry
139 // has all the info needed to later stop the thread.
140 retCode =
141 pthread_create( &(coreLoopThds[coreIdx]), thdAttrs, &coreLoop,
142 (void *)(thdParams[coreIdx]) );
143 if( retCode != 0 )
144 { //error
145 printf("ERROR creating coreLoop %d, code: %d\n", coreIdx, retCode);
146 exit(-1);
147 }
149 pinThdToCore( ); //figure out how to specify this..
151 startThd(); //look up PThread call to start the thread running, if it's
152 // not automatic
153 }
154 }
156 /*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
158 * work-unit for that procr. If turns out have to save registers, then
159 * save them in the procr struc too. Then do assembly jump to the CoreLoop's
160 * "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
162 * there, and will get passed along, inside the request handler, to the
163 * next work-unit for that procr.
164 */
165 VMS__suspend_processor( VirtProcr *callingPr )
166 { void *jmpPt;
168 callingPr->nextInstrPt = &&ResumePt;
170 //return ownership of the virt procr and sched slot to Master virt pr
171 callingPr->schedSlot->workIsDone = TRUE;
173 jmpPt = callingPr->coreLoopStartPt;
175 //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
177 asm volatile("movl %%esp, %0;
178 movl %%ebp, %1;
179 jmp %2 "
180 /* outputs */ : "=m" (currPr->stackPtr), "=m" (currPr->framePtr)
181 /* inputs */ : "g" (jmpPt)
182 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi"
183 );
185 ResumePt:
186 return;
187 }
190 /*Create stack, then create __cdecl structure on it and put initialData and
191 * pointer to the new structure instance into the parameter positions on
192 * the stack
193 *Then put function pointer into nextInstrPt -- the stack is setup in std
194 * call structure, so jumping to function ptr is same as a GCC generated
195 * function call
196 *No need to save registers on old stack frame, because there's no old
197 * animator state to return to --
198 *
199 */
200 VirtProcr *
201 VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
202 { VirtProcr newPr;
204 newPr = malloc( sizeof(VirtProcr) );
205 newPr->nextInstrPt = fnPtr;
206 newPr->initialData = initialData;
207 newPr->stackPtr = createNewStack();
208 newPr->framePtr = newPr->stackPtr;
209 put params onto stack and setup __cdecl call structure
211 return newPr;
212 }
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 }