| rev |
line source |
|
seanhalle@230
|
1 /*
|
|
seanhalle@270
|
2 * Copyright 2012 OpenSourceResearchInstitute.org
|
|
seanhalle@230
|
3 *
|
|
seanhalle@230
|
4 * Licensed under BSD
|
|
seanhalle@230
|
5 */
|
|
seanhalle@230
|
6
|
|
seanhalle@230
|
7
|
|
seanhalle@230
|
8
|
|
seanhalle@230
|
9 #include <stdio.h>
|
|
seanhalle@230
|
10 #include <stddef.h>
|
|
seanhalle@230
|
11
|
|
seanhalle@260
|
12 #include "PR.h"
|
|
seanhalle@230
|
13
|
|
seanhalle@273
|
14 //========================= Local Declarations ========================
|
|
seanhalle@273
|
15 inline PRProcess *
|
|
seanhalle@273
|
16 pickAProcess( AnimSlot *slot );
|
|
seanhalle@273
|
17 inline bool32
|
|
seanhalle@273
|
18 assignWork( PRProcess *process, AnimSlot *slot );
|
|
seanhalle@230
|
19
|
|
seanhalle@273
|
20 inline void
|
|
seanhalle@273
|
21 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@273
|
22 inline void
|
|
seanhalle@273
|
23 PRHandle__EndTask( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@273
|
24 inline void
|
|
seanhalle@273
|
25 PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave );
|
|
seanhalle@273
|
26 inline void
|
|
seanhalle@273
|
27 PRHandle__EndSlave( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
28
|
|
seanhalle@273
|
29 inline void
|
|
seanhalle@273
|
30 PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv );
|
|
seanhalle@268
|
31
|
|
seanhalle@273
|
32 inline void
|
|
seanhalle@273
|
33 handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv );
|
|
seanhalle@273
|
34 inline void
|
|
seanhalle@273
|
35 handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv );
|
|
seanhalle@230
|
36
|
|
seanhalle@285
|
37 void
|
|
seanhalle@285
|
38 debug_print_req(AnimSlot *slot, PRReqst *req);
|
|
seanhalle@285
|
39
|
|
seanhalle@273
|
40 //===========================================================================
|
|
seanhalle@272
|
41
|
|
seanhalle@272
|
42 /*Note: there used to be a coreController that was another animation
|
|
seanhalle@272
|
43 * layer below both the masterVP and the slaveVPs.. in that case, the
|
|
seanhalle@272
|
44 * masterVP was a virtual processor whose processor-state was the same
|
|
seanhalle@272
|
45 * as a slaveVP's processor sate, both implemented as a SlaveVP struct.
|
|
seanhalle@272
|
46 * Have removed that, and
|
|
seanhalle@272
|
47 * changed the masterVP implementation. Instead of being a special version
|
|
seanhalle@272
|
48 * of a proto-runtime virtual processor, using the slaveVP stuct, the
|
|
seanhalle@272
|
49 * Master "virtual processor" is now implemented as a pthread pinned to
|
|
seanhalle@272
|
50 * a physical core.
|
|
seanhalle@260
|
51 */
|
|
seanhalle@260
|
52
|
|
seanhalle@272
|
53 /*This is the behavior of the Master. The physical processor switches
|
|
seanhalle@272
|
54 * between animating the master, and animating a slave. When a slave
|
|
seanhalle@272
|
55 * suspends, the PR "suspend" primitive switches the physical core over
|
|
seanhalle@272
|
56 * to animating the masterVP, which is implemented as a pinned pthread.
|
|
seanhalle@272
|
57 * This function is the behavior of that masterVP.
|
|
seanhalle@272
|
58 *This function's job is to manage processing
|
|
seanhalle@272
|
59 * requests and to trigger assignment of new work to the physical core,
|
|
seanhalle@272
|
60 * and to manage sharing the core among processes.
|
|
seanhalle@272
|
61 */
|
|
seanhalle@261
|
62 inline
|
|
seanhalle@270
|
63 bool32
|
|
seanhalle@269
|
64 masterFunction( AnimSlot *slot )
|
|
seanhalle@261
|
65 { //Scan the animation slots
|
|
seanhalle@261
|
66 int32 magicNumber;
|
|
seanhalle@261
|
67 SlaveVP *slave;
|
|
seanhalle@268
|
68 PRLangEnv *langEnv;
|
|
seanhalle@261
|
69 PRReqst *req;
|
|
seanhalle@268
|
70 PRProcess *process;
|
|
seanhalle@273
|
71 bool32 didAssignWork;
|
|
seanhalle@260
|
72
|
|
seanhalle@268
|
73 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@272
|
74 //NOTE: left over from when had a coreController & MasterVP managed
|
|
seanhalle@272
|
75 // several slots
|
|
seanhalle@268
|
76 if( slot->workIsDone )
|
|
seanhalle@268
|
77 { slot->workIsDone = FALSE;
|
|
seanhalle@268
|
78 slot->needsWorkAssigned = TRUE;
|
|
seanhalle@273
|
79
|
|
seanhalle@273
|
80 //An Idle VP has no request to handle, so skip to assign..
|
|
seanhalle@278
|
81 if( slot->slaveAssignedToSlot->typeOfVP != IdleVP &&
|
|
seanhalle@278
|
82 slot->slaveAssignedToSlot->typeOfVP != ShutdownVP)
|
|
seanhalle@273
|
83 {
|
|
seanhalle@273
|
84 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@273
|
85 MEAS__startReqHdlr;
|
|
seanhalle@261
|
86
|
|
seanhalle@261
|
87
|
|
seanhalle@273
|
88 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@273
|
89 slave = slot->slaveAssignedToSlot;
|
|
seanhalle@273
|
90 req = slave->request;
|
|
seanhalle@268
|
91
|
|
seanhalle@273
|
92 //If the requesting slave is a slot slave, and request is not
|
|
seanhalle@273
|
93 // task-end, then turn it into a free task slave & continue
|
|
seanhalle@273
|
94 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
|
|
seanhalle@273
|
95 PR_int__replace_with_new_slot_slv( slave );
|
|
seanhalle@268
|
96
|
|
seanhalle@273
|
97 //Handle task create and end first -- they're special cases..
|
|
seanhalle@273
|
98 switch( req->reqType )
|
|
seanhalle@278
|
99 {
|
|
seanhalle@278
|
100 case TaskEnd:
|
|
seanhalle@273
|
101 { //do PR handler, which calls lang's hdlr and does recycle of
|
|
seanhalle@273
|
102 // free task slave if needed -- PR handler checks for free task Slv
|
|
seanhalle@273
|
103 PRHandle__EndTask( req, slave ); break;
|
|
seanhalle@273
|
104 }
|
|
seanhalle@273
|
105 case TaskCreate:
|
|
seanhalle@273
|
106 { //Do PR's create-task handler, which calls the lang's hdlr
|
|
seanhalle@273
|
107 // PR handler checks for free task Slv
|
|
seanhalle@273
|
108 PRHandle__CreateTask( req, slave ); break;
|
|
seanhalle@273
|
109 }
|
|
seanhalle@273
|
110 case SlvCreate: PRHandle__CreateSlave( req, slave ); break;
|
|
seanhalle@273
|
111 case SlvDissipate: PRHandle__EndSlave( req, slave ); break;
|
|
seanhalle@273
|
112 case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env
|
|
seanhalle@273
|
113 case Hardware: //for future expansion
|
|
seanhalle@273
|
114 case IO: //for future expansion
|
|
seanhalle@273
|
115 case OSCall: //for future expansion
|
|
seanhalle@273
|
116 PR_int__throw_exception("Not implemented", slave, NULL); break;
|
|
seanhalle@273
|
117 case LangShutdown: PRHandle__LangShutdown( req, slave ); break;
|
|
seanhalle@273
|
118 case Language: //normal lang request
|
|
seanhalle@273
|
119 { magicNumber = req->langMagicNumber;
|
|
seanhalle@273
|
120 langEnv = PR_PI__give_lang_env_for_slave( slave, magicNumber );
|
|
seanhalle@273
|
121 (*req->handler)( req->langReq, slave, langEnv );
|
|
seanhalle@273
|
122 }
|
|
seanhalle@267
|
123 }
|
|
seanhalle@273
|
124
|
|
seanhalle@268
|
125 MEAS__endReqHdlr;
|
|
seanhalle@267
|
126 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@273
|
127 }//if not idleVP
|
|
seanhalle@278
|
128 else if( slot->slaveAssignedToSlot->typeOfVP == ShutdownVP )
|
|
seanhalle@278
|
129 { //ShutdownVP used, essentially, as a flag, to cause terminate here
|
|
seanhalle@278
|
130 PR_int__release_master_lock();
|
|
seanhalle@278
|
131 terminateCoreCtlr( slot->slaveAssignedToSlot );
|
|
seanhalle@278
|
132 }
|
|
seanhalle@268
|
133 } //if have request to be handled
|
|
seanhalle@268
|
134
|
|
seanhalle@272
|
135 //NOTE: IF statement is leftover from when master managed many slots
|
|
seanhalle@273
|
136 didAssignWork = FALSE;
|
|
seanhalle@273
|
137 if( slot->needsWorkAssigned ) //can probably remove IF, now that only one slot
|
|
seanhalle@268
|
138 {
|
|
seanhalle@268
|
139 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@272
|
140
|
|
seanhalle@268
|
141 //Pick a process to get this slot
|
|
seanhalle@268
|
142 process = pickAProcess( slot );
|
|
seanhalle@268
|
143
|
|
seanhalle@268
|
144 //Scan lang environs, looking for langEnv with ready work.
|
|
seanhalle@268
|
145 // call the Assigner for that lang Env, to get a slave for the slot
|
|
seanhalle@273
|
146 if( process != NULL )
|
|
seanhalle@273
|
147 { didAssignWork =
|
|
seanhalle@273
|
148 assignWork( process, slot );
|
|
seanhalle@273
|
149 }
|
|
seanhalle@268
|
150 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@272
|
151
|
|
seanhalle@273
|
152 if( !didAssignWork ) //if no work assigned, be sure idle slave is in slot
|
|
seanhalle@273
|
153 { slot->slaveAssignedToSlot = _PRTopEnv->idleSlv[slot->coreSlotIsOn][0];
|
|
seanhalle@273
|
154 }
|
|
seanhalle@273
|
155 // fixme; //make into a loop that tries more processes if fails to assign
|
|
seanhalle@268
|
156 }//if slot needs slave assigned
|
|
seanhalle@270
|
157
|
|
seanhalle@273
|
158 return didAssignWork;
|
|
seanhalle@261
|
159 }
|
|
seanhalle@260
|
160
|
|
seanhalle@268
|
161 /*When several processes exist, use some pattern for picking one to give
|
|
seanhalle@268
|
162 * the animation slot to.
|
|
seanhalle@268
|
163 *First, it has to be a process that has work available.
|
|
seanhalle@268
|
164 *For now, just do a round-robin
|
|
seanhalle@261
|
165 */
|
|
seanhalle@268
|
166 inline
|
|
seanhalle@268
|
167 PRProcess *
|
|
seanhalle@268
|
168 pickAProcess( AnimSlot *slot )
|
|
seanhalle@268
|
169 { int32 idx;
|
|
seanhalle@268
|
170 PRProcess *process;
|
|
seanhalle@268
|
171
|
|
seanhalle@268
|
172 for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++)
|
|
seanhalle@268
|
173 {
|
|
seanhalle@268
|
174 process = _PRTopEnv->processes[ idx ];
|
|
seanhalle@268
|
175 if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
176 { _PRTopEnv->currProcessIdx = idx;
|
|
seanhalle@268
|
177 return process;
|
|
seanhalle@268
|
178 }
|
|
seanhalle@261
|
179 }
|
|
seanhalle@268
|
180 for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++)
|
|
seanhalle@268
|
181 {
|
|
seanhalle@268
|
182 process = _PRTopEnv->processes[ idx ];
|
|
seanhalle@268
|
183 if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
184 { _PRTopEnv->currProcessIdx = idx;
|
|
seanhalle@268
|
185 return process;
|
|
seanhalle@268
|
186 }
|
|
seanhalle@268
|
187 }
|
|
seanhalle@268
|
188 //none found
|
|
seanhalle@268
|
189 return NULL;
|
|
seanhalle@260
|
190 }
|
|
seanhalle@260
|
191
|
|
seanhalle@261
|
192 /*This does:
|
|
seanhalle@268
|
193 * 1) searches the language environments for one with work ready
|
|
seanhalle@261
|
194 * if finds one, asks its assigner to return work
|
|
seanhalle@261
|
195 * 2) checks what kind of work: new task, resuming task, resuming slave
|
|
seanhalle@261
|
196 * if new task, gets the slot slave and assigns task to it and returns slave
|
|
seanhalle@261
|
197 * else, gets the slave attached to the metaTask and returns that.
|
|
seanhalle@261
|
198 * 3) if no work found, then prune former task slaves waiting to be recycled.
|
|
seanhalle@261
|
199 * If no work and no slaves to prune, check for shutdown conditions.
|
|
seanhalle@261
|
200 *
|
|
seanhalle@268
|
201 * language env keeps its own work in its own structures, and has its own
|
|
seanhalle@261
|
202 * assigner. It chooses
|
|
seanhalle@261
|
203 * However, include a switch that switches-in an override assigner, which
|
|
seanhalle@268
|
204 * sees all the work in all the language env's. This is most likely
|
|
seanhalle@261
|
205 * generated by static tools and included in the executable. That means it
|
|
seanhalle@261
|
206 * has to be called via a registered pointer from here. The idea is that
|
|
seanhalle@261
|
207 * the static tools know which languages are grouped together.. and the
|
|
seanhalle@261
|
208 * override enables them to generate a custom assigner that uses info from
|
|
seanhalle@261
|
209 * all the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@261
|
210 * but am making it possible.
|
|
seanhalle@260
|
211 */
|
|
seanhalle@268
|
212 inline
|
|
seanhalle@270
|
213 bool32
|
|
seanhalle@261
|
214 assignWork( PRProcess *process, AnimSlot *slot )
|
|
seanhalle@272
|
215 { int32 coreNum;
|
|
seanhalle@260
|
216
|
|
seanhalle@261
|
217 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@260
|
218
|
|
seanhalle@267
|
219 if( process->overrideAssigner != NULL )
|
|
seanhalle@268
|
220 { if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
221 { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot
|
|
seanhalle@268
|
222 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@261
|
223 }
|
|
seanhalle@268
|
224 else
|
|
seanhalle@261
|
225 goto NoWork;
|
|
seanhalle@261
|
226 }
|
|
seanhalle@261
|
227
|
|
seanhalle@268
|
228 //If here, then no override assigner, so search language envs for work
|
|
seanhalle@273
|
229 int32 envIdx, numEnvs; PRLangEnv **protoLangEnvsList, *protoLangEnv;
|
|
seanhalle@273
|
230 protoLangEnvsList = process->protoLangEnvsList;
|
|
seanhalle@268
|
231 numEnvs = process->numLangEnvs;
|
|
seanhalle@268
|
232 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array
|
|
seanhalle@273
|
233 { protoLangEnv = protoLangEnvsList[envIdx];
|
|
seanhalle@273
|
234 if( protoLangEnv->numReadyWork > 0 )
|
|
seanhalle@272
|
235 { bool32
|
|
seanhalle@272
|
236 didAssignWork =
|
|
seanhalle@273
|
237 (*protoLangEnv->workAssigner)( PR_int__give_lang_env(protoLangEnv), slot ); //assigner calls PR to put slave/task into slot
|
|
seanhalle@272
|
238
|
|
seanhalle@272
|
239 if(didAssignWork)
|
|
seanhalle@273
|
240 { protoLangEnv->numReadyWork -= 1;
|
|
seanhalle@273
|
241 if( protoLangEnv->numReadyWork == 0 )
|
|
seanhalle@272
|
242 { process->numEnvsWithWork -= 1;
|
|
seanhalle@272
|
243 }
|
|
seanhalle@272
|
244 goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work
|
|
seanhalle@272
|
245 }
|
|
seanhalle@272
|
246 else
|
|
seanhalle@272
|
247 goto NoWork; //quit for-loop, cause found work
|
|
seanhalle@272
|
248
|
|
seanhalle@268
|
249 //NOTE: bad search alg -- should start where left off, then wrap around
|
|
seanhalle@260
|
250 }
|
|
seanhalle@260
|
251 }
|
|
seanhalle@268
|
252 //If reach here, then have searched all langEnv's & none have work..
|
|
seanhalle@260
|
253
|
|
seanhalle@268
|
254 NoWork: //No work, if end up here..
|
|
seanhalle@260
|
255 {
|
|
seanhalle@260
|
256 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@272
|
257 returnSlv = process->idleSlv[coreNum][0]; //only one slot now, so [0]
|
|
seanhalle@260
|
258
|
|
seanhalle@260
|
259 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@260
|
260 // never go there
|
|
seanhalle@261
|
261 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@260
|
262 Unit newU;
|
|
seanhalle@268
|
263 newU.vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
264 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
265 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@260
|
266
|
|
seanhalle@261
|
267 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@260
|
268 { Dependency newD; // to this one
|
|
seanhalle@268
|
269 newD.from_vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
270 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@268
|
271 newD.to_vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
272 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
273 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@260
|
274 }
|
|
seanhalle@268
|
275 #endif
|
|
seanhalle@268
|
276 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@269
|
277 return FALSE;
|
|
seanhalle@260
|
278 }
|
|
seanhalle@268
|
279
|
|
seanhalle@268
|
280 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@268
|
281 {
|
|
seanhalle@268
|
282 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@269
|
283 return TRUE;
|
|
seanhalle@260
|
284 }
|
|
seanhalle@260
|
285 }
|
|
seanhalle@260
|
286
|
|
seanhalle@260
|
287
|
|
seanhalle@273
|
288 //=================================
|
|
seanhalle@273
|
289 //===
|
|
seanhalle@273
|
290 //=
|
|
seanhalle@273
|
291 /*Create task is a special form, that has PR behavior in addition to plugin
|
|
seanhalle@273
|
292 * behavior. Master calls this first, and it then calls the plugin's
|
|
seanhalle@273
|
293 * create task handler.
|
|
seanhalle@273
|
294 *
|
|
seanhalle@273
|
295 *Note: the requesting slave must be either generic slave or free task slave
|
|
seanhalle@273
|
296 */
|
|
seanhalle@273
|
297 inline
|
|
seanhalle@273
|
298 void
|
|
seanhalle@273
|
299 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@273
|
300 { PRMetaTask *protoMetaTask;
|
|
seanhalle@273
|
301 PRProcess *process;
|
|
seanhalle@273
|
302 PRLangEnv *protoLangEnv;
|
|
seanhalle@273
|
303 void *task;
|
|
seanhalle@273
|
304
|
|
seanhalle@273
|
305 process = slave->processSlaveIsIn;
|
|
seanhalle@273
|
306
|
|
seanhalle@273
|
307 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave,
|
|
seanhalle@273
|
308 req->langMagicNumber );
|
|
seanhalle@273
|
309
|
|
seanhalle@273
|
310 //Do the langlet's create-task handler, which keeps the task
|
|
seanhalle@273
|
311 // inside the langlet's lang env, but returns the langMetaTask
|
|
seanhalle@273
|
312 // so that PR can then put stuff into the prolog
|
|
seanhalle@273
|
313 //typedef void * (*CreateHandler)( void *, SlaveVP *, void * ); //req, slv, langEnv
|
|
seanhalle@273
|
314 //
|
|
seanhalle@273
|
315 task =
|
|
seanhalle@273
|
316 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@273
|
317 protoMetaTask = PR_int__give_prolog_of_lang_meta_task( task );
|
|
seanhalle@273
|
318 protoMetaTask->ID = req->ID; //may be NULL
|
|
seanhalle@273
|
319 protoMetaTask->topLevelFn = req->topLevelFn;
|
|
seanhalle@273
|
320 protoMetaTask->initData = req->initData;
|
|
seanhalle@273
|
321 protoMetaTask->processTaskIsIn = process;
|
|
seanhalle@273
|
322
|
|
seanhalle@273
|
323 process->numLiveTasks += 1;
|
|
seanhalle@273
|
324 protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead
|
|
seanhalle@273
|
325
|
|
seanhalle@273
|
326 return;
|
|
seanhalle@273
|
327 }
|
|
seanhalle@273
|
328
|
|
seanhalle@273
|
329 /*When a task ends, have two scenarios: 1) task ran to completion, or 2) task
|
|
seanhalle@273
|
330 * has been suspended at some point in its code.
|
|
seanhalle@273
|
331 *For 1, just decr count of live tasks (and check for end condition) -- the
|
|
seanhalle@273
|
332 * master loop will decide what goes into the slot freed up by this task end,
|
|
seanhalle@273
|
333 * so, here, don't worry about assigning a new task to the slot slave.
|
|
seanhalle@273
|
334 *For 2, the task's slot slave has been converted to a free task slave, which
|
|
seanhalle@273
|
335 * now has nothing more to do, so send it to the recycle Q (which includes
|
|
seanhalle@273
|
336 * freeing all the langData and meta task structs alloc'd for it). Then
|
|
seanhalle@273
|
337 * decrement the live task count and check end condition.
|
|
seanhalle@273
|
338 *
|
|
seanhalle@273
|
339 *PR has to update count of live tasks, and check end of process condition.
|
|
seanhalle@273
|
340 * The "main" can invoke constructs that wait for a process to end, so when
|
|
seanhalle@273
|
341 * end detected, have to resume what's waiting..
|
|
seanhalle@273
|
342 *Thing is, that wait involves the main OS thread. That means
|
|
seanhalle@273
|
343 * PR internals have to do OS thread signaling. Want to do that in the
|
|
seanhalle@273
|
344 * core controller, which has the original stack of an OS thread. So the
|
|
seanhalle@273
|
345 * end process handling happens in the core controller.
|
|
seanhalle@273
|
346 *
|
|
seanhalle@273
|
347 *So here, when detect process end, signal to the core controller, which will
|
|
seanhalle@273
|
348 * then do the condition variable notify to the OS thread that's waiting.
|
|
seanhalle@273
|
349 *
|
|
seanhalle@273
|
350 *Note: slave may be either a slot slave or a free task slave.
|
|
seanhalle@273
|
351 */
|
|
seanhalle@273
|
352 inline
|
|
seanhalle@273
|
353 void
|
|
seanhalle@273
|
354 PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@273
|
355 { void *langEnv;
|
|
seanhalle@273
|
356 PRLangEnv *protoLangEnv;
|
|
seanhalle@273
|
357 PRProcess *process;
|
|
seanhalle@273
|
358 void *langMetaTask;
|
|
seanhalle@273
|
359
|
|
seanhalle@273
|
360 process = requestingSlv->processSlaveIsIn;
|
|
seanhalle@273
|
361 langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req
|
|
seanhalle@273
|
362 protoLangEnv = PR_int__give_proto_lang_env( langEnv );
|
|
seanhalle@273
|
363
|
|
seanhalle@273
|
364 langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber);
|
|
seanhalle@273
|
365
|
|
seanhalle@273
|
366 //Do the langlet's request handler
|
|
seanhalle@273
|
367 //Want to keep PR structs hidden from plugin, so extract langReq..
|
|
seanhalle@273
|
368 //This is supposed to free any langlet-malloc'd mem, including meta task
|
|
seanhalle@273
|
369 (*req->handler)( req->langReq, requestingSlv, langEnv );
|
|
seanhalle@273
|
370
|
|
seanhalle@273
|
371 protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead
|
|
seanhalle@273
|
372 if( protoLangEnv->numLiveWork == 0 &&
|
|
seanhalle@273
|
373 numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 )
|
|
seanhalle@273
|
374 { SlaveVP *
|
|
seanhalle@273
|
375 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
|
|
seanhalle@273
|
376 //can't resume into langlet that just ended its last work!
|
|
seanhalle@273
|
377 // and don't have env that the waiter was created in, so resume
|
|
seanhalle@273
|
378 // into PRServ env..
|
|
seanhalle@273
|
379 void *
|
|
seanhalle@273
|
380 resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER );
|
|
seanhalle@273
|
381 while( waitingSlave != NULL )
|
|
seanhalle@273
|
382 { //resume a slave that was waiting for work in this env to finish
|
|
seanhalle@273
|
383 PR_PI__make_slave_ready( waitingSlave, resumeEnv );
|
|
seanhalle@273
|
384 //get next waiting slave, repeat..
|
|
seanhalle@273
|
385 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
|
|
seanhalle@273
|
386 }
|
|
seanhalle@273
|
387 }
|
|
seanhalle@273
|
388
|
|
seanhalle@273
|
389
|
|
seanhalle@273
|
390 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
|
|
seanhalle@273
|
391 if( requestingSlv->typeOfVP == FreeTaskSlv )
|
|
seanhalle@273
|
392 PR_int__recycle_slaveVP( requestingSlv ); //Doesn't decr num live slaves
|
|
seanhalle@273
|
393
|
|
seanhalle@273
|
394 process->numLiveTasks -= 1;
|
|
seanhalle@273
|
395 //NOTE: end-task is unrelated to work available (just in case wondering)
|
|
seanhalle@273
|
396
|
|
seanhalle@273
|
397 //check End Of Process Condition
|
|
seanhalle@273
|
398 if( process->numLiveTasks == 0 &&
|
|
seanhalle@273
|
399 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@273
|
400 { //Tell the core controller to do wakeup of any waiting OS thread
|
|
seanhalle@273
|
401 PR_SS__end_process_normally( process );
|
|
seanhalle@273
|
402 }
|
|
seanhalle@273
|
403 }
|
|
seanhalle@273
|
404
|
|
seanhalle@273
|
405
|
|
seanhalle@268
|
406
|
|
seanhalle@268
|
407 /*This is first thing called when creating a slave.. it hands off to the
|
|
seanhalle@268
|
408 * langlet's creator, then adds updates of its own..
|
|
seanhalle@268
|
409 *
|
|
seanhalle@268
|
410 *There's a question of things like lang data, meta tasks, and such..
|
|
seanhalle@268
|
411 *In creator, only PR related things happen, and things for the langlet whose
|
|
seanhalle@261
|
412 * creator construct was used.
|
|
seanhalle@268
|
413 *
|
|
seanhalle@268
|
414 *Other langlets still get a chance to create langData -- but by registering a
|
|
seanhalle@268
|
415 * "createLangData" handler in the langEnv. When a construct of the langlet
|
|
seanhalle@268
|
416 * calls "PR__give_lang_data()", if there is no langData for that langlet,
|
|
seanhalle@268
|
417 * the PR will call the creator in the langlet's langEnv, place whatever it
|
|
seanhalle@268
|
418 * makes as the langData in that slave for that langlet, and return that langData
|
|
seanhalle@261
|
419 *
|
|
seanhalle@261
|
420 *So, as far as counting things, a langlet is only allowed to count creation
|
|
seanhalle@261
|
421 * of slaves it creates itself.. may have to change this later.. add a way for
|
|
seanhalle@261
|
422 * langlet to register a trigger Fn called each time a slave gets created..
|
|
seanhalle@261
|
423 * need more experience with what langlets will do at create time.. think Cilk
|
|
seanhalle@261
|
424 * has interesting create behavior.. not sure how that will differ in light
|
|
seanhalle@261
|
425 * of true tasks and langlet approach. Look at it after all done and start
|
|
seanhalle@261
|
426 * modifying the langs to be langlets..
|
|
seanhalle@261
|
427 *
|
|
seanhalle@261
|
428 *PR itself needs to create the slave, then update numLiveSlaves in process,
|
|
seanhalle@261
|
429 * copy processID from requestor to newly created
|
|
seanhalle@261
|
430 */
|
|
seanhalle@268
|
431 inline
|
|
seanhalle@268
|
432 void
|
|
seanhalle@272
|
433 PRHandle__CreateSlave( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@268
|
434 { SlaveVP *newSlv;
|
|
seanhalle@261
|
435 PRProcess *process;
|
|
seanhalle@268
|
436 PRLangEnv *protoLangEnv;
|
|
seanhalle@261
|
437
|
|
seanhalle@268
|
438 process = slave->processSlaveIsIn;
|
|
seanhalle@273
|
439 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, req->langMagicNumber );
|
|
seanhalle@272
|
440
|
|
seanhalle@272
|
441 //create handler, or a future request handler will call PR_PI__make_slave_ready
|
|
seanhalle@272
|
442 // which will in turn handle updating which langlets and which processes have
|
|
seanhalle@272
|
443 // work available.
|
|
seanhalle@272
|
444 //NOTE: create slv has diff prototype than standard reqst hdlr
|
|
seanhalle@268
|
445 newSlv =
|
|
seanhalle@268
|
446 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv));
|
|
seanhalle@268
|
447
|
|
seanhalle@261
|
448 newSlv->typeOfVP = GenericSlv;
|
|
seanhalle@261
|
449 newSlv->processSlaveIsIn = process;
|
|
seanhalle@268
|
450 newSlv->ID = req->ID;
|
|
seanhalle@272
|
451 process->numLiveGenericSlvs += 1; //not same as work ready!
|
|
seanhalle@273
|
452 protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead
|
|
seanhalle@260
|
453 }
|
|
seanhalle@260
|
454
|
|
seanhalle@268
|
455 /*The dissipate handler has to, update the number of slaves of the type, within
|
|
seanhalle@261
|
456 * the process, and call the langlet handler linked into the request,
|
|
seanhalle@261
|
457 * and after that returns, then call the PR function that frees the slave state
|
|
seanhalle@261
|
458 * (or recycles the slave).
|
|
seanhalle@261
|
459 *
|
|
seanhalle@261
|
460 *The PR function that frees the slave state has to also free all of the
|
|
seanhalle@268
|
461 * langData in the slave.. or else reset all of the langDatas.. by, say, marking
|
|
seanhalle@268
|
462 * them, then in PR__give_langData( magicNum ) call the langlet registered
|
|
seanhalle@268
|
463 * "resetLangData" Fn.
|
|
seanhalle@261
|
464 */
|
|
seanhalle@268
|
465 inline
|
|
seanhalle@268
|
466 void
|
|
seanhalle@272
|
467 PRHandle__EndSlave( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@261
|
468 { PRProcess *process;
|
|
seanhalle@268
|
469 PRLangEnv *protoLangEnv;
|
|
seanhalle@261
|
470
|
|
seanhalle@261
|
471 process = slave->processSlaveIsIn;
|
|
seanhalle@261
|
472
|
|
seanhalle@261
|
473 //do the language's dissipate handler
|
|
seanhalle@273
|
474 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, slave->request->langMagicNumber );
|
|
seanhalle@268
|
475
|
|
seanhalle@268
|
476 if(req->handler != NULL)
|
|
seanhalle@268
|
477 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@261
|
478
|
|
seanhalle@273
|
479 protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead
|
|
seanhalle@273
|
480 if( protoLangEnv->numLiveWork == 0 &&
|
|
seanhalle@273
|
481 numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 )
|
|
seanhalle@273
|
482 { SlaveVP *
|
|
seanhalle@273
|
483 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
|
|
seanhalle@273
|
484 //can't resume into langlet that just ended its last work!
|
|
seanhalle@273
|
485 // and don't have env that the waiter was created in, so resume
|
|
seanhalle@273
|
486 // into PRServ env..
|
|
seanhalle@273
|
487 void *
|
|
seanhalle@273
|
488 resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER );
|
|
seanhalle@273
|
489 while( waitingSlave != NULL )
|
|
seanhalle@273
|
490 { //resume a slave that was waiting for work in this env to finish
|
|
seanhalle@273
|
491 PR_PI__make_slave_ready( waitingSlave, resumeEnv );
|
|
seanhalle@273
|
492 //get next waiting slave, repeat..
|
|
seanhalle@273
|
493 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
|
|
seanhalle@273
|
494 }
|
|
seanhalle@273
|
495 }
|
|
seanhalle@273
|
496
|
|
seanhalle@272
|
497 process->numLiveGenericSlvs -= 1;
|
|
seanhalle@273
|
498 PR_int__recycle_slaveVP( slave );
|
|
seanhalle@272
|
499 //NOTE: dissipate is unrelated to work available (just in case wondering)
|
|
seanhalle@272
|
500
|
|
seanhalle@261
|
501 //check End Of Process Condition
|
|
seanhalle@261
|
502 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
503 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@273
|
504 PR_SS__end_process_normally( process );
|
|
seanhalle@261
|
505 }
|
|
seanhalle@261
|
506
|
|
seanhalle@273
|
507 //=======================
|
|
seanhalle@273
|
508 //===
|
|
seanhalle@273
|
509 //=
|
|
seanhalle@273
|
510 /*Langlet shutdown triggers this, which calls the registered shutdown
|
|
seanhalle@273
|
511 * handler for the langlet, and removes the lang's env from the process
|
|
seanhalle@261
|
512 */
|
|
seanhalle@268
|
513 inline
|
|
seanhalle@268
|
514 void
|
|
seanhalle@273
|
515 PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@273
|
516 { void *langEnv;
|
|
seanhalle@273
|
517 PRLangEnv *protoLangEnv;
|
|
seanhalle@273
|
518 PRProcess *process;
|
|
seanhalle@268
|
519
|
|
seanhalle@273
|
520 process = requestingSlv->processSlaveIsIn;
|
|
seanhalle@273
|
521 protoLangEnv = PR_int__give_proto_lang_env_from_process( process, req->langMagicNumber );
|
|
seanhalle@273
|
522 langEnv = PR_int__give_lang_env( protoLangEnv );
|
|
seanhalle@268
|
523
|
|
seanhalle@273
|
524 //call the langlet's registered handler
|
|
seanhalle@273
|
525 (*protoLangEnv->shutdownHdlr)( langEnv );
|
|
seanhalle@267
|
526
|
|
seanhalle@273
|
527 PR_int__remove_lang_env_from_process_and_free( langEnv ); //removes from process and frees
|
|
seanhalle@276
|
528
|
|
seanhalle@276
|
529 PR_PI__resume_slave_in_PRServ( requestingSlv );
|
|
seanhalle@261
|
530 }
|
|
seanhalle@261
|
531
|
|
seanhalle@272
|
532
|
|
seanhalle@272
|
533 /*This is for OS requests and PR infrastructure requests, which are not
|
|
seanhalle@272
|
534 * part of the PRServ language -- this is for things that have to be in the
|
|
seanhalle@272
|
535 * infrastructure of PR itself, such as I/O requests, which have to go through
|
|
seanhalle@272
|
536 * pthreads inside the core controller..
|
|
seanhalle@272
|
537 *
|
|
seanhalle@272
|
538 *As of Jan 2013, doesn't do much of anything..
|
|
seanhalle@272
|
539 */
|
|
seanhalle@272
|
540 void inline
|
|
seanhalle@272
|
541 PRHandle__ServiceReq( SlaveVP *requestingSlv )
|
|
seanhalle@273
|
542 { PRReqst *req;
|
|
seanhalle@273
|
543 PRServiceReq *langReq;
|
|
seanhalle@273
|
544 PRLangEnv *protoLangEnv;
|
|
seanhalle@273
|
545 int32 magicNumber;
|
|
seanhalle@272
|
546
|
|
seanhalle@272
|
547
|
|
seanhalle@272
|
548 req = requestingSlv->request;
|
|
seanhalle@272
|
549
|
|
seanhalle@272
|
550 magicNumber = req->langMagicNumber;
|
|
seanhalle@273
|
551 protoLangEnv = PR_int__give_proto_lang_env_for_slave( requestingSlv, magicNumber );
|
|
seanhalle@272
|
552
|
|
seanhalle@272
|
553 langReq = PR_PI__take_lang_reqst_from(req);
|
|
seanhalle@272
|
554 if( langReq == NULL ) return;
|
|
seanhalle@272
|
555 switch( langReq->reqType ) //lang handlers are all in other file
|
|
seanhalle@272
|
556 {
|
|
seanhalle@273
|
557 case make_probe: handleMakeProbe( langReq, protoLangEnv );
|
|
seanhalle@272
|
558 break;
|
|
seanhalle@273
|
559 case throw_excp: handleThrowException( langReq, protoLangEnv );
|
|
seanhalle@272
|
560 break;
|
|
seanhalle@272
|
561 }
|
|
seanhalle@272
|
562 }
|
|
seanhalle@273
|
563
|
|
seanhalle@273
|
564
|
|
seanhalle@273
|
565 /*These handlers are special -- they don't belong to a language, because they
|
|
seanhalle@273
|
566 * deal with things internal to PR, so put them here..
|
|
seanhalle@273
|
567 */
|
|
seanhalle@273
|
568 inline
|
|
seanhalle@273
|
569 void
|
|
seanhalle@273
|
570 handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv )
|
|
seanhalle@273
|
571 { IntervalProbe *newProbe;
|
|
seanhalle@273
|
572
|
|
seanhalle@273
|
573 newProbe = PR_int__malloc( sizeof(IntervalProbe) );
|
|
seanhalle@273
|
574 newProbe->nameStr = PR_int__strDup( langReq->nameStr );
|
|
seanhalle@273
|
575 newProbe->hist = NULL;
|
|
seanhalle@273
|
576 newProbe->schedChoiceWasRecorded = FALSE;
|
|
seanhalle@273
|
577
|
|
seanhalle@273
|
578 //This runs in masterVP, so no race-condition worries
|
|
seanhalle@273
|
579 //BUG: move to process
|
|
seanhalle@273
|
580 newProbe->probeID =
|
|
seanhalle@273
|
581 addToDynArray( newProbe, _PRTopEnv->dynIntervalProbesInfo );
|
|
seanhalle@273
|
582
|
|
seanhalle@273
|
583 langReq->requestingSlv->dataRetFromReq = newProbe;
|
|
seanhalle@273
|
584
|
|
seanhalle@273
|
585 (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@273
|
586 }
|
|
seanhalle@273
|
587
|
|
seanhalle@273
|
588 inline
|
|
seanhalle@273
|
589 void
|
|
seanhalle@273
|
590 handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv )
|
|
seanhalle@273
|
591 {
|
|
seanhalle@273
|
592 PR_int__throw_exception( langReq->msgStr, langReq->requestingSlv, langReq->exceptionData );
|
|
seanhalle@273
|
593
|
|
seanhalle@273
|
594 (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@273
|
595 }
|
|
seanhalle@273
|
596
|
|
seanhalle@285
|
597 void
|
|
seanhalle@285
|
598 debug_print_req(AnimSlot *slot, PRReqst *req)
|
|
seanhalle@285
|
599 {
|
|
seanhalle@285
|
600 if(dbgMaster)
|
|
seanhalle@285
|
601 { printf("top handle request: %d | reqType: ", slot->coreSlotIsOn );
|
|
seanhalle@285
|
602 switch(req->reqType)
|
|
seanhalle@285
|
603 { case TaskCreate: printf("TaskCreate \n"); break;
|
|
seanhalle@285
|
604 case TaskEnd: printf("TaskEnd \n"); break;
|
|
seanhalle@285
|
605 case SlvCreate: printf("SlvCreate \n"); break;
|
|
seanhalle@285
|
606 case SlvDissipate: printf("SlvDissipate \n"); break;
|
|
seanhalle@285
|
607 case Language: printf("Language \n"); break;
|
|
seanhalle@285
|
608 case Service: printf("Service \n"); break;
|
|
seanhalle@285
|
609 case Hardware: printf("Hardware \n"); break;
|
|
seanhalle@285
|
610 case IO: printf("IO \n"); break;
|
|
seanhalle@285
|
611 case OSCall: printf("OSCall \n"); break;
|
|
seanhalle@285
|
612 case LangShutdown: printf("LangShutdown \n"); break;
|
|
seanhalle@285
|
613 case ProcessEnd: printf("ProcessEnd \n"); break;
|
|
seanhalle@285
|
614 case PRShutdown: printf("PRShutdown \n"); break;
|
|
seanhalle@285
|
615 }
|
|
seanhalle@285
|
616 fflush(stdin);
|
|
seanhalle@285
|
617 }
|
|
seanhalle@285
|
618 }
|
|
seanhalle@285
|
619
|
|
seanhalle@285
|
620
|