annotate AnimationMaster.c @ 270:292393c6bef1

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