annotate AnimationMaster.c @ 268:e5bd470b562b

Checkpoint 2 -- split up header file, and about to delete single lang version of AnimationMaster
author Sean Halle <seanhalle@yahoo.com>
date Mon, 14 Jan 2013 15:31:23 -0800
parents 608833ae2c5d
children e6a68e7ea63f
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@268 25 void PRHandle_Dissipate( 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 void masterFunction_MultiLang( 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@268 81 switch(masterEnv->mode)
seanhalle@268 82 {
seanhalle@268 83 /*
seanhalle@268 84 { case SingleLang:
seanhalle@268 85 while(1)
seanhalle@268 86 { MEAS__Capture_Pre_Master_Point
seanhalle@268 87 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@268 88 {
seanhalle@268 89 currSlot = animSlots[ slotIdx ];
seanhalle@268 90
seanhalle@268 91 masterFunction_StandaloneSlavesOnly( masterEnv, currSlot );
seanhalle@268 92 }
seanhalle@268 93 MEAS__Capture_Post_Master_Point;
seanhalle@268 94 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@268 95 flushRegisters();
seanhalle@268 96 }
seanhalle@268 97
seanhalle@268 98 case SingleLang:
seanhalle@268 99 { PRLangEnv *protoLangEnv = _PRTopEnv->protoLangEnv;
seanhalle@268 100 while(1)
seanhalle@268 101 { MEAS__Capture_Pre_Master_Point
seanhalle@268 102 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@268 103 {
seanhalle@268 104 currSlot = animSlots[ slotIdx ];
seanhalle@268 105
seanhalle@268 106 masterFunction_SingleLang( protoLangEnv, currSlot );
seanhalle@268 107 }
seanhalle@268 108 MEAS__Capture_Post_Master_Point;
seanhalle@268 109 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@268 110 flushRegisters();
seanhalle@268 111 }
seanhalle@268 112 }
seanhalle@268 113 */
seanhalle@268 114 case MultiLang:
seanhalle@268 115 { while(1)
seanhalle@268 116 { MEAS__Capture_Pre_Master_Point
seanhalle@268 117 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@268 118 {
seanhalle@268 119 currSlot = animSlots[ slotIdx ];
seanhalle@268 120
seanhalle@268 121 masterFunction_MultiLang( currSlot );
seanhalle@268 122 }
seanhalle@268 123 MEAS__Capture_Post_Master_Point;
seanhalle@268 124 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@268 125 flushRegisters();
seanhalle@268 126 }
seanhalle@268 127 }
seanhalle@268 128 }
seanhalle@268 129 }
seanhalle@268 130
seanhalle@268 131
seanhalle@261 132
seanhalle@260 133 //===================== The versions of the Animation Master =================
seanhalle@260 134 //
seanhalle@260 135 //==============================================================================
seanhalle@260 136
seanhalle@260 137 /* 1) This version is for a single language, that has only slaves, no tasks,
seanhalle@260 138 * such as Vthread or SSR.
seanhalle@260 139 *This version is for when an application has only a single language, and
seanhalle@260 140 * that language exposes slaves explicitly (as opposed to a task based
seanhalle@260 141 * language like pure dataflow).
seanhalle@260 142 *
seanhalle@260 143 *
seanhalle@260 144 *It scans the animation slots for just-completed slaves.
seanhalle@260 145 * Each completed slave has a request in it. So, the master hands each to
seanhalle@260 146 * the plugin's request handler (there is only one plugin, because only one
seanhalle@260 147 * lang).
seanhalle@230 148 *Each request represents a language construct that has been encountered
seanhalle@230 149 * by the application code in the slave. Passing the request to the
seanhalle@230 150 * request handler is how that language construct's behavior gets invoked.
seanhalle@230 151 * The request handler then performs the actions of the construct's
seanhalle@230 152 * behavior. So, the request handler encodes the behavior of the
seanhalle@230 153 * language's parallelism constructs, and performs that when the master
seanhalle@230 154 * hands it a slave containing a request to perform that construct.
seanhalle@230 155 *
seanhalle@230 156 *On a shared-memory machine, the behavior of parallelism constructs
seanhalle@230 157 * equals control, over order of execution of code. Hence, the behavior
seanhalle@230 158 * of the language constructs performed by the request handler is to
seanhalle@230 159 * choose the order that slaves get animated, and thereby control the
seanhalle@230 160 * order that application code in the slaves executes.
seanhalle@230 161 *
seanhalle@230 162 *To control order of animation of slaves, the request handler has a
seanhalle@268 163 * language environment that holds data structures used to hold slaves
seanhalle@230 164 * and choose when they're ready to be animated.
seanhalle@230 165 *
seanhalle@230 166 *Once a slave is marked as ready to be animated by the request handler,
seanhalle@230 167 * it is the second plugin function, the Assigner, which chooses the core
seanhalle@230 168 * the slave gets assigned to for animation. Hence, the Assigner doesn't
seanhalle@230 169 * perform any of the semantic behavior of language constructs, rather
seanhalle@230 170 * it gives the language a chance to improve performance. The performance
seanhalle@230 171 * of application code is strongly related to communication between
seanhalle@230 172 * cores. On shared-memory machines, communication is caused during
seanhalle@230 173 * execution of code, by memory accesses, and how much depends on contents
seanhalle@230 174 * of caches connected to the core executing the code. So, the placement
seanhalle@230 175 * of slaves determines the communication caused during execution of the
seanhalle@230 176 * slave's code.
seanhalle@230 177 *The point of the Assigner, then, is to use application information during
seanhalle@230 178 * execution of the program, to make choices about slave placement onto
seanhalle@230 179 * cores, with the aim to put slaves close to caches containing the data
seanhalle@230 180 * used by the slave's code.
seanhalle@230 181 *
seanhalle@230 182 *==========================================================================
seanhalle@230 183 *In summary, the animationMaster scans the slots, finds slaves
seanhalle@230 184 * just-finished, which hold requests, pass those to the request handler,
seanhalle@268 185 * along with the language environment, and the request handler then manages
seanhalle@268 186 * the structures in the language env, which controls the order of
seanhalle@230 187 * animation of slaves, and so embodies the behavior of the language
seanhalle@230 188 * constructs.
seanhalle@230 189 *The animationMaster then rescans the slots, offering each empty one to
seanhalle@268 190 * the Assigner, along with the language environment. The Assigner chooses
seanhalle@268 191 * among the ready slaves in the language env, finding the one best suited
seanhalle@230 192 * to be animated by that slot's associated core.
seanhalle@230 193 *
seanhalle@230 194 *==========================================================================
seanhalle@230 195 *Implementation Details:
seanhalle@230 196 *
seanhalle@268 197 *There is a separate masterVP for each core, but a single language
seanhalle@230 198 * environment shared by all cores. Each core also has its own scheduling
seanhalle@230 199 * slots, which are used to communicate slaves between animationMaster and
seanhalle@261 200 * coreController. There is only one global variable, _PRTopEnv, which
seanhalle@268 201 * holds the language env and other things shared by the different
seanhalle@230 202 * masterVPs. The request handler and Assigner are registered with
seanhalle@230 203 * the animationMaster by the language's init function, and a pointer to
seanhalle@261 204 * each is in the _PRTopEnv. (There are also some pthread related global
seanhalle@260 205 * vars, but they're only used during init of PR).
seanhalle@260 206 *PR gains control over the cores by essentially "turning off" the OS's
seanhalle@230 207 * scheduler, using pthread pin-to-core commands.
seanhalle@230 208 *
seanhalle@230 209 *The masterVPs are created during init, with this animationMaster as their
seanhalle@230 210 * top level function. The masterVPs use the same SlaveVP data structure,
seanhalle@230 211 * even though they're not slave VPs.
seanhalle@230 212 *A "seed slave" is also created during init -- this is equivalent to the
seanhalle@260 213 * "main" function in C, and acts as the entry-point to the PR-language-
seanhalle@230 214 * based application.
seanhalle@260 215 *The masterVPs share a single system-wide master-lock, so only one
seanhalle@230 216 * masterVP may be animated at a time.
seanhalle@261 217 *The core controllers access _PRTopEnv to get the masterVP, and when
seanhalle@230 218 * they start, the slots are all empty, so they run their associated core's
seanhalle@230 219 * masterVP. The first of those to get the master lock sees the seed slave
seanhalle@268 220 * in the shared language environment, so when it runs the Assigner, that
seanhalle@230 221 * returns the seed slave, which the animationMaster puts into a scheduling
seanhalle@230 222 * slot then switches to the core controller. That then switches the core
seanhalle@230 223 * over to the seed slave, which then proceeds to execute language
seanhalle@230 224 * constructs to create more slaves, and so on. Each of those constructs
seanhalle@230 225 * causes the seed slave to suspend, switching over to the core controller,
seanhalle@230 226 * which eventually switches to the masterVP, which executes the
seanhalle@260 227 * request handler, which uses PR primitives to carry out the creation of
seanhalle@230 228 * new slave VPs, which are marked as ready for the Assigner, and so on..
seanhalle@230 229 *
seanhalle@230 230 *On animation slots, and system behavior:
seanhalle@260 231 * A request may linger in an animation slot for a long time while
seanhalle@230 232 * the slaves in the other slots are animated. This only becomes a problem
seanhalle@230 233 * when such a request is a choke-point in the constraints, and is needed
seanhalle@260 234 * to free work for *other* cores. To reduce this occurrence, the number
seanhalle@230 235 * of animation slots should be kept low. In balance, having multiple
seanhalle@230 236 * animation slots amortizes the overhead of switching to the masterVP and
seanhalle@230 237 * executing the animationMaster code, which drives for more than one. In
seanhalle@230 238 * practice, the best balance should be discovered by profiling.
seanhalle@230 239 */
seanhalle@268 240 /*
seanhalle@268 241 void masterFunction_StandaloneSlavesOnly( AnimSlot *slot )
seanhalle@230 242 {
seanhalle@268 243 SlaveVP *slave;
seanhalle@268 244 PRReqst *req;
seanhalle@268 245 PRLangEnv *langEnv = _PRTopEnv->langEnv;
seanhalle@268 246
seanhalle@230 247
seanhalle@230 248 //======================== animationMaster ========================
seanhalle@268 249
seanhalle@268 250 //Check if newly-done slave in slot, which will need request handled
seanhalle@268 251 if( slot->workIsDone )
seanhalle@268 252 { slot->workIsDone = FALSE;
seanhalle@268 253 slot->needsWorkAssigned = TRUE;
seanhalle@230 254
seanhalle@230 255
seanhalle@268 256 HOLISTIC__Record_AppResponder_start;
seanhalle@268 257 MEAS__startReqHdlr;
seanhalle@268 258 //process the request made by the slave (held inside slave struc)
seanhalle@268 259 slave = slot->slaveAssignedToSlot;
seanhalle@268 260 req = slave->request;
seanhalle@260 261
seanhalle@268 262 //Handle task create and end first -- they're special cases..
seanhalle@268 263 switch( req->reqType )
seanhalle@268 264 { case SlvCreate: PRHandle_CreateSlave( slave ); break;
seanhalle@268 265 case SlvDissipate: PRHandle_Dissipate( slave ); break;
seanhalle@268 266 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own language env
seanhalle@268 267 case Hardware: //for future expansion
seanhalle@268 268 case IO: //for future expansion
seanhalle@268 269 case OSCall: //for future expansion
seanhalle@268 270 PR_int__throw_exception("Not implemented"); break;
seanhalle@268 271 case Language: //normal lang request
seanhalle@268 272 {
seanhalle@268 273 (*langEnv->requestHdlr)( req->langReq, slave, langEnv );
seanhalle@230 274 }
seanhalle@230 275 }
seanhalle@268 276 HOLISTIC__Record_AppResponder_end;
seanhalle@268 277 MEAS__endReqHdlr;
seanhalle@230 278 }
seanhalle@268 279 //If slot empty, hand to Assigner to fill with a slave
seanhalle@268 280 if( slot->needsWorkAssigned )
seanhalle@268 281 { //Call plugin's Assigner to give slot a new slave
seanhalle@268 282 HOLISTIC__Record_Assigner_start;
seanhalle@230 283
seanhalle@268 284 if( langEnv->hasWork )
seanhalle@268 285 { (*langEnv->slaveAssigner)( langEnv, slot ); //calls PR fn that inserts work into slot
seanhalle@268 286 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
seanhalle@268 287 }
seanhalle@268 288 else
seanhalle@268 289 goto NoWork;
seanhalle@268 290 }
seanhalle@230 291
seanhalle@268 292 NoWork:
seanhalle@268 293 //No work, if reach here..
seanhalle@268 294 {
seanhalle@268 295 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
seanhalle@268 296 coreNum = slot->coreSlotIsOn;
seanhalle@268 297 returnSlv = process->idleSlv[coreNum][slotNum];
seanhalle@268 298
seanhalle@268 299 //things that would normally happen in resume(), but idle VPs
seanhalle@268 300 // never go there
seanhalle@268 301 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
seanhalle@268 302 Unit newU;
seanhalle@268 303 newU.vp = returnSlv->slaveNum;
seanhalle@268 304 newU.task = returnSlv->numTimesAssignedToASlot;
seanhalle@268 305 addToListOfArrays(Unit,newU,process->unitList);
seanhalle@268 306
seanhalle@268 307 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
seanhalle@268 308 { Dependency newD; // to this one
seanhalle@268 309 newD.from_vp = returnSlv->slaveNum;
seanhalle@268 310 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
seanhalle@268 311 newD.to_vp = returnSlv->slaveNum;
seanhalle@268 312 newD.to_task = returnSlv->numTimesAssignedToASlot;
seanhalle@268 313 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
seanhalle@268 314 }
seanhalle@268 315 #endif
seanhalle@268 316 HOLISTIC__Record_Assigner_end;
seanhalle@268 317 return;
seanhalle@268 318 }
seanhalle@268 319
seanhalle@268 320 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
seanhalle@268 321 {
seanhalle@268 322 HOLISTIC__Record_Assigner_end;
seanhalle@268 323 return;
seanhalle@268 324 }
seanhalle@230 325 }
seanhalle@268 326 */
seanhalle@260 327
seanhalle@260 328
seanhalle@260 329 /*This is the master when just multi-lang, but not multi-process mode is on.
seanhalle@260 330 * This version has to handle both tasks and slaves, and do extra work of
seanhalle@268 331 * looking up the language env and handlers to use, for each completed bit of
seanhalle@260 332 * work.
seanhalle@268 333 *It also has to search through the language envs to find one with work,
seanhalle@260 334 * then ask that env's assigner to return a unit of that work.
seanhalle@260 335 *
seanhalle@260 336 *The language is written to startup in the same way as if it were the only
seanhalle@260 337 * language in the app, and it operates in the same way,
seanhalle@260 338 * the only difference between single language and multi-lang is here, in the
seanhalle@260 339 * master.
seanhalle@260 340 *This invisibility to mode is why the language has to use registration calls
seanhalle@260 341 * for everything during startup -- those calls do different things depending
seanhalle@260 342 * on whether it's single-language or multi-language mode.
seanhalle@260 343 *
seanhalle@260 344 *In this version of the master, work can either be a task or a resumed slave
seanhalle@260 345 *Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 346 * then the next available work may be either.. so really have two distinct
seanhalle@260 347 * loops that are inter-twined..
seanhalle@260 348 *
seanhalle@260 349 *Some special cases:
seanhalle@260 350 * A task-end is a special case for a few reasons (below).
seanhalle@260 351 * A task-end can't block a slave (can't cause it to "logically suspend")
seanhalle@260 352 * A task available for work can only be assigned to a special slave, which
seanhalle@260 353 * has been set aside for doing tasks, one such task-slave is always
seanhalle@260 354 * assigned to each slot. So, when a task ends, a new task is assigned to
seanhalle@260 355 * that slot's task-slave right away.
seanhalle@260 356 * But if no tasks are available, then have to switch over to looking at
seanhalle@260 357 * slaves to find one ready to resume, to find work for the slot.
seanhalle@260 358 * If a task just suspends, not ends, then its task-slave is no longer
seanhalle@260 359 * available to take new tasks, so a new task-slave has to be assigned to
seanhalle@260 360 * that slot. Then the slave of the suspended task is turned into a free
seanhalle@260 361 * task-slave and request handling is done on it as if it were a slave
seanhalle@260 362 * that suspended.
seanhalle@260 363 * After request handling, do the same sequence of looking for a task to be
seanhalle@260 364 * work, and if none, look for a slave ready to resume, as work for the slot.
seanhalle@260 365 * If a slave suspends, handle its request, then look for work.. first for a
seanhalle@260 366 * task to assign, and if none, slaves ready to resume.
seanhalle@260 367 * Another special case is when task-end is done on a free task-slave.. in
seanhalle@260 368 * that case, the slave has no more work and no way to get more.. so place
seanhalle@260 369 * it into a recycle queue.
seanhalle@260 370 * If no work is found of either type, then do a special thing to prune down
seanhalle@260 371 * the extra slaves in the recycle queue, just so don't get too many..
seanhalle@260 372 *
seanhalle@260 373 *The multi-lang thing complicates matters..
seanhalle@260 374 *
seanhalle@268 375 *For request handling, it means have to first fetch the language environment
seanhalle@260 376 * of the language, and then do the request handler pointed to by that
seanhalle@268 377 * language env.
seanhalle@260 378 *For assigning, things get more complex because of competing goals.. One
seanhalle@260 379 * goal is for language specific stuff to be used during assignment, so
seanhalle@260 380 * assigner can make higher quality decisions.. but with multiple languages,
seanhalle@260 381 * which only get mixed in the application, the assigners can't be written
seanhalle@260 382 * with knowledge of each other. So, they can only make localized decisions,
seanhalle@260 383 * and so different language's assigners may interfere with each other..
seanhalle@260 384 *
seanhalle@260 385 *So, have some possibilities available:
seanhalle@260 386 *1) can have a fixed scheduler in the proto-runtime, that all the
seanhalle@260 387 * languages give their work to.. (but then lose language-specific info,
seanhalle@260 388 * there is a standard PR format for assignment info, and the langauge
seanhalle@260 389 * attaches this to the work-unit when it gives it to PR.. also have issue
seanhalle@260 390 * with HWSim, which uses a priority Q instead of FIFO, and requests can
seanhalle@260 391 * "undo" previous work put in, so request handlers need way to manipulate
seanhalle@260 392 * the work-holding Q..) (this might be fudgeable with
seanhalle@260 393 * HWSim, if the master did a lang-supplied callback each time it assigns a
seanhalle@260 394 * unit to a slot.. then HWSim can keep exactly one unit of work in PR's
seanhalle@260 395 * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies
seanhalle@260 396 * a task-end handler that kicks the next unit of work from HWSim internal
seanhalle@260 397 * priority queue, over to PR readyQ)
seanhalle@268 398 *2) can have each language have its own language env, that holds its own
seanhalle@260 399 * work, which is assigned by its own assigner.. then the master searches
seanhalle@268 400 * through all the language envs to find one with work and asks it give work..
seanhalle@260 401 * (this has downside of blinding assigners to each other.. but does work
seanhalle@260 402 * for HWSim case)
seanhalle@260 403 *3) could make PR have a different readyQ for each core, and ask the lang
seanhalle@260 404 * to put work to the core it prefers.. but the work may be moved by PR if
seanhalle@260 405 * needed, say if one core idles for too long. This is a hybrid approach,
seanhalle@260 406 * letting the language decide which core, but PR keeps the work and does it
seanhalle@260 407 * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion,
seanhalle@260 408 * but it would be complicated by having to track cores separately)
seanhalle@260 409 *
seanhalle@260 410 *Choosing 2, to keep compatibility with single-lang mode.. it allows the same
seanhalle@260 411 * assigner to be used for single-lang as for multi-lang.. the overhead of
seanhalle@260 412 * the extra master search for work is part of the price of the flexibility,
seanhalle@260 413 * but should be fairly small.. takes the first env that has work available,
seanhalle@260 414 * and whatever it returns is assigned to the slot..
seanhalle@260 415 *
seanhalle@260 416 *As a hybrid, giving an option for a unified override assigner to be registered
seanhalle@260 417 * and used.. This allows something like a static analysis to detect
seanhalle@260 418 * which languages are grouped together, and then analyze the pattern of
seanhalle@260 419 * construct calls, and generate a custom assigner that uses info from all
seanhalle@260 420 * the languages in a unified way.. Don't really expect this to happen,
seanhalle@260 421 * but making it possible.
seanhalle@260 422 */
seanhalle@268 423 /*
seanhalle@268 424 inline
seanhalle@268 425 void
seanhalle@268 426 masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot )
seanhalle@268 427 { //Scan the animation slots
seanhalle@268 428 SlaveVP *slave;
seanhalle@268 429 PRReqst *req;
seanhalle@268 430
seanhalle@268 431 //Check if newly-done slave in slot, which will need request handled
seanhalle@268 432 if( slot->workIsDone )
seanhalle@268 433 { slot->workIsDone = FALSE;
seanhalle@268 434 slot->needsWorkAssigned = TRUE;
seanhalle@268 435
seanhalle@268 436 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@268 437 MEAS__startReqHdlr;
seanhalle@268 438
seanhalle@268 439
seanhalle@268 440 //process the request made by the slave (held inside slave struc)
seanhalle@268 441 slave = slot->slaveAssignedToSlot;
seanhalle@268 442 req = slave->request;
seanhalle@268 443
seanhalle@268 444 //If the requesting slave is a slot slave, and request is not
seanhalle@268 445 // task-end, then turn it into a free task slave.
seanhalle@268 446 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
seanhalle@268 447 PR_int__replace_with_new_slot_slv( slave );
seanhalle@268 448
seanhalle@268 449 //Handle task create and end first -- they're special cases..
seanhalle@268 450 switch( req->reqType )
seanhalle@268 451 { case TaskEnd:
seanhalle@268 452 { //do PR handler, which calls lang's hdlr and does recycle of
seanhalle@268 453 // free task slave if needed -- PR handler checks for free task Slv
seanhalle@268 454 PRHandle_EndTask_SL( slave ); break;
seanhalle@268 455 }
seanhalle@268 456 case TaskCreate:
seanhalle@268 457 { //Do PR's create-task handler, which calls the lang's hdlr
seanhalle@268 458 // PR handler checks for free task Slv
seanhalle@268 459 PRHandle_CreateTask_SL( slave ); break;
seanhalle@268 460 }
seanhalle@268 461 case SlvCreate: PRHandle_CreateSlave_SL( slave ); break;
seanhalle@268 462 case SlvDissipate: PRHandle_Dissipate_SL( slave ); break;
seanhalle@268 463 case Service: PR_int__handle_PRServiceReq_SL( slave ); break; //resume into PR's own language env
seanhalle@268 464 case Hardware: //for future expansion
seanhalle@268 465 case IO: //for future expansion
seanhalle@268 466 case OSCall: //for future expansion
seanhalle@268 467 PR_int__throw_exception("Not implemented", slave, NULL); break;
seanhalle@268 468 case Language: //normal lang request
seanhalle@268 469 {
seanhalle@268 470 (*protoLangEnv->requestHdlr)( req->langReq, slave, (void*)PR_int__give_lang_env(protoLangEnv ));
seanhalle@268 471 }
seanhalle@268 472 }
seanhalle@268 473
seanhalle@268 474 MEAS__endReqHdlr;
seanhalle@268 475 HOLISTIC__Record_AppResponder_end;
seanhalle@268 476 } //if have request to be handled
seanhalle@268 477
seanhalle@268 478 //If slot empty, hand to Assigner to fill with a slave
seanhalle@268 479 if( slot->needsWorkAssigned )
seanhalle@268 480 { //Call plugin's Assigner to give slot a new slave
seanhalle@268 481 HOLISTIC__Record_Assigner_start;
seanhalle@268 482
seanhalle@268 483 if( protoLangEnv->hasWork )
seanhalle@268 484 { (*protoLangEnv->slaveAssigner)( protoLangEnv, slot ); //calls PR fn that inserts work into slot
seanhalle@268 485 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
seanhalle@268 486 }
seanhalle@268 487 else
seanhalle@268 488 goto NoWork;
seanhalle@268 489 }
seanhalle@260 490
seanhalle@268 491 NoWork:
seanhalle@268 492 //No work, if reach here..
seanhalle@268 493 {
seanhalle@268 494 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
seanhalle@268 495 coreNum = slot->coreSlotIsOn;
seanhalle@268 496 returnSlv = process->idleSlv[coreNum][slotNum];
seanhalle@268 497
seanhalle@268 498 //things that would normally happen in resume(), but idle VPs
seanhalle@268 499 // never go there
seanhalle@268 500 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
seanhalle@268 501 Unit newU;
seanhalle@268 502 newU.vp = returnSlv->slaveNum;
seanhalle@268 503 newU.task = returnSlv->numTimesAssignedToASlot;
seanhalle@268 504 addToListOfArrays(Unit,newU,process->unitList);
seanhalle@260 505
seanhalle@268 506 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
seanhalle@268 507 { Dependency newD; // to this one
seanhalle@268 508 newD.from_vp = returnSlv->slaveNum;
seanhalle@268 509 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
seanhalle@268 510 newD.to_vp = returnSlv->slaveNum;
seanhalle@268 511 newD.to_task = returnSlv->numTimesAssignedToASlot;
seanhalle@268 512 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
seanhalle@268 513 }
seanhalle@268 514 #endif
seanhalle@268 515 HOLISTIC__Record_Assigner_end;
seanhalle@268 516 return;
seanhalle@268 517 }
seanhalle@268 518
seanhalle@268 519 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
seanhalle@260 520 {
seanhalle@268 521 HOLISTIC__Record_Assigner_end;
seanhalle@268 522 return;
seanhalle@267 523 }
seanhalle@267 524 }
seanhalle@268 525 */
seanhalle@267 526
seanhalle@261 527 inline
seanhalle@261 528 void
seanhalle@268 529 masterFunction_MultiLang( AnimSlot *slot )
seanhalle@261 530 { //Scan the animation slots
seanhalle@261 531 int32 magicNumber;
seanhalle@261 532 SlaveVP *slave;
seanhalle@268 533 PRLangEnv *langEnv;
seanhalle@261 534 PRReqst *req;
seanhalle@261 535 RequestHandler requestHandler;
seanhalle@268 536 PRProcess *process;
seanhalle@260 537
seanhalle@268 538 //Check if newly-done slave in slot, which will need request handled
seanhalle@268 539 if( slot->workIsDone )
seanhalle@268 540 { slot->workIsDone = FALSE;
seanhalle@268 541 slot->needsWorkAssigned = TRUE;
seanhalle@261 542
seanhalle@268 543 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@268 544 MEAS__startReqHdlr;
seanhalle@261 545
seanhalle@268 546
seanhalle@268 547 //process the request made by the slave (held inside slave struc)
seanhalle@268 548 slave = slot->slaveAssignedToSlot;
seanhalle@268 549 req = slave->request;
seanhalle@268 550
seanhalle@268 551 //If the requesting slave is a slot slave, and request is not
seanhalle@268 552 // task-end, then turn it into a free task slave.
seanhalle@268 553 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
seanhalle@268 554 PR_int__replace_with_new_slot_slv( slave );
seanhalle@268 555
seanhalle@268 556 //Handle task create and end first -- they're special cases..
seanhalle@268 557 switch( req->reqType )
seanhalle@268 558 { case TaskEnd:
seanhalle@268 559 { //do PR handler, which calls lang's hdlr and does recycle of
seanhalle@268 560 // free task slave if needed -- PR handler checks for free task Slv
seanhalle@268 561 PRHandle_EndTask( req, slave ); break;
seanhalle@267 562 }
seanhalle@268 563 case TaskCreate:
seanhalle@268 564 { //Do PR's create-task handler, which calls the lang's hdlr
seanhalle@268 565 // PR handler checks for free task Slv
seanhalle@268 566 PRHandle_CreateTask( req, slave ); break;
seanhalle@268 567 }
seanhalle@268 568 case SlvCreate: PRHandle_CreateSlave( req, slave ); break;
seanhalle@268 569 case SlvDissipate: PRHandle_Dissipate( req, slave ); break;
seanhalle@268 570 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own language env
seanhalle@268 571 case Hardware: //for future expansion
seanhalle@268 572 case IO: //for future expansion
seanhalle@268 573 case OSCall: //for future expansion
seanhalle@268 574 PR_int__throw_exception("Not implemented", slave, NULL); break;
seanhalle@268 575 case Language: //normal lang request
seanhalle@268 576 { magicNumber = req->langMagicNumber;
seanhalle@268 577 langEnv = PR_PI__give_lang_env_for( slave, magicNumber );
seanhalle@268 578 (*req->handler)( req->langReq, slave, langEnv );
seanhalle@268 579 }
seanhalle@268 580 }
seanhalle@261 581
seanhalle@268 582 MEAS__endReqHdlr;
seanhalle@267 583 HOLISTIC__Record_AppResponder_end;
seanhalle@268 584 } //if have request to be handled
seanhalle@268 585
seanhalle@268 586 if( slot->needsWorkAssigned )
seanhalle@268 587 {
seanhalle@268 588 HOLISTIC__Record_Assigner_start;
seanhalle@268 589
seanhalle@268 590 //Pick a process to get this slot
seanhalle@268 591 process = pickAProcess( slot );
seanhalle@268 592
seanhalle@268 593 //Scan lang environs, looking for langEnv with ready work.
seanhalle@268 594 // call the Assigner for that lang Env, to get a slave for the slot
seanhalle@268 595 assignWork( process, slot );
seanhalle@268 596
seanhalle@268 597 HOLISTIC__Record_Assigner_end;
seanhalle@268 598 }//if slot needs slave assigned
seanhalle@261 599 }
seanhalle@260 600
seanhalle@268 601 /*When several processes exist, use some pattern for picking one to give
seanhalle@268 602 * the animation slot to.
seanhalle@268 603 *First, it has to be a process that has work available.
seanhalle@268 604 *For now, just do a round-robin
seanhalle@261 605 */
seanhalle@268 606 inline
seanhalle@268 607 PRProcess *
seanhalle@268 608 pickAProcess( AnimSlot *slot )
seanhalle@268 609 { int32 idx;
seanhalle@268 610 PRProcess *process;
seanhalle@268 611
seanhalle@268 612 for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++)
seanhalle@268 613 {
seanhalle@268 614 process = _PRTopEnv->processes[ idx ];
seanhalle@268 615 if( process->numEnvsWithWork != 0 )
seanhalle@268 616 { _PRTopEnv->currProcessIdx = idx;
seanhalle@268 617 return process;
seanhalle@268 618 }
seanhalle@261 619 }
seanhalle@268 620 for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++)
seanhalle@268 621 {
seanhalle@268 622 process = _PRTopEnv->processes[ idx ];
seanhalle@268 623 if( process->numEnvsWithWork != 0 )
seanhalle@268 624 { _PRTopEnv->currProcessIdx = idx;
seanhalle@268 625 return process;
seanhalle@268 626 }
seanhalle@268 627 }
seanhalle@268 628 //none found
seanhalle@268 629 return NULL;
seanhalle@260 630 }
seanhalle@260 631
seanhalle@261 632 /*This does:
seanhalle@268 633 * 1) searches the language environments for one with work ready
seanhalle@261 634 * if finds one, asks its assigner to return work
seanhalle@261 635 * 2) checks what kind of work: new task, resuming task, resuming slave
seanhalle@261 636 * if new task, gets the slot slave and assigns task to it and returns slave
seanhalle@261 637 * else, gets the slave attached to the metaTask and returns that.
seanhalle@261 638 * 3) if no work found, then prune former task slaves waiting to be recycled.
seanhalle@261 639 * If no work and no slaves to prune, check for shutdown conditions.
seanhalle@261 640 *
seanhalle@268 641 * language env keeps its own work in its own structures, and has its own
seanhalle@261 642 * assigner. It chooses
seanhalle@261 643 * However, include a switch that switches-in an override assigner, which
seanhalle@268 644 * sees all the work in all the language env's. This is most likely
seanhalle@261 645 * generated by static tools and included in the executable. That means it
seanhalle@261 646 * has to be called via a registered pointer from here. The idea is that
seanhalle@261 647 * the static tools know which languages are grouped together.. and the
seanhalle@261 648 * override enables them to generate a custom assigner that uses info from
seanhalle@261 649 * all the languages in a unified way.. Don't really expect this to happen,
seanhalle@261 650 * but am making it possible.
seanhalle@260 651 */
seanhalle@268 652 inline
seanhalle@268 653 SlaveVP *
seanhalle@261 654 assignWork( PRProcess *process, AnimSlot *slot )
seanhalle@261 655 { SlaveVP *returnSlv;
seanhalle@261 656 int32 coreNum, slotNum;
seanhalle@267 657 PRMetaTask *assignedMetaTask;
seanhalle@260 658
seanhalle@261 659 coreNum = slot->coreSlotIsOn;
seanhalle@260 660
seanhalle@267 661 if( process->overrideAssigner != NULL )
seanhalle@268 662 { if( process->numEnvsWithWork != 0 )
seanhalle@268 663 { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot
seanhalle@268 664 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
seanhalle@261 665 }
seanhalle@268 666 else
seanhalle@261 667 goto NoWork;
seanhalle@261 668 }
seanhalle@261 669
seanhalle@268 670 //If here, then no override assigner, so search language envs for work
seanhalle@268 671 int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv;
seanhalle@268 672 langEnvsList = process->langEnvsList;
seanhalle@268 673 numEnvs = process->numLangEnvs;
seanhalle@268 674 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array
seanhalle@268 675 { langEnv = langEnvsList[envIdx];
seanhalle@268 676 if( langEnv->hasWork )
seanhalle@268 677 { (*langEnv->slaveAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot
seanhalle@268 678 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
seanhalle@268 679 //NOTE: bad search alg -- should start where left off, then wrap around
seanhalle@260 680 }
seanhalle@260 681 }
seanhalle@268 682 //If reach here, then have searched all langEnv's & none have work..
seanhalle@260 683
seanhalle@268 684 NoWork: //No work, if end up here..
seanhalle@260 685 {
seanhalle@260 686 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
seanhalle@268 687 returnSlv = process->idleSlv[coreNum][slotNum];
seanhalle@260 688
seanhalle@260 689 //things that would normally happen in resume(), but idle VPs
seanhalle@260 690 // never go there
seanhalle@261 691 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
seanhalle@260 692 Unit newU;
seanhalle@268 693 newU.vp = returnSlv->slaveNum;
seanhalle@261 694 newU.task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 695 addToListOfArrays(Unit,newU,process->unitList);
seanhalle@260 696
seanhalle@261 697 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
seanhalle@260 698 { Dependency newD; // to this one
seanhalle@268 699 newD.from_vp = returnSlv->slaveNum;
seanhalle@261 700 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
seanhalle@268 701 newD.to_vp = returnSlv->slaveNum;
seanhalle@261 702 newD.to_task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 703 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
seanhalle@260 704 }
seanhalle@268 705 #endif
seanhalle@268 706 HOLISTIC__Record_Assigner_end;
seanhalle@268 707 return;
seanhalle@260 708 }
seanhalle@268 709
seanhalle@268 710 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
seanhalle@268 711 {
seanhalle@268 712 HOLISTIC__Record_Assigner_end;
seanhalle@268 713 return;
seanhalle@260 714 }
seanhalle@260 715 }
seanhalle@260 716
seanhalle@260 717
seanhalle@268 718
seanhalle@268 719 /*This is first thing called when creating a slave.. it hands off to the
seanhalle@268 720 * langlet's creator, then adds updates of its own..
seanhalle@268 721 *
seanhalle@268 722 *There's a question of things like lang data, meta tasks, and such..
seanhalle@268 723 *In creator, only PR related things happen, and things for the langlet whose
seanhalle@261 724 * creator construct was used.
seanhalle@268 725 *
seanhalle@268 726 *Other langlets still get a chance to create langData -- but by registering a
seanhalle@268 727 * "createLangData" handler in the langEnv. When a construct of the langlet
seanhalle@268 728 * calls "PR__give_lang_data()", if there is no langData for that langlet,
seanhalle@268 729 * the PR will call the creator in the langlet's langEnv, place whatever it
seanhalle@268 730 * makes as the langData in that slave for that langlet, and return that langData
seanhalle@261 731 *
seanhalle@261 732 *So, as far as counting things, a langlet is only allowed to count creation
seanhalle@261 733 * of slaves it creates itself.. may have to change this later.. add a way for
seanhalle@261 734 * langlet to register a trigger Fn called each time a slave gets created..
seanhalle@261 735 * need more experience with what langlets will do at create time.. think Cilk
seanhalle@261 736 * has interesting create behavior.. not sure how that will differ in light
seanhalle@261 737 * of true tasks and langlet approach. Look at it after all done and start
seanhalle@261 738 * modifying the langs to be langlets..
seanhalle@261 739 *
seanhalle@261 740 *PR itself needs to create the slave, then update numLiveSlaves in process,
seanhalle@261 741 * copy processID from requestor to newly created
seanhalle@261 742 */
seanhalle@268 743 inline
seanhalle@268 744 void
seanhalle@268 745 PRHandle_CreateSlave( PRReqst *req, SlaveVP *slave )
seanhalle@268 746 { SlaveVP *newSlv;
seanhalle@261 747 PRProcess *process;
seanhalle@268 748 PRLangEnv *protoLangEnv;
seanhalle@261 749
seanhalle@268 750 process = slave->processSlaveIsIn;
seanhalle@268 751 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber );
seanhalle@268 752
seanhalle@268 753 // newSlv = PR_int__create_slave( req->topLevelFn, req->initData );
seanhalle@268 754
seanhalle@268 755 //create slv has diff prototype than standard reqst hdlr
seanhalle@268 756 newSlv =
seanhalle@268 757 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv));
seanhalle@268 758
seanhalle@261 759 newSlv->typeOfVP = GenericSlv;
seanhalle@261 760 newSlv->processSlaveIsIn = process;
seanhalle@268 761 newSlv->ID = req->ID;
seanhalle@266 762 process->numLiveGenericSlvs += 1;
seanhalle@260 763 }
seanhalle@260 764
seanhalle@268 765 /*The dissipate handler has to, update the number of slaves of the type, within
seanhalle@261 766 * the process, and call the langlet handler linked into the request,
seanhalle@261 767 * and after that returns, then call the PR function that frees the slave state
seanhalle@261 768 * (or recycles the slave).
seanhalle@261 769 *
seanhalle@261 770 *The PR function that frees the slave state has to also free all of the
seanhalle@268 771 * langData in the slave.. or else reset all of the langDatas.. by, say, marking
seanhalle@268 772 * them, then in PR__give_langData( magicNum ) call the langlet registered
seanhalle@268 773 * "resetLangData" Fn.
seanhalle@261 774 */
seanhalle@268 775 inline
seanhalle@268 776 void
seanhalle@268 777 PRHandle_Dissipate( PRReqst *req, SlaveVP *slave )
seanhalle@261 778 { PRProcess *process;
seanhalle@268 779 PRLangEnv *protoLangEnv;
seanhalle@261 780
seanhalle@261 781 process = slave->processSlaveIsIn;
seanhalle@261 782
seanhalle@261 783 //do the language's dissipate handler
seanhalle@268 784 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber );
seanhalle@268 785
seanhalle@268 786 if(req->handler != NULL)
seanhalle@268 787 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
seanhalle@261 788
seanhalle@266 789 process->numLiveGenericSlvs -= 1;
seanhalle@268 790 PR_int__recycle_slave__ML( slave );
seanhalle@267 791
seanhalle@261 792 //check End Of Process Condition
seanhalle@261 793 if( process->numLiveTasks == 0 &&
seanhalle@266 794 process->numLiveGenericSlvs == 0 )
seanhalle@268 795 PR_SS__shutdown_process__ML( process );
seanhalle@261 796 }
seanhalle@261 797
seanhalle@261 798 /*Create task is a special form, that has PR behavior in addition to plugin
seanhalle@268 799 * behavior. Master calls this first, and it then calls the plugin's
seanhalle@261 800 * create task handler.
seanhalle@267 801 *
seanhalle@267 802 *Note: the requesting slave must be either generic slave or free task slave
seanhalle@261 803 */
seanhalle@268 804 inline
seanhalle@268 805 void
seanhalle@268 806 PRHandle_CreateTask( PRReqst *req, SlaveVP *slave )
seanhalle@267 807 { PRMetaTask *metaTask;
seanhalle@267 808 PRProcess *process;
seanhalle@268 809 PRLangEnv *protoLangEnv;
seanhalle@268 810 void *task;
seanhalle@267 811
seanhalle@268 812 process = slave->processSlaveIsIn;
seanhalle@268 813
seanhalle@268 814 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave,
seanhalle@268 815 req->langMagicNumber );
seanhalle@268 816
seanhalle@268 817 //Do the langlet's create-task handler, which keeps the task
seanhalle@268 818 // inside the langlet's lang env, but returns the langMetaTask
seanhalle@268 819 // so PR can put stuff into the prolog
seanhalle@268 820 task =
seanhalle@268 821 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
seanhalle@268 822 metaTask = PR_int__give_prolog_of_task( task );
seanhalle@268 823 metaTask->ID = req->ID; //may be NULL
seanhalle@267 824 metaTask->topLevelFn = req->topLevelFn;
seanhalle@267 825 metaTask->initData = req->initData;
seanhalle@261 826
seanhalle@261 827 process->numLiveTasks += 1;
seanhalle@267 828
seanhalle@261 829 return;
seanhalle@261 830 }
seanhalle@261 831
seanhalle@261 832 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
seanhalle@261 833 * suspended at some point in its code.
seanhalle@261 834 *For 1, just decr count of live tasks (and check for end condition) -- the
seanhalle@261 835 * master loop will decide what goes into the slot freed up by this task end,
seanhalle@261 836 * so, here, don't worry about assigning a new task to the slot slave.
seanhalle@261 837 *For 2, the task's slot slave has been converted to a free task slave, which
seanhalle@261 838 * now has nothing more to do, so send it to the recycle Q (which includes
seanhalle@268 839 * freeing all the langData and meta task structs alloc'd for it). Then
seanhalle@261 840 * decrement the live task count and check end condition.
seanhalle@261 841 *
seanhalle@261 842 *PR has to update count of live tasks, and check end of process condition.
seanhalle@267 843 * The "main" can invoke constructs that wait for a process to end, so when
seanhalle@267 844 * end detected, have to resume what's waiting..
seanhalle@267 845 *Thing is, that wait involves the main OS thread. That means
seanhalle@261 846 * PR internals have to do OS thread signaling. Want to do that in the
seanhalle@267 847 * core controller, which has the original stack of an OS thread. So the
seanhalle@267 848 * end process handling happens in the core controller.
seanhalle@261 849 *
seanhalle@261 850 *So here, when detect process end, signal to the core controller, which will
seanhalle@267 851 * then do the condition variable notify to the OS thread that's waiting.
seanhalle@267 852 *
seanhalle@267 853 *Note: slave may be either a slot slave or a free task slave.
seanhalle@261 854 */
seanhalle@268 855 inline
seanhalle@268 856 void
seanhalle@268 857 PRHandle_EndTask( PRReqst *req, SlaveVP *requestingSlv )
seanhalle@268 858 { void *langEnv;
seanhalle@261 859 PRProcess *process;
seanhalle@268 860 void *langMetaTask;
seanhalle@267 861
seanhalle@268 862 langEnv = PR_int__give_lang_env_of_req__ML( req, requestingSlv ); //magic num in req
seanhalle@268 863 langMetaTask = PR_int__give_lang_meta_task_from_slave__ML( requestingSlv, req->langMagicNumber);
seanhalle@261 864
seanhalle@267 865 //Do the langlet's request handler
seanhalle@268 866 //Want to keep PR structs hidden from plugin, so extract langReq..
seanhalle@268 867 (*req->handler)( req->langReq, requestingSlv, langEnv );
seanhalle@267 868
seanhalle@267 869 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
seanhalle@267 870 if( requestingSlv->typeOfVP == FreeTaskSlv )
seanhalle@268 871 PR_int__recycle_slave__ML( requestingSlv );
seanhalle@261 872
seanhalle@261 873 process->numLiveTasks -= 1;
seanhalle@261 874
seanhalle@261 875 //check End Of Process Condition
seanhalle@261 876 if( process->numLiveTasks == 0 &&
seanhalle@266 877 process->numLiveGenericSlvs == 0 )
seanhalle@268 878 { //Tell the core controller to do wakeup of any waiting OS thread
seanhalle@268 879 PR_SS__shutdown_process__ML( process );
seanhalle@268 880 }
seanhalle@261 881 }
seanhalle@261 882