| rev |
line source |
|
seanhalle@230
|
1 /*
|
|
seanhalle@268
|
2 * Copyright 2010 OpenSourceResearchInstitute
|
|
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@261
|
13 #include "VSs_impl/VSs.h"
|
|
seanhalle@230
|
14
|
|
seanhalle@268
|
15 /*
|
|
seanhalle@268
|
16 void PRHandle_CreateTask_SL(SlaveVP *slave);
|
|
seanhalle@230
|
17
|
|
seanhalle@268
|
18 void PRHandle_CreateSlave_SL(SlaveVP *slave);
|
|
seanhalle@268
|
19 void PRHandle_Dissipate_SL(SlaveVP *slave);
|
|
seanhalle@268
|
20 void PR_int__handle_PRServiceReq_SL(SlaveVP *slave);
|
|
seanhalle@268
|
21 */
|
|
seanhalle@268
|
22 inline void PRHandle_CreateTask( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
23 inline void PRHandle_EndTask( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
24 inline void PRHandle_CreateSlave(PRReqst *req, SlaveVP *slave );
|
|
seanhalle@269
|
25 void PRHandle_EndSlave( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
26
|
|
seanhalle@268
|
27
|
|
seanhalle@268
|
28 //inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot );
|
|
seanhalle@269
|
29 inline void masterFunction( AnimSlot *slot );
|
|
seanhalle@268
|
30 inline PRProcess * pickAProcess( AnimSlot *slot );
|
|
seanhalle@268
|
31 inline SlaveVP * assignWork( PRProcess *process, AnimSlot *slot );
|
|
seanhalle@230
|
32
|
|
seanhalle@230
|
33 /*The animationMaster embodies most of the animator of the language. The
|
|
seanhalle@230
|
34 * animator is what emodies the behavior of language constructs.
|
|
seanhalle@230
|
35 * As such, it is the animationMaster, in combination with the plugin
|
|
seanhalle@230
|
36 * functions, that make the language constructs do their behavior.
|
|
seanhalle@230
|
37 *
|
|
seanhalle@230
|
38 *Within the code, this is the top-level-function of the masterVPs, and
|
|
seanhalle@230
|
39 * runs when the coreController has no more slave VPs. It's job is to
|
|
seanhalle@260
|
40 * refill the animation slots with slaves that have work.
|
|
seanhalle@230
|
41 *
|
|
seanhalle@260
|
42 *There are multiple versions of the master, each tuned to a specific
|
|
seanhalle@260
|
43 * combination of modes. This keeps the master simple, with reduced overhead,
|
|
seanhalle@260
|
44 * when the application is not using the extra complexity.
|
|
seanhalle@260
|
45 *
|
|
seanhalle@260
|
46 *As of Sept 2012, the versions available will be:
|
|
seanhalle@260
|
47 * 1) Single langauge, which only exposes slaves (such as SSR or Vthread)
|
|
seanhalle@260
|
48 * 2) Single language, which only exposes tasks (such as pure dataflow)
|
|
seanhalle@260
|
49 * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP)
|
|
seanhalle@260
|
50 * 4) Multi-language, which always assumes both tasks and slaves
|
|
seanhalle@260
|
51 * 5) Multi-language and multi-process, which also assumes both tasks and slaves
|
|
seanhalle@260
|
52 *
|
|
seanhalle@260
|
53 *
|
|
seanhalle@260
|
54 *
|
|
seanhalle@260
|
55 */
|
|
seanhalle@260
|
56
|
|
seanhalle@268
|
57 //This version of the master selects one of three loops, depending upon
|
|
seanhalle@268
|
58 // whether stand-alone single language (just slaves), or standalone with
|
|
seanhalle@268
|
59 // tasks, or multi-lang (implies multi-process)
|
|
seanhalle@268
|
60 void animationMaster( void *_environment, SlaveVP *masterVP )
|
|
seanhalle@268
|
61 {
|
|
seanhalle@268
|
62 TopEnv *masterEnv = (TopEnv *)_environment;
|
|
seanhalle@268
|
63 int32 slotIdx;
|
|
seanhalle@268
|
64 AnimSlot *currSlot;
|
|
seanhalle@268
|
65 //Used while scanning and filling animation slots
|
|
seanhalle@268
|
66 AnimSlot **animSlots;
|
|
seanhalle@268
|
67
|
|
seanhalle@268
|
68 //Local copies, for performance
|
|
seanhalle@268
|
69 int32 thisCoresIdx;
|
|
seanhalle@268
|
70
|
|
seanhalle@268
|
71 //======================== Initializations ========================
|
|
seanhalle@268
|
72 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@268
|
73 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@268
|
74
|
|
seanhalle@268
|
75 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@268
|
76
|
|
seanhalle@268
|
77 //======================== animationMaster ========================
|
|
seanhalle@268
|
78 //Have three different modes, and the master behavior is different for
|
|
seanhalle@268
|
79 // each, so jump to the loop that corresponds to the mode.
|
|
seanhalle@268
|
80 //
|
|
seanhalle@269
|
81 while(1)
|
|
seanhalle@269
|
82 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@269
|
83 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@269
|
84 {
|
|
seanhalle@269
|
85 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@268
|
86
|
|
seanhalle@269
|
87 masterFunction( currSlot );
|
|
seanhalle@268
|
88 }
|
|
seanhalle@269
|
89 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@269
|
90 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@269
|
91 flushRegisters();
|
|
seanhalle@268
|
92 }
|
|
seanhalle@268
|
93 }
|
|
seanhalle@268
|
94
|
|
seanhalle@268
|
95
|
|
seanhalle@261
|
96 inline
|
|
seanhalle@261
|
97 void
|
|
seanhalle@269
|
98 masterFunction( AnimSlot *slot )
|
|
seanhalle@261
|
99 { //Scan the animation slots
|
|
seanhalle@261
|
100 int32 magicNumber;
|
|
seanhalle@261
|
101 SlaveVP *slave;
|
|
seanhalle@268
|
102 PRLangEnv *langEnv;
|
|
seanhalle@261
|
103 PRReqst *req;
|
|
seanhalle@268
|
104 PRProcess *process;
|
|
seanhalle@260
|
105
|
|
seanhalle@268
|
106 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@268
|
107 if( slot->workIsDone )
|
|
seanhalle@268
|
108 { slot->workIsDone = FALSE;
|
|
seanhalle@268
|
109 slot->needsWorkAssigned = TRUE;
|
|
seanhalle@261
|
110
|
|
seanhalle@268
|
111 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@268
|
112 MEAS__startReqHdlr;
|
|
seanhalle@261
|
113
|
|
seanhalle@268
|
114
|
|
seanhalle@268
|
115 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@268
|
116 slave = slot->slaveAssignedToSlot;
|
|
seanhalle@268
|
117 req = slave->request;
|
|
seanhalle@268
|
118
|
|
seanhalle@268
|
119 //If the requesting slave is a slot slave, and request is not
|
|
seanhalle@268
|
120 // task-end, then turn it into a free task slave.
|
|
seanhalle@268
|
121 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
|
|
seanhalle@268
|
122 PR_int__replace_with_new_slot_slv( slave );
|
|
seanhalle@268
|
123
|
|
seanhalle@268
|
124 //Handle task create and end first -- they're special cases..
|
|
seanhalle@268
|
125 switch( req->reqType )
|
|
seanhalle@268
|
126 { case TaskEnd:
|
|
seanhalle@268
|
127 { //do PR handler, which calls lang's hdlr and does recycle of
|
|
seanhalle@268
|
128 // free task slave if needed -- PR handler checks for free task Slv
|
|
seanhalle@268
|
129 PRHandle_EndTask( req, slave ); break;
|
|
seanhalle@267
|
130 }
|
|
seanhalle@268
|
131 case TaskCreate:
|
|
seanhalle@268
|
132 { //Do PR's create-task handler, which calls the lang's hdlr
|
|
seanhalle@268
|
133 // PR handler checks for free task Slv
|
|
seanhalle@268
|
134 PRHandle_CreateTask( req, slave ); break;
|
|
seanhalle@268
|
135 }
|
|
seanhalle@268
|
136 case SlvCreate: PRHandle_CreateSlave( req, slave ); break;
|
|
seanhalle@269
|
137 case SlvDissipate: PRHandle_EndSlave( req, slave ); break;
|
|
seanhalle@269
|
138 case Service: PR_int__handle_PRServiceReq( slave ); break; //resumes into Service lang env
|
|
seanhalle@268
|
139 case Hardware: //for future expansion
|
|
seanhalle@268
|
140 case IO: //for future expansion
|
|
seanhalle@268
|
141 case OSCall: //for future expansion
|
|
seanhalle@268
|
142 PR_int__throw_exception("Not implemented", slave, NULL); break;
|
|
seanhalle@268
|
143 case Language: //normal lang request
|
|
seanhalle@268
|
144 { magicNumber = req->langMagicNumber;
|
|
seanhalle@268
|
145 langEnv = PR_PI__give_lang_env_for( slave, magicNumber );
|
|
seanhalle@268
|
146 (*req->handler)( req->langReq, slave, langEnv );
|
|
seanhalle@268
|
147 }
|
|
seanhalle@268
|
148 }
|
|
seanhalle@261
|
149
|
|
seanhalle@268
|
150 MEAS__endReqHdlr;
|
|
seanhalle@267
|
151 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@268
|
152 } //if have request to be handled
|
|
seanhalle@268
|
153
|
|
seanhalle@268
|
154 if( slot->needsWorkAssigned )
|
|
seanhalle@268
|
155 {
|
|
seanhalle@268
|
156 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@268
|
157
|
|
seanhalle@268
|
158 //Pick a process to get this slot
|
|
seanhalle@268
|
159 process = pickAProcess( slot );
|
|
seanhalle@268
|
160
|
|
seanhalle@268
|
161 //Scan lang environs, looking for langEnv with ready work.
|
|
seanhalle@268
|
162 // call the Assigner for that lang Env, to get a slave for the slot
|
|
seanhalle@268
|
163 assignWork( process, slot );
|
|
seanhalle@268
|
164
|
|
seanhalle@268
|
165 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
166 }//if slot needs slave assigned
|
|
seanhalle@261
|
167 }
|
|
seanhalle@260
|
168
|
|
seanhalle@268
|
169 /*When several processes exist, use some pattern for picking one to give
|
|
seanhalle@268
|
170 * the animation slot to.
|
|
seanhalle@268
|
171 *First, it has to be a process that has work available.
|
|
seanhalle@268
|
172 *For now, just do a round-robin
|
|
seanhalle@261
|
173 */
|
|
seanhalle@268
|
174 inline
|
|
seanhalle@268
|
175 PRProcess *
|
|
seanhalle@268
|
176 pickAProcess( AnimSlot *slot )
|
|
seanhalle@268
|
177 { int32 idx;
|
|
seanhalle@268
|
178 PRProcess *process;
|
|
seanhalle@268
|
179
|
|
seanhalle@268
|
180 for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; 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@261
|
187 }
|
|
seanhalle@268
|
188 for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++)
|
|
seanhalle@268
|
189 {
|
|
seanhalle@268
|
190 process = _PRTopEnv->processes[ idx ];
|
|
seanhalle@268
|
191 if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
192 { _PRTopEnv->currProcessIdx = idx;
|
|
seanhalle@268
|
193 return process;
|
|
seanhalle@268
|
194 }
|
|
seanhalle@268
|
195 }
|
|
seanhalle@268
|
196 //none found
|
|
seanhalle@268
|
197 return NULL;
|
|
seanhalle@260
|
198 }
|
|
seanhalle@260
|
199
|
|
seanhalle@261
|
200 /*This does:
|
|
seanhalle@268
|
201 * 1) searches the language environments for one with work ready
|
|
seanhalle@261
|
202 * if finds one, asks its assigner to return work
|
|
seanhalle@261
|
203 * 2) checks what kind of work: new task, resuming task, resuming slave
|
|
seanhalle@261
|
204 * if new task, gets the slot slave and assigns task to it and returns slave
|
|
seanhalle@261
|
205 * else, gets the slave attached to the metaTask and returns that.
|
|
seanhalle@261
|
206 * 3) if no work found, then prune former task slaves waiting to be recycled.
|
|
seanhalle@261
|
207 * If no work and no slaves to prune, check for shutdown conditions.
|
|
seanhalle@261
|
208 *
|
|
seanhalle@268
|
209 * language env keeps its own work in its own structures, and has its own
|
|
seanhalle@261
|
210 * assigner. It chooses
|
|
seanhalle@261
|
211 * However, include a switch that switches-in an override assigner, which
|
|
seanhalle@268
|
212 * sees all the work in all the language env's. This is most likely
|
|
seanhalle@261
|
213 * generated by static tools and included in the executable. That means it
|
|
seanhalle@261
|
214 * has to be called via a registered pointer from here. The idea is that
|
|
seanhalle@261
|
215 * the static tools know which languages are grouped together.. and the
|
|
seanhalle@261
|
216 * override enables them to generate a custom assigner that uses info from
|
|
seanhalle@261
|
217 * all the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@261
|
218 * but am making it possible.
|
|
seanhalle@260
|
219 */
|
|
seanhalle@268
|
220 inline
|
|
seanhalle@268
|
221 SlaveVP *
|
|
seanhalle@261
|
222 assignWork( PRProcess *process, AnimSlot *slot )
|
|
seanhalle@261
|
223 { SlaveVP *returnSlv;
|
|
seanhalle@261
|
224 int32 coreNum, slotNum;
|
|
seanhalle@267
|
225 PRMetaTask *assignedMetaTask;
|
|
seanhalle@260
|
226
|
|
seanhalle@261
|
227 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@260
|
228
|
|
seanhalle@267
|
229 if( process->overrideAssigner != NULL )
|
|
seanhalle@268
|
230 { if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
231 { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot
|
|
seanhalle@268
|
232 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@261
|
233 }
|
|
seanhalle@268
|
234 else
|
|
seanhalle@261
|
235 goto NoWork;
|
|
seanhalle@261
|
236 }
|
|
seanhalle@261
|
237
|
|
seanhalle@268
|
238 //If here, then no override assigner, so search language envs for work
|
|
seanhalle@268
|
239 int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv;
|
|
seanhalle@268
|
240 langEnvsList = process->langEnvsList;
|
|
seanhalle@268
|
241 numEnvs = process->numLangEnvs;
|
|
seanhalle@268
|
242 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array
|
|
seanhalle@268
|
243 { langEnv = langEnvsList[envIdx];
|
|
seanhalle@268
|
244 if( langEnv->hasWork )
|
|
seanhalle@268
|
245 { (*langEnv->slaveAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot
|
|
seanhalle@268
|
246 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@268
|
247 //NOTE: bad search alg -- should start where left off, then wrap around
|
|
seanhalle@260
|
248 }
|
|
seanhalle@260
|
249 }
|
|
seanhalle@268
|
250 //If reach here, then have searched all langEnv's & none have work..
|
|
seanhalle@260
|
251
|
|
seanhalle@268
|
252 NoWork: //No work, if end up here..
|
|
seanhalle@260
|
253 {
|
|
seanhalle@260
|
254 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@268
|
255 returnSlv = process->idleSlv[coreNum][slotNum];
|
|
seanhalle@260
|
256
|
|
seanhalle@260
|
257 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@260
|
258 // never go there
|
|
seanhalle@261
|
259 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@260
|
260 Unit newU;
|
|
seanhalle@268
|
261 newU.vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
262 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
263 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@260
|
264
|
|
seanhalle@261
|
265 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@260
|
266 { Dependency newD; // to this one
|
|
seanhalle@268
|
267 newD.from_vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
268 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@268
|
269 newD.to_vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
270 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
271 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@260
|
272 }
|
|
seanhalle@268
|
273 #endif
|
|
seanhalle@268
|
274 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@269
|
275 return FALSE;
|
|
seanhalle@260
|
276 }
|
|
seanhalle@268
|
277
|
|
seanhalle@268
|
278 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@268
|
279 {
|
|
seanhalle@268
|
280 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@269
|
281 return TRUE;
|
|
seanhalle@260
|
282 }
|
|
seanhalle@260
|
283 }
|
|
seanhalle@260
|
284
|
|
seanhalle@260
|
285
|
|
seanhalle@268
|
286
|
|
seanhalle@268
|
287 /*This is first thing called when creating a slave.. it hands off to the
|
|
seanhalle@268
|
288 * langlet's creator, then adds updates of its own..
|
|
seanhalle@268
|
289 *
|
|
seanhalle@268
|
290 *There's a question of things like lang data, meta tasks, and such..
|
|
seanhalle@268
|
291 *In creator, only PR related things happen, and things for the langlet whose
|
|
seanhalle@261
|
292 * creator construct was used.
|
|
seanhalle@268
|
293 *
|
|
seanhalle@268
|
294 *Other langlets still get a chance to create langData -- but by registering a
|
|
seanhalle@268
|
295 * "createLangData" handler in the langEnv. When a construct of the langlet
|
|
seanhalle@268
|
296 * calls "PR__give_lang_data()", if there is no langData for that langlet,
|
|
seanhalle@268
|
297 * the PR will call the creator in the langlet's langEnv, place whatever it
|
|
seanhalle@268
|
298 * makes as the langData in that slave for that langlet, and return that langData
|
|
seanhalle@261
|
299 *
|
|
seanhalle@261
|
300 *So, as far as counting things, a langlet is only allowed to count creation
|
|
seanhalle@261
|
301 * of slaves it creates itself.. may have to change this later.. add a way for
|
|
seanhalle@261
|
302 * langlet to register a trigger Fn called each time a slave gets created..
|
|
seanhalle@261
|
303 * need more experience with what langlets will do at create time.. think Cilk
|
|
seanhalle@261
|
304 * has interesting create behavior.. not sure how that will differ in light
|
|
seanhalle@261
|
305 * of true tasks and langlet approach. Look at it after all done and start
|
|
seanhalle@261
|
306 * modifying the langs to be langlets..
|
|
seanhalle@261
|
307 *
|
|
seanhalle@261
|
308 *PR itself needs to create the slave, then update numLiveSlaves in process,
|
|
seanhalle@261
|
309 * copy processID from requestor to newly created
|
|
seanhalle@261
|
310 */
|
|
seanhalle@268
|
311 inline
|
|
seanhalle@268
|
312 void
|
|
seanhalle@268
|
313 PRHandle_CreateSlave( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@268
|
314 { SlaveVP *newSlv;
|
|
seanhalle@261
|
315 PRProcess *process;
|
|
seanhalle@268
|
316 PRLangEnv *protoLangEnv;
|
|
seanhalle@261
|
317
|
|
seanhalle@268
|
318 process = slave->processSlaveIsIn;
|
|
seanhalle@268
|
319 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber );
|
|
seanhalle@268
|
320
|
|
seanhalle@268
|
321 // newSlv = PR_int__create_slave( req->topLevelFn, req->initData );
|
|
seanhalle@268
|
322
|
|
seanhalle@268
|
323 //create slv has diff prototype than standard reqst hdlr
|
|
seanhalle@268
|
324 newSlv =
|
|
seanhalle@268
|
325 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv));
|
|
seanhalle@268
|
326
|
|
seanhalle@261
|
327 newSlv->typeOfVP = GenericSlv;
|
|
seanhalle@261
|
328 newSlv->processSlaveIsIn = process;
|
|
seanhalle@268
|
329 newSlv->ID = req->ID;
|
|
seanhalle@266
|
330 process->numLiveGenericSlvs += 1;
|
|
seanhalle@260
|
331 }
|
|
seanhalle@260
|
332
|
|
seanhalle@268
|
333 /*The dissipate handler has to, update the number of slaves of the type, within
|
|
seanhalle@261
|
334 * the process, and call the langlet handler linked into the request,
|
|
seanhalle@261
|
335 * and after that returns, then call the PR function that frees the slave state
|
|
seanhalle@261
|
336 * (or recycles the slave).
|
|
seanhalle@261
|
337 *
|
|
seanhalle@261
|
338 *The PR function that frees the slave state has to also free all of the
|
|
seanhalle@268
|
339 * langData in the slave.. or else reset all of the langDatas.. by, say, marking
|
|
seanhalle@268
|
340 * them, then in PR__give_langData( magicNum ) call the langlet registered
|
|
seanhalle@268
|
341 * "resetLangData" Fn.
|
|
seanhalle@261
|
342 */
|
|
seanhalle@268
|
343 inline
|
|
seanhalle@268
|
344 void
|
|
seanhalle@269
|
345 PRHandle_EndSlave( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@261
|
346 { PRProcess *process;
|
|
seanhalle@268
|
347 PRLangEnv *protoLangEnv;
|
|
seanhalle@261
|
348
|
|
seanhalle@261
|
349 process = slave->processSlaveIsIn;
|
|
seanhalle@261
|
350
|
|
seanhalle@261
|
351 //do the language's dissipate handler
|
|
seanhalle@268
|
352 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber );
|
|
seanhalle@268
|
353
|
|
seanhalle@268
|
354 if(req->handler != NULL)
|
|
seanhalle@268
|
355 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@261
|
356
|
|
seanhalle@266
|
357 process->numLiveGenericSlvs -= 1;
|
|
seanhalle@268
|
358 PR_int__recycle_slave__ML( slave );
|
|
seanhalle@267
|
359
|
|
seanhalle@261
|
360 //check End Of Process Condition
|
|
seanhalle@261
|
361 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
362 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@268
|
363 PR_SS__shutdown_process__ML( process );
|
|
seanhalle@261
|
364 }
|
|
seanhalle@261
|
365
|
|
seanhalle@261
|
366 /*Create task is a special form, that has PR behavior in addition to plugin
|
|
seanhalle@268
|
367 * behavior. Master calls this first, and it then calls the plugin's
|
|
seanhalle@261
|
368 * create task handler.
|
|
seanhalle@267
|
369 *
|
|
seanhalle@267
|
370 *Note: the requesting slave must be either generic slave or free task slave
|
|
seanhalle@261
|
371 */
|
|
seanhalle@268
|
372 inline
|
|
seanhalle@268
|
373 void
|
|
seanhalle@268
|
374 PRHandle_CreateTask( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@267
|
375 { PRMetaTask *metaTask;
|
|
seanhalle@267
|
376 PRProcess *process;
|
|
seanhalle@268
|
377 PRLangEnv *protoLangEnv;
|
|
seanhalle@268
|
378 void *task;
|
|
seanhalle@267
|
379
|
|
seanhalle@268
|
380 process = slave->processSlaveIsIn;
|
|
seanhalle@268
|
381
|
|
seanhalle@268
|
382 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave,
|
|
seanhalle@268
|
383 req->langMagicNumber );
|
|
seanhalle@268
|
384
|
|
seanhalle@268
|
385 //Do the langlet's create-task handler, which keeps the task
|
|
seanhalle@268
|
386 // inside the langlet's lang env, but returns the langMetaTask
|
|
seanhalle@268
|
387 // so PR can put stuff into the prolog
|
|
seanhalle@268
|
388 task =
|
|
seanhalle@268
|
389 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@268
|
390 metaTask = PR_int__give_prolog_of_task( task );
|
|
seanhalle@268
|
391 metaTask->ID = req->ID; //may be NULL
|
|
seanhalle@267
|
392 metaTask->topLevelFn = req->topLevelFn;
|
|
seanhalle@267
|
393 metaTask->initData = req->initData;
|
|
seanhalle@261
|
394
|
|
seanhalle@261
|
395 process->numLiveTasks += 1;
|
|
seanhalle@267
|
396
|
|
seanhalle@261
|
397 return;
|
|
seanhalle@261
|
398 }
|
|
seanhalle@261
|
399
|
|
seanhalle@261
|
400 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
|
|
seanhalle@261
|
401 * suspended at some point in its code.
|
|
seanhalle@261
|
402 *For 1, just decr count of live tasks (and check for end condition) -- the
|
|
seanhalle@261
|
403 * master loop will decide what goes into the slot freed up by this task end,
|
|
seanhalle@261
|
404 * so, here, don't worry about assigning a new task to the slot slave.
|
|
seanhalle@261
|
405 *For 2, the task's slot slave has been converted to a free task slave, which
|
|
seanhalle@261
|
406 * now has nothing more to do, so send it to the recycle Q (which includes
|
|
seanhalle@268
|
407 * freeing all the langData and meta task structs alloc'd for it). Then
|
|
seanhalle@261
|
408 * decrement the live task count and check end condition.
|
|
seanhalle@261
|
409 *
|
|
seanhalle@261
|
410 *PR has to update count of live tasks, and check end of process condition.
|
|
seanhalle@267
|
411 * The "main" can invoke constructs that wait for a process to end, so when
|
|
seanhalle@267
|
412 * end detected, have to resume what's waiting..
|
|
seanhalle@267
|
413 *Thing is, that wait involves the main OS thread. That means
|
|
seanhalle@261
|
414 * PR internals have to do OS thread signaling. Want to do that in the
|
|
seanhalle@267
|
415 * core controller, which has the original stack of an OS thread. So the
|
|
seanhalle@267
|
416 * end process handling happens in the core controller.
|
|
seanhalle@261
|
417 *
|
|
seanhalle@261
|
418 *So here, when detect process end, signal to the core controller, which will
|
|
seanhalle@267
|
419 * then do the condition variable notify to the OS thread that's waiting.
|
|
seanhalle@267
|
420 *
|
|
seanhalle@267
|
421 *Note: slave may be either a slot slave or a free task slave.
|
|
seanhalle@261
|
422 */
|
|
seanhalle@268
|
423 inline
|
|
seanhalle@268
|
424 void
|
|
seanhalle@268
|
425 PRHandle_EndTask( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@268
|
426 { void *langEnv;
|
|
seanhalle@261
|
427 PRProcess *process;
|
|
seanhalle@268
|
428 void *langMetaTask;
|
|
seanhalle@267
|
429
|
|
seanhalle@268
|
430 langEnv = PR_int__give_lang_env_of_req__ML( req, requestingSlv ); //magic num in req
|
|
seanhalle@268
|
431 langMetaTask = PR_int__give_lang_meta_task_from_slave__ML( requestingSlv, req->langMagicNumber);
|
|
seanhalle@261
|
432
|
|
seanhalle@267
|
433 //Do the langlet's request handler
|
|
seanhalle@268
|
434 //Want to keep PR structs hidden from plugin, so extract langReq..
|
|
seanhalle@268
|
435 (*req->handler)( req->langReq, requestingSlv, langEnv );
|
|
seanhalle@267
|
436
|
|
seanhalle@267
|
437 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
|
|
seanhalle@267
|
438 if( requestingSlv->typeOfVP == FreeTaskSlv )
|
|
seanhalle@268
|
439 PR_int__recycle_slave__ML( requestingSlv );
|
|
seanhalle@261
|
440
|
|
seanhalle@261
|
441 process->numLiveTasks -= 1;
|
|
seanhalle@261
|
442
|
|
seanhalle@261
|
443 //check End Of Process Condition
|
|
seanhalle@261
|
444 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
445 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@268
|
446 { //Tell the core controller to do wakeup of any waiting OS thread
|
|
seanhalle@268
|
447 PR_SS__shutdown_process__ML( process );
|
|
seanhalle@268
|
448 }
|
|
seanhalle@261
|
449 }
|
|
seanhalle@261
|
450
|