seanhalle@230: /* seanhalle@230: * Copyright 2010 OpenSourceStewardshipFoundation seanhalle@230: * seanhalle@230: * Licensed under BSD seanhalle@230: */ seanhalle@230: seanhalle@230: seanhalle@230: seanhalle@230: #include seanhalle@230: #include seanhalle@230: seanhalle@260: #include "PR.h" seanhalle@230: seanhalle@230: seanhalle@230: seanhalle@230: /*The animationMaster embodies most of the animator of the language. The seanhalle@230: * animator is what emodies the behavior of language constructs. seanhalle@230: * As such, it is the animationMaster, in combination with the plugin seanhalle@230: * functions, that make the language constructs do their behavior. seanhalle@230: * seanhalle@230: *Within the code, this is the top-level-function of the masterVPs, and seanhalle@230: * runs when the coreController has no more slave VPs. It's job is to seanhalle@260: * refill the animation slots with slaves that have work. seanhalle@230: * seanhalle@260: *There are multiple versions of the master, each tuned to a specific seanhalle@260: * combination of modes. This keeps the master simple, with reduced overhead, seanhalle@260: * when the application is not using the extra complexity. seanhalle@260: * seanhalle@260: *As of Sept 2012, the versions available will be: seanhalle@260: * 1) Single langauge, which only exposes slaves (such as SSR or Vthread) seanhalle@260: * 2) Single language, which only exposes tasks (such as pure dataflow) seanhalle@260: * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP) seanhalle@260: * 4) Multi-language, which always assumes both tasks and slaves seanhalle@260: * 5) Multi-language and multi-process, which also assumes both tasks and slaves seanhalle@260: * seanhalle@260: * seanhalle@260: * seanhalle@260: */ seanhalle@260: seanhalle@260: seanhalle@260: //===================== The versions of the Animation Master ================= seanhalle@260: // seanhalle@260: //============================================================================== seanhalle@260: seanhalle@260: /* 1) This version is for a single language, that has only slaves, no tasks, seanhalle@260: * such as Vthread or SSR. seanhalle@260: *This version is for when an application has only a single language, and seanhalle@260: * that language exposes slaves explicitly (as opposed to a task based seanhalle@260: * language like pure dataflow). seanhalle@260: * seanhalle@260: * seanhalle@260: *It scans the animation slots for just-completed slaves. seanhalle@260: * Each completed slave has a request in it. So, the master hands each to seanhalle@260: * the plugin's request handler (there is only one plugin, because only one seanhalle@260: * lang). seanhalle@230: *Each request represents a language construct that has been encountered seanhalle@230: * by the application code in the slave. Passing the request to the seanhalle@230: * request handler is how that language construct's behavior gets invoked. seanhalle@230: * The request handler then performs the actions of the construct's seanhalle@230: * behavior. So, the request handler encodes the behavior of the seanhalle@230: * language's parallelism constructs, and performs that when the master seanhalle@230: * hands it a slave containing a request to perform that construct. seanhalle@230: * seanhalle@230: *On a shared-memory machine, the behavior of parallelism constructs seanhalle@230: * equals control, over order of execution of code. Hence, the behavior seanhalle@230: * of the language constructs performed by the request handler is to seanhalle@230: * choose the order that slaves get animated, and thereby control the seanhalle@230: * order that application code in the slaves executes. seanhalle@230: * seanhalle@230: *To control order of animation of slaves, the request handler has a seanhalle@230: * semantic environment that holds data structures used to hold slaves seanhalle@230: * and choose when they're ready to be animated. seanhalle@230: * seanhalle@230: *Once a slave is marked as ready to be animated by the request handler, seanhalle@230: * it is the second plugin function, the Assigner, which chooses the core seanhalle@230: * the slave gets assigned to for animation. Hence, the Assigner doesn't seanhalle@230: * perform any of the semantic behavior of language constructs, rather seanhalle@230: * it gives the language a chance to improve performance. The performance seanhalle@230: * of application code is strongly related to communication between seanhalle@230: * cores. On shared-memory machines, communication is caused during seanhalle@230: * execution of code, by memory accesses, and how much depends on contents seanhalle@230: * of caches connected to the core executing the code. So, the placement seanhalle@230: * of slaves determines the communication caused during execution of the seanhalle@230: * slave's code. seanhalle@230: *The point of the Assigner, then, is to use application information during seanhalle@230: * execution of the program, to make choices about slave placement onto seanhalle@230: * cores, with the aim to put slaves close to caches containing the data seanhalle@230: * used by the slave's code. seanhalle@230: * seanhalle@230: *========================================================================== seanhalle@230: *In summary, the animationMaster scans the slots, finds slaves seanhalle@230: * just-finished, which hold requests, pass those to the request handler, seanhalle@230: * along with the semantic environment, and the request handler then manages seanhalle@230: * the structures in the semantic env, which controls the order of seanhalle@230: * animation of slaves, and so embodies the behavior of the language seanhalle@230: * constructs. seanhalle@230: *The animationMaster then rescans the slots, offering each empty one to seanhalle@230: * the Assigner, along with the semantic environment. The Assigner chooses seanhalle@230: * among the ready slaves in the semantic Env, finding the one best suited seanhalle@230: * to be animated by that slot's associated core. seanhalle@230: * seanhalle@230: *========================================================================== seanhalle@230: *Implementation Details: seanhalle@230: * seanhalle@230: *There is a separate masterVP for each core, but a single semantic seanhalle@230: * environment shared by all cores. Each core also has its own scheduling seanhalle@230: * slots, which are used to communicate slaves between animationMaster and seanhalle@260: * coreController. There is only one global variable, _PRMasterEnv, which seanhalle@230: * holds the semantic env and other things shared by the different seanhalle@230: * masterVPs. The request handler and Assigner are registered with seanhalle@230: * the animationMaster by the language's init function, and a pointer to seanhalle@260: * each is in the _PRMasterEnv. (There are also some pthread related global seanhalle@260: * vars, but they're only used during init of PR). seanhalle@260: *PR gains control over the cores by essentially "turning off" the OS's seanhalle@230: * scheduler, using pthread pin-to-core commands. seanhalle@230: * seanhalle@230: *The masterVPs are created during init, with this animationMaster as their seanhalle@230: * top level function. The masterVPs use the same SlaveVP data structure, seanhalle@230: * even though they're not slave VPs. seanhalle@230: *A "seed slave" is also created during init -- this is equivalent to the seanhalle@260: * "main" function in C, and acts as the entry-point to the PR-language- seanhalle@230: * based application. seanhalle@260: *The masterVPs share a single system-wide master-lock, so only one seanhalle@230: * masterVP may be animated at a time. seanhalle@260: *The core controllers access _PRMasterEnv to get the masterVP, and when seanhalle@230: * they start, the slots are all empty, so they run their associated core's seanhalle@230: * masterVP. The first of those to get the master lock sees the seed slave seanhalle@230: * in the shared semantic environment, so when it runs the Assigner, that seanhalle@230: * returns the seed slave, which the animationMaster puts into a scheduling seanhalle@230: * slot then switches to the core controller. That then switches the core seanhalle@230: * over to the seed slave, which then proceeds to execute language seanhalle@230: * constructs to create more slaves, and so on. Each of those constructs seanhalle@230: * causes the seed slave to suspend, switching over to the core controller, seanhalle@230: * which eventually switches to the masterVP, which executes the seanhalle@260: * request handler, which uses PR primitives to carry out the creation of seanhalle@230: * new slave VPs, which are marked as ready for the Assigner, and so on.. seanhalle@230: * seanhalle@230: *On animation slots, and system behavior: seanhalle@260: * A request may linger in an animation slot for a long time while seanhalle@230: * the slaves in the other slots are animated. This only becomes a problem seanhalle@230: * when such a request is a choke-point in the constraints, and is needed seanhalle@260: * to free work for *other* cores. To reduce this occurrence, the number seanhalle@230: * of animation slots should be kept low. In balance, having multiple seanhalle@230: * animation slots amortizes the overhead of switching to the masterVP and seanhalle@230: * executing the animationMaster code, which drives for more than one. In seanhalle@230: * practice, the best balance should be discovered by profiling. seanhalle@230: */ seanhalle@230: void animationMaster( void *initData, SlaveVP *masterVP ) seanhalle@230: { seanhalle@230: //Used while scanning and filling animation slots seanhalle@230: int32 slotIdx, numSlotsFilled; seanhalle@235: AnimSlot *currSlot, **animSlots; seanhalle@230: SlaveVP *assignedSlaveVP; //the slave chosen by the assigner seanhalle@230: seanhalle@230: //Local copies, for performance seanhalle@230: MasterEnv *masterEnv; seanhalle@230: SlaveAssigner slaveAssigner; seanhalle@230: RequestHandler requestHandler; seanhalle@230: void *semanticEnv; seanhalle@230: int32 thisCoresIdx; nengel@238: seanhalle@230: //======================== Initializations ======================== seanhalle@230: masterEnv = (MasterEnv*)_VMSMasterEnv; seanhalle@230: seanhalle@230: thisCoresIdx = masterVP->coreAnimatedBy; seanhalle@235: animSlots = masterEnv->allAnimSlots[thisCoresIdx]; seanhalle@230: seanhalle@230: requestHandler = masterEnv->requestHandler; seanhalle@230: slaveAssigner = masterEnv->slaveAssigner; seanhalle@230: semanticEnv = masterEnv->semanticEnv; nengel@238: nengel@238: HOLISTIC__Insert_Master_Global_Vars; seanhalle@230: seanhalle@230: //======================== animationMaster ======================== seanhalle@230: while(1){ seanhalle@230: seanhalle@230: MEAS__Capture_Pre_Master_Point seanhalle@230: seanhalle@230: //Scan the animation slots seanhalle@230: numSlotsFilled = 0; seanhalle@236: for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) seanhalle@230: { seanhalle@235: currSlot = animSlots[ slotIdx ]; seanhalle@230: nengel@239: //Check if newly-done slave in slot, which will need request handled seanhalle@230: if( currSlot->workIsDone ) seanhalle@230: { seanhalle@230: currSlot->workIsDone = FALSE; seanhalle@230: currSlot->needsSlaveAssigned = TRUE; nengel@238: nengel@238: HOLISTIC__Record_AppResponder_start; seanhalle@230: MEAS__startReqHdlr; seanhalle@230: seanhalle@260: currSlot->workIsDone = FALSE; seanhalle@260: currSlot->needsSlaveAssigned = TRUE; seanhalle@260: SlaveVP *currSlave = currSlot->slaveAssignedToSlot; seanhalle@260: seanhalle@260: justAddedReqHdlrChg(); seanhalle@260: //handle the request, either by VMS or by the language seanhalle@260: if( currSlave->requests->reqType != LangReq ) seanhalle@260: { //The request is a standard VMS one, not one defined by the seanhalle@260: // language, so VMS handles it, then queues slave to be assigned seanhalle@260: handleReqInVMS( currSlave ); seanhalle@260: writePrivQ( currSlave, VMSReadyQ ); //Q slave to be assigned below seanhalle@260: } seanhalle@260: else seanhalle@260: { MEAS__startReqHdlr; seanhalle@260: seanhalle@260: //Language handles request, which is held inside slave struc seanhalle@260: (*requestHandler)( currSlave, semanticEnv ); seanhalle@260: seanhalle@260: MEAS__endReqHdlr; seanhalle@260: } seanhalle@260: } seanhalle@260: seanhalle@260: //process the requests made by the slave (held inside slave struc) seanhalle@230: (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv ); seanhalle@230: nengel@238: HOLISTIC__Record_AppResponder_end; seanhalle@230: MEAS__endReqHdlr; seanhalle@230: } seanhalle@230: //If slot empty, hand to Assigner to fill with a slave seanhalle@230: if( currSlot->needsSlaveAssigned ) seanhalle@230: { //Call plugin's Assigner to give slot a new slave nengel@238: HOLISTIC__Record_Assigner_start; seanhalle@230: assignedSlaveVP = seanhalle@230: (*slaveAssigner)( semanticEnv, currSlot ); seanhalle@230: seanhalle@230: //put the chosen slave into slot, and adjust flags and state seanhalle@230: if( assignedSlaveVP != NULL ) seanhalle@230: { currSlot->slaveAssignedToSlot = assignedSlaveVP; seanhalle@235: assignedSlaveVP->animSlotAssignedTo = currSlot; seanhalle@230: currSlot->needsSlaveAssigned = FALSE; seanhalle@230: numSlotsFilled += 1; nengel@238: nengel@238: HOLISTIC__Record_Assigner_end; seanhalle@230: } seanhalle@230: } seanhalle@230: } seanhalle@230: seanhalle@230: MEAS__Capture_Post_Master_Point; seanhalle@230: seanhalle@231: masterSwitchToCoreCtlr( masterVP ); seanhalle@230: flushRegisters(); seanhalle@235: DEBUG__printf(FALSE,"came back after switch to core -- so lock released!"); seanhalle@232: }//while(1) seanhalle@230: } seanhalle@230: seanhalle@260: seanhalle@260: /* 2) This version is for a single language that has only tasks, which seanhalle@260: * cannot be suspended. seanhalle@260: */ seanhalle@260: void animationMaster( void *initData, SlaveVP *masterVP ) seanhalle@260: { seanhalle@260: //Used while scanning and filling animation slots seanhalle@260: int32 slotIdx, numSlotsFilled; seanhalle@260: AnimSlot *currSlot, **animSlots; seanhalle@260: SlaveVP *assignedSlaveVP; //the slave chosen by the assigner seanhalle@260: seanhalle@260: //Local copies, for performance seanhalle@260: MasterEnv *masterEnv; seanhalle@260: SlaveAssigner slaveAssigner; seanhalle@260: RequestHandler requestHandler; seanhalle@260: PRSemEnv *semanticEnv; seanhalle@260: int32 thisCoresIdx; seanhalle@260: seanhalle@260: //#ifdef MODE__MULTI_LANG seanhalle@260: SlaveVP *slave; seanhalle@260: PRProcess *process; seanhalle@260: PRConstrEnvHolder *constrEnvHolder; seanhalle@260: int32 langMagicNumber; seanhalle@260: //#endif seanhalle@260: seanhalle@260: //======================== Initializations ======================== seanhalle@260: masterEnv = (MasterEnv*)_PRMasterEnv; seanhalle@260: seanhalle@260: thisCoresIdx = masterVP->coreAnimatedBy; seanhalle@260: animSlots = masterEnv->allAnimSlots[thisCoresIdx]; seanhalle@260: seanhalle@260: requestHandler = masterEnv->requestHandler; seanhalle@260: slaveAssigner = masterEnv->slaveAssigner; seanhalle@260: semanticEnv = masterEnv->semanticEnv; seanhalle@260: seanhalle@260: //initialize, for non-multi-lang, non multi-proc case seanhalle@260: // default handler gets put into master env by a registration call by lang seanhalle@260: endTaskHandler = masterEnv->defaultTaskHandler; seanhalle@260: seanhalle@260: HOLISTIC__Insert_Master_Global_Vars; seanhalle@260: seanhalle@260: //======================== animationMaster ======================== seanhalle@260: //Do loop gets requests handled and work assigned to slots.. seanhalle@260: // work can either be a task or a resumed slave seanhalle@260: //Having two cases makes this logic complex.. can be finishing either, and seanhalle@260: // then the next available work may be either.. so really have two distinct seanhalle@260: // loops that are inter-twined.. seanhalle@260: while(1){ seanhalle@260: seanhalle@260: MEAS__Capture_Pre_Master_Point seanhalle@260: seanhalle@260: //Scan the animation slots seanhalle@260: numSlotsFilled = 0; seanhalle@260: for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) seanhalle@260: { seanhalle@260: currSlot = animSlots[ slotIdx ]; seanhalle@260: seanhalle@260: //Check if newly-done slave in slot, which will need request handled seanhalle@260: if( currSlot->workIsDone ) seanhalle@260: { currSlot->workIsDone = FALSE; seanhalle@260: seanhalle@260: HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot seanhalle@260: MEAS__startReqHdlr; seanhalle@260: seanhalle@260: seanhalle@260: //process the request made by the slave (held inside slave struc) seanhalle@260: slave = currSlot->slaveAssignedToSlot; seanhalle@260: seanhalle@260: //check if the completed work was a task.. seanhalle@260: if( slave->taskMetaInfo->isATask ) seanhalle@260: { seanhalle@260: if( slave->reqst->type == TaskEnd ) seanhalle@260: { //do task end handler, which is registered separately seanhalle@260: //note, end hdlr may use semantic data from reqst.. seanhalle@260: //#ifdef MODE__MULTI_LANG seanhalle@260: //get end-task handler seanhalle@260: //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); seanhalle@260: taskEndHandler = slave->taskMetaInfo->endTaskHandler; seanhalle@260: //#endif seanhalle@260: (*taskEndHandler)( slave, semanticEnv ); seanhalle@260: seanhalle@260: goto AssignWork; seanhalle@260: } seanhalle@260: else //is a task, and just suspended seanhalle@260: { //turn slot slave into free task slave & make replacement seanhalle@260: if( slave->typeOfVP == TaskSlotSlv ) changeSlvType(); seanhalle@260: seanhalle@260: //goto normal slave request handling seanhalle@260: goto SlaveReqHandling; seanhalle@260: } seanhalle@260: } seanhalle@260: else //is a slave that suspended seanhalle@260: { seanhalle@260: SlaveReqHandling: seanhalle@260: (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) seanhalle@260: seanhalle@260: HOLISTIC__Record_AppResponder_end; seanhalle@260: MEAS__endReqHdlr; seanhalle@260: seanhalle@260: goto AssignWork; seanhalle@260: } seanhalle@260: } //if has suspended slave that needs handling seanhalle@260: seanhalle@260: //if slot empty, hand to Assigner to fill with a slave seanhalle@260: if( currSlot->needsSlaveAssigned ) seanhalle@260: { //Call plugin's Assigner to give slot a new slave seanhalle@260: HOLISTIC__Record_Assigner_start; seanhalle@260: seanhalle@260: AssignWork: seanhalle@260: seanhalle@260: assignedSlaveVP = assignWork( semanticEnv, currSlot ); seanhalle@260: seanhalle@260: //put the chosen slave into slot, and adjust flags and state seanhalle@260: if( assignedSlaveVP != NULL ) seanhalle@260: { currSlot->slaveAssignedToSlot = assignedSlaveVP; seanhalle@260: assignedSlaveVP->animSlotAssignedTo = currSlot; seanhalle@260: currSlot->needsSlaveAssigned = FALSE; seanhalle@260: numSlotsFilled += 1; seanhalle@260: } seanhalle@260: else seanhalle@260: { seanhalle@260: currSlot->needsSlaveAssigned = TRUE; //local write seanhalle@260: } seanhalle@260: HOLISTIC__Record_Assigner_end; seanhalle@260: }//if slot needs slave assigned seanhalle@260: }//for( slotIdx.. seanhalle@260: seanhalle@260: MEAS__Capture_Post_Master_Point; seanhalle@260: seanhalle@260: masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master seanhalle@260: flushRegisters(); seanhalle@260: }//while(1) seanhalle@260: } seanhalle@260: seanhalle@260: seanhalle@260: /*This is the master when just multi-lang, but not multi-process mode is on. seanhalle@260: * This version has to handle both tasks and slaves, and do extra work of seanhalle@260: * looking up the semantic env and handlers to use, for each completed bit of seanhalle@260: * work. seanhalle@260: *It also has to search through the semantic envs to find one with work, seanhalle@260: * then ask that env's assigner to return a unit of that work. seanhalle@260: * seanhalle@260: *The language is written to startup in the same way as if it were the only seanhalle@260: * language in the app, and it operates in the same way, seanhalle@260: * the only difference between single language and multi-lang is here, in the seanhalle@260: * master. seanhalle@260: *This invisibility to mode is why the language has to use registration calls seanhalle@260: * for everything during startup -- those calls do different things depending seanhalle@260: * on whether it's single-language or multi-language mode. seanhalle@260: * seanhalle@260: *In this version of the master, work can either be a task or a resumed slave seanhalle@260: *Having two cases makes this logic complex.. can be finishing either, and seanhalle@260: * then the next available work may be either.. so really have two distinct seanhalle@260: * loops that are inter-twined.. seanhalle@260: * seanhalle@260: *Some special cases: seanhalle@260: * A task-end is a special case for a few reasons (below). seanhalle@260: * A task-end can't block a slave (can't cause it to "logically suspend") seanhalle@260: * A task available for work can only be assigned to a special slave, which seanhalle@260: * has been set aside for doing tasks, one such task-slave is always seanhalle@260: * assigned to each slot. So, when a task ends, a new task is assigned to seanhalle@260: * that slot's task-slave right away. seanhalle@260: * But if no tasks are available, then have to switch over to looking at seanhalle@260: * slaves to find one ready to resume, to find work for the slot. seanhalle@260: * If a task just suspends, not ends, then its task-slave is no longer seanhalle@260: * available to take new tasks, so a new task-slave has to be assigned to seanhalle@260: * that slot. Then the slave of the suspended task is turned into a free seanhalle@260: * task-slave and request handling is done on it as if it were a slave seanhalle@260: * that suspended. seanhalle@260: * After request handling, do the same sequence of looking for a task to be seanhalle@260: * work, and if none, look for a slave ready to resume, as work for the slot. seanhalle@260: * If a slave suspends, handle its request, then look for work.. first for a seanhalle@260: * task to assign, and if none, slaves ready to resume. seanhalle@260: * Another special case is when task-end is done on a free task-slave.. in seanhalle@260: * that case, the slave has no more work and no way to get more.. so place seanhalle@260: * it into a recycle queue. seanhalle@260: * If no work is found of either type, then do a special thing to prune down seanhalle@260: * the extra slaves in the recycle queue, just so don't get too many.. seanhalle@260: * seanhalle@260: *The multi-lang thing complicates matters.. seanhalle@260: * seanhalle@260: *For request handling, it means have to first fetch the semantic environment seanhalle@260: * of the language, and then do the request handler pointed to by that seanhalle@260: * semantic env. seanhalle@260: *For assigning, things get more complex because of competing goals.. One seanhalle@260: * goal is for language specific stuff to be used during assignment, so seanhalle@260: * assigner can make higher quality decisions.. but with multiple languages, seanhalle@260: * which only get mixed in the application, the assigners can't be written seanhalle@260: * with knowledge of each other. So, they can only make localized decisions, seanhalle@260: * and so different language's assigners may interfere with each other.. seanhalle@260: * seanhalle@260: *So, have some possibilities available: seanhalle@260: *1) can have a fixed scheduler in the proto-runtime, that all the seanhalle@260: * languages give their work to.. (but then lose language-specific info, seanhalle@260: * there is a standard PR format for assignment info, and the langauge seanhalle@260: * attaches this to the work-unit when it gives it to PR.. also have issue seanhalle@260: * with HWSim, which uses a priority Q instead of FIFO, and requests can seanhalle@260: * "undo" previous work put in, so request handlers need way to manipulate seanhalle@260: * the work-holding Q..) (this might be fudgeable with seanhalle@260: * HWSim, if the master did a lang-supplied callback each time it assigns a seanhalle@260: * unit to a slot.. then HWSim can keep exactly one unit of work in PR's seanhalle@260: * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies seanhalle@260: * a task-end handler that kicks the next unit of work from HWSim internal seanhalle@260: * priority queue, over to PR readyQ) seanhalle@260: *2) can have each language have its own semantic env, that holds its own seanhalle@260: * work, which is assigned by its own assigner.. then the master searches seanhalle@260: * through all the semantic envs to find one with work and asks it give work.. seanhalle@260: * (this has downside of blinding assigners to each other.. but does work seanhalle@260: * for HWSim case) seanhalle@260: *3) could make PR have a different readyQ for each core, and ask the lang seanhalle@260: * to put work to the core it prefers.. but the work may be moved by PR if seanhalle@260: * needed, say if one core idles for too long. This is a hybrid approach, seanhalle@260: * letting the language decide which core, but PR keeps the work and does it seanhalle@260: * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion, seanhalle@260: * but it would be complicated by having to track cores separately) seanhalle@260: * seanhalle@260: *Choosing 2, to keep compatibility with single-lang mode.. it allows the same seanhalle@260: * assigner to be used for single-lang as for multi-lang.. the overhead of seanhalle@260: * the extra master search for work is part of the price of the flexibility, seanhalle@260: * but should be fairly small.. takes the first env that has work available, seanhalle@260: * and whatever it returns is assigned to the slot.. seanhalle@260: * seanhalle@260: *As a hybrid, giving an option for a unified override assigner to be registered seanhalle@260: * and used.. This allows something like a static analysis to detect seanhalle@260: * which languages are grouped together, and then analyze the pattern of seanhalle@260: * construct calls, and generate a custom assigner that uses info from all seanhalle@260: * the languages in a unified way.. Don't really expect this to happen, seanhalle@260: * but making it possible. seanhalle@260: */ seanhalle@260: #ifdef MODE__MULTI_LANG seanhalle@260: void animationMaster( void *initData, SlaveVP *masterVP ) seanhalle@260: { seanhalle@260: //Used while scanning and filling animation slots seanhalle@260: int32 slotIdx, numSlotsFilled; seanhalle@260: AnimSlot *currSlot, **animSlots; seanhalle@260: SlaveVP *assignedSlaveVP; //the slave chosen by the assigner seanhalle@260: seanhalle@260: //Local copies, for performance seanhalle@260: MasterEnv *masterEnv; seanhalle@260: SlaveAssigner slaveAssigner; seanhalle@260: RequestHandler requestHandler; seanhalle@260: PRSemEnv *semanticEnv; seanhalle@260: int32 thisCoresIdx; seanhalle@260: seanhalle@260: //#ifdef MODE__MULTI_LANG seanhalle@260: SlaveVP *slave; seanhalle@260: PRProcess *process; seanhalle@260: PRConstrEnvHolder *constrEnvHolder; seanhalle@260: int32 langMagicNumber; seanhalle@260: //#endif seanhalle@260: seanhalle@260: //======================== Initializations ======================== seanhalle@260: masterEnv = (MasterEnv*)_PRMasterEnv; seanhalle@260: seanhalle@260: thisCoresIdx = masterVP->coreAnimatedBy; seanhalle@260: animSlots = masterEnv->allAnimSlots[thisCoresIdx]; seanhalle@260: seanhalle@260: requestHandler = masterEnv->requestHandler; seanhalle@260: slaveAssigner = masterEnv->slaveAssigner; seanhalle@260: semanticEnv = masterEnv->semanticEnv; seanhalle@260: seanhalle@260: //initialize, for non-multi-lang, non multi-proc case seanhalle@260: // default handler gets put into master env by a registration call by lang seanhalle@260: endTaskHandler = masterEnv->defaultTaskHandler; seanhalle@260: seanhalle@260: HOLISTIC__Insert_Master_Global_Vars; seanhalle@260: seanhalle@260: //======================== animationMaster ======================== seanhalle@260: //Do loop gets requests handled and work assigned to slots.. seanhalle@260: // work can either be a task or a resumed slave seanhalle@260: //Having two cases makes this logic complex.. can be finishing either, and seanhalle@260: // then the next available work may be either.. so really have two distinct seanhalle@260: // loops that are inter-twined.. seanhalle@260: while(1){ seanhalle@260: seanhalle@260: MEAS__Capture_Pre_Master_Point seanhalle@260: seanhalle@260: //Scan the animation slots seanhalle@260: numSlotsFilled = 0; seanhalle@260: for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) seanhalle@260: { seanhalle@260: currSlot = animSlots[ slotIdx ]; seanhalle@260: seanhalle@260: //Check if newly-done slave in slot, which will need request handled seanhalle@260: if( currSlot->workIsDone ) seanhalle@260: { currSlot->workIsDone = FALSE; seanhalle@260: seanhalle@260: HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot seanhalle@260: MEAS__startReqHdlr; seanhalle@260: seanhalle@260: seanhalle@260: //process the request made by the slave (held inside slave struc) seanhalle@260: slave = currSlot->slaveAssignedToSlot; seanhalle@260: seanhalle@260: //check if the completed work was a task.. seanhalle@260: if( slave->taskMetaInfo->isATask ) seanhalle@260: { seanhalle@260: if( slave->reqst->type == TaskEnd ) seanhalle@260: { //do task end handler, which is registered separately seanhalle@260: //note, end hdlr may use semantic data from reqst.. seanhalle@260: //#ifdef MODE__MULTI_LANG seanhalle@260: //get end-task handler seanhalle@260: //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); seanhalle@260: taskEndHandler = slave->taskMetaInfo->endTaskHandler; seanhalle@260: //#endif seanhalle@260: (*taskEndHandler)( slave, semanticEnv ); seanhalle@260: seanhalle@260: goto AssignWork; seanhalle@260: } seanhalle@260: else //is a task, and just suspended seanhalle@260: { //turn slot slave into free task slave & make replacement seanhalle@260: if( slave->typeOfVP == TaskSlotSlv ) changeSlvType(); seanhalle@260: seanhalle@260: //goto normal slave request handling seanhalle@260: goto SlaveReqHandling; seanhalle@260: } seanhalle@260: } seanhalle@260: else //is a slave that suspended seanhalle@260: { seanhalle@260: SlaveReqHandling: seanhalle@260: (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) seanhalle@260: seanhalle@260: HOLISTIC__Record_AppResponder_end; seanhalle@260: MEAS__endReqHdlr; seanhalle@260: seanhalle@260: goto AssignWork; seanhalle@260: } seanhalle@260: } //if has suspended slave that needs handling seanhalle@260: seanhalle@260: //if slot empty, hand to Assigner to fill with a slave seanhalle@260: if( currSlot->needsSlaveAssigned ) seanhalle@260: { //Call plugin's Assigner to give slot a new slave seanhalle@260: HOLISTIC__Record_Assigner_start; seanhalle@260: seanhalle@260: AssignWork: seanhalle@260: seanhalle@260: assignedSlaveVP = assignWork( semanticEnv, currSlot ); seanhalle@260: seanhalle@260: //put the chosen slave into slot, and adjust flags and state seanhalle@260: if( assignedSlaveVP != NULL ) seanhalle@260: { currSlot->slaveAssignedToSlot = assignedSlaveVP; seanhalle@260: assignedSlaveVP->animSlotAssignedTo = currSlot; seanhalle@260: currSlot->needsSlaveAssigned = FALSE; seanhalle@260: numSlotsFilled += 1; seanhalle@260: } seanhalle@260: else seanhalle@260: { seanhalle@260: currSlot->needsSlaveAssigned = TRUE; //local write seanhalle@260: } seanhalle@260: HOLISTIC__Record_Assigner_end; seanhalle@260: }//if slot needs slave assigned seanhalle@260: }//for( slotIdx.. seanhalle@260: seanhalle@260: MEAS__Capture_Post_Master_Point; seanhalle@260: seanhalle@260: masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master seanhalle@260: flushRegisters(); seanhalle@260: }//while(1) seanhalle@260: } seanhalle@260: #endif //MODE__MULTI_LANG seanhalle@260: seanhalle@260: seanhalle@260: seanhalle@260: //This is the master when both multi-lang and multi-process modes are turned on seanhalle@260: //#ifdef MODE__MULTI_LANG seanhalle@260: //#ifdef MODE__MULTI_PROCESS seanhalle@260: void animationMaster( void *initData, SlaveVP *masterVP ) seanhalle@260: { seanhalle@260: //Used while scanning and filling animation slots seanhalle@260: int32 slotIdx, numSlotsFilled; seanhalle@260: AnimSlot *currSlot, **animSlots; seanhalle@260: SlaveVP *assignedSlaveVP; //the slave chosen by the assigner seanhalle@260: seanhalle@260: //Local copies, for performance seanhalle@260: MasterEnv *masterEnv; seanhalle@260: SlaveAssigner slaveAssigner; seanhalle@260: RequestHandler requestHandler; seanhalle@260: PRSemEnv *semanticEnv; seanhalle@260: int32 thisCoresIdx; seanhalle@260: seanhalle@260: SlaveVP *slave; seanhalle@260: PRProcess *process; seanhalle@260: PRConstrEnvHolder *constrEnvHolder; seanhalle@260: int32 langMagicNumber; seanhalle@260: seanhalle@260: //======================== Initializations ======================== seanhalle@260: masterEnv = (MasterEnv*)_PRMasterEnv; seanhalle@260: seanhalle@260: thisCoresIdx = masterVP->coreAnimatedBy; seanhalle@260: animSlots = masterEnv->allAnimSlots[thisCoresIdx]; seanhalle@260: seanhalle@260: requestHandler = masterEnv->requestHandler; seanhalle@260: slaveAssigner = masterEnv->slaveAssigner; seanhalle@260: semanticEnv = masterEnv->semanticEnv; seanhalle@260: seanhalle@260: //initialize, for non-multi-lang, non multi-proc case seanhalle@260: // default handler gets put into master env by a registration call by lang seanhalle@260: endTaskHandler = masterEnv->defaultTaskHandler; seanhalle@260: seanhalle@260: HOLISTIC__Insert_Master_Global_Vars; seanhalle@260: seanhalle@260: //======================== animationMaster ======================== seanhalle@260: //Do loop gets requests handled and work assigned to slots.. seanhalle@260: // work can either be a task or a resumed slave seanhalle@260: //Having two cases makes this logic complex.. can be finishing either, and seanhalle@260: // then the next available work may be either.. so really have two distinct seanhalle@260: // loops that are inter-twined.. seanhalle@260: while(1){ seanhalle@260: seanhalle@260: MEAS__Capture_Pre_Master_Point seanhalle@260: seanhalle@260: //Scan the animation slots seanhalle@260: numSlotsFilled = 0; seanhalle@260: for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) seanhalle@260: { seanhalle@260: currSlot = animSlots[ slotIdx ]; seanhalle@260: seanhalle@260: //Check if newly-done slave in slot, which will need request handled seanhalle@260: if( currSlot->workIsDone ) seanhalle@260: { currSlot->workIsDone = FALSE; seanhalle@260: seanhalle@260: HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot seanhalle@260: MEAS__startReqHdlr; seanhalle@260: seanhalle@260: seanhalle@260: //process the request made by the slave (held inside slave struc) seanhalle@260: slave = currSlot->slaveAssignedToSlot; seanhalle@260: seanhalle@260: //check if the completed work was a task.. seanhalle@260: if( slave->taskMetaInfo->isATask ) seanhalle@260: { seanhalle@260: if( slave->reqst->type == TaskEnd ) seanhalle@260: { //do task end handler, which is registered separately seanhalle@260: //note, end hdlr may use semantic data from reqst.. seanhalle@260: //get end-task handler seanhalle@260: //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); seanhalle@260: taskEndHandler = slave->taskMetaInfo->endTaskHandler; seanhalle@260: seanhalle@260: (*taskEndHandler)( slave, semanticEnv ); seanhalle@260: seanhalle@260: goto AssignWork; seanhalle@260: } seanhalle@260: else //is a task, and just suspended seanhalle@260: { //turn slot slave into free task slave & make replacement seanhalle@260: if( slave->typeOfVP == TaskSlotSlv ) changeSlvType(); seanhalle@260: seanhalle@260: //goto normal slave request handling seanhalle@260: goto SlaveReqHandling; seanhalle@260: } seanhalle@260: } seanhalle@260: else //is a slave that suspended seanhalle@260: { seanhalle@260: seanhalle@260: SlaveReqHandling: seanhalle@260: (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) seanhalle@260: seanhalle@260: HOLISTIC__Record_AppResponder_end; seanhalle@260: MEAS__endReqHdlr; seanhalle@260: seanhalle@260: goto AssignWork; seanhalle@260: } seanhalle@260: } //if has suspended slave that needs handling seanhalle@260: seanhalle@260: //if slot empty, hand to Assigner to fill with a slave seanhalle@260: if( currSlot->needsSlaveAssigned ) seanhalle@260: { //Scan sem environs, looking for one with ready work. seanhalle@260: // call the Assigner for that sem Env, to give slot a new slave seanhalle@260: HOLISTIC__Record_Assigner_start; seanhalle@260: seanhalle@260: AssignWork: seanhalle@260: seanhalle@260: assignedSlaveVP = assignWork( semanticEnv, currSlot ); seanhalle@260: seanhalle@260: //put the chosen slave into slot, and adjust flags and state seanhalle@260: if( assignedSlaveVP != NULL ) seanhalle@260: { currSlot->slaveAssignedToSlot = assignedSlaveVP; seanhalle@260: assignedSlaveVP->animSlotAssignedTo = currSlot; seanhalle@260: currSlot->needsSlaveAssigned = FALSE; seanhalle@260: numSlotsFilled += 1; seanhalle@260: } seanhalle@260: else seanhalle@260: { seanhalle@260: currSlot->needsSlaveAssigned = TRUE; //local write seanhalle@260: } seanhalle@260: HOLISTIC__Record_Assigner_end; seanhalle@260: }//if slot needs slave assigned seanhalle@260: }//for( slotIdx.. seanhalle@260: seanhalle@260: MEAS__Capture_Post_Master_Point; seanhalle@260: seanhalle@260: masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master seanhalle@260: flushRegisters(); seanhalle@260: }//while(1) seanhalle@260: } seanhalle@260: #endif //MODE__MULTI_LANG seanhalle@260: #endif //MODE__MULTI_PROCESS seanhalle@260: seanhalle@260: seanhalle@260: /*This does three things: seanhalle@260: * 1) ask for a slave ready to resume seanhalle@260: * 2) if none, then ask for a task, and assign to the slot slave seanhalle@260: * 3) if none, then prune former task slaves waiting to be recycled. seanhalle@260: * seanhalle@260: //Have two separate assigners in each semantic env, seanhalle@260: // which keeps its own work in its own structures.. the master, here, seanhalle@260: // searches through the semantic environs, takes the first that has work seanhalle@260: // available, and whatever it returns is assigned to the slot.. seanhalle@260: //However, also have an override assigner.. because static analysis tools know seanhalle@260: // which languages are grouped together.. and the override enables them to seanhalle@260: // generate a custom assigner that uses info from all the languages in a seanhalle@260: // unified way.. Don't really expect this to happen, but making it possible. seanhalle@260: */ seanhalle@260: inline SlaveVP * seanhalle@260: assignWork( PRProcessEnv *processEnv, AnimSlot *slot ) seanhalle@260: { SlaveVP *returnSlv; seanhalle@260: //VSsSemEnv *semEnv; seanhalle@260: //VSsSemData *semData; seanhalle@260: int32 coreNum, slotNum; seanhalle@260: PRTaskMetaInfo *newTaskStub; seanhalle@260: SlaveVP *freeTaskSlv; seanhalle@260: seanhalle@260: seanhalle@260: //master has to handle slot slaves.. so either assigner returns seanhalle@260: // taskMetaInfo or else two assigners, one for slaves, other for tasks.. seanhalle@260: semEnvs = processEnv->semEnvs; seanhalle@260: numEnvs = processEnv->numSemEnvs; seanhalle@260: for( envIdx = 0; envIdx < numEnvs; envIdx++ ) seanhalle@260: { semEnv = semEnvs[envIdx]; seanhalle@260: if( semEnv->hasWork ) seanhalle@260: { assigner = semEnv->assigner; seanhalle@260: retTaskMetaInfo = (*assigner)( semEnv, slot ); seanhalle@260: seanhalle@260: return retTaskMetaInfo; //quit, have work seanhalle@260: } seanhalle@260: } seanhalle@260: seanhalle@260: coreNum = slot->coreSlotIsOn; seanhalle@260: slotNum = slot->slotIdx; seanhalle@260: seanhalle@260: //first try to get a ready slave seanhalle@260: returnSlv = getReadySlave(); seanhalle@260: seanhalle@260: if( returnSlv != NULL ) seanhalle@260: { returnSlv->coreAnimatedBy = coreNum; seanhalle@260: seanhalle@260: //have work, so reset Done flag (when work generated on other core) seanhalle@260: if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf seanhalle@260: processEnv->coreIsDone[coreNum] = FALSE; //don't just write always seanhalle@260: seanhalle@260: goto ReturnTheSlv; seanhalle@260: } seanhalle@260: seanhalle@260: //were no slaves, so try to get a ready task.. seanhalle@260: newTaskStub = getTaskStub(); seanhalle@260: seanhalle@260: if( newTaskStub != NULL ) seanhalle@260: { seanhalle@260: //get the slot slave to assign the task to.. seanhalle@260: returnSlv = processEnv->slotTaskSlvs[coreNum][slotNum]; seanhalle@260: seanhalle@260: //point slave to task's function, and mark slave as having task seanhalle@260: PR_int__reset_slaveVP_to_TopLvlFn( returnSlv, seanhalle@260: newTaskStub->taskType->fn, newTaskStub->args ); seanhalle@260: returnSlv->taskStub = newTaskStub; seanhalle@260: newTaskStub->slaveAssignedTo = returnSlv; seanhalle@260: returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type seanhalle@260: seanhalle@260: //have work, so reset Done flag, if was set seanhalle@260: if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf seanhalle@260: processEnv->coreIsDone[coreNum] = FALSE; //don't just write always seanhalle@260: seanhalle@260: goto ReturnTheSlv; seanhalle@260: } seanhalle@260: else seanhalle@260: { //no task, so prune the recycle pool of free task slaves seanhalle@260: freeTaskSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ ); seanhalle@260: if( freeTaskSlv != NULL ) seanhalle@260: { //delete to bound the num extras, and deliver shutdown cond seanhalle@260: handleDissipate( freeTaskSlv, processEnv ); seanhalle@260: //then return NULL seanhalle@260: returnSlv = NULL; seanhalle@260: seanhalle@260: goto ReturnTheSlv; seanhalle@260: } seanhalle@260: else seanhalle@260: { //candidate for shutdown.. if all extras dissipated, and no tasks seanhalle@260: // and no ready to resume slaves, then no way to generate seanhalle@260: // more tasks (on this core -- other core might have task still) seanhalle@260: if( processEnv->numLiveExtraTaskSlvs == 0 && seanhalle@260: processEnv->numLiveThreadSlvs == 0 ) seanhalle@260: { //This core sees no way to generate more tasks, so say it seanhalle@260: if( processEnv->coreIsDone[coreNum] == FALSE ) seanhalle@260: { processEnv->numCoresDone += 1; seanhalle@260: processEnv->coreIsDone[coreNum] = TRUE; seanhalle@260: #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE seanhalle@260: processEnv->shutdownInitiated = TRUE; seanhalle@260: seanhalle@260: #else seanhalle@260: if( processEnv->numCoresDone == NUM_CORES ) seanhalle@260: { //means no cores have work, and none can generate more seanhalle@260: processEnv->shutdownInitiated = TRUE; seanhalle@260: } seanhalle@260: #endif seanhalle@260: } seanhalle@260: } seanhalle@260: //check if shutdown has been initiated by this or other core seanhalle@260: if(processEnv->shutdownInitiated) seanhalle@260: { returnSlv = PR_SS__create_shutdown_slave(); seanhalle@260: } seanhalle@260: else seanhalle@260: returnSlv = NULL; seanhalle@260: seanhalle@260: goto ReturnTheSlv; //don't need, but completes pattern seanhalle@260: } //if( freeTaskSlv != NULL ) seanhalle@260: } //if( newTaskStub == NULL ) seanhalle@260: //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL seanhalle@260: seanhalle@260: seanhalle@260: ReturnTheSlv: //All paths goto here.. to provide single point for holistic.. seanhalle@260: seanhalle@260: #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC seanhalle@260: if( returnSlv == NULL ) seanhalle@260: { returnSlv = processEnv->idleSlv[coreNum][slotNum]; seanhalle@260: seanhalle@260: //things that would normally happen in resume(), but idle VPs seanhalle@260: // never go there seanhalle@260: returnSlv->assignCount++; //gives each idle unit a unique ID seanhalle@260: Unit newU; seanhalle@260: newU.vp = returnSlv->slaveID; seanhalle@260: newU.task = returnSlv->assignCount; seanhalle@260: addToListOfArrays(Unit,newU,processEnv->unitList); seanhalle@260: seanhalle@260: if (returnSlv->assignCount > 1) //make a dependency from prev idle unit seanhalle@260: { Dependency newD; // to this one seanhalle@260: newD.from_vp = returnSlv->slaveID; seanhalle@260: newD.from_task = returnSlv->assignCount - 1; seanhalle@260: newD.to_vp = returnSlv->slaveID; seanhalle@260: newD.to_task = returnSlv->assignCount; seanhalle@260: addToListOfArrays(Dependency, newD ,processEnv->ctlDependenciesList); seanhalle@260: } seanhalle@260: } seanhalle@260: else //have a slave will be assigned to the slot seanhalle@260: { //assignSlv->numTimesAssigned++; seanhalle@260: //get previous occupant of the slot seanhalle@260: Unit prev_in_slot = seanhalle@260: processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; seanhalle@260: if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency seanhalle@260: { Dependency newD; // is a hardware dependency seanhalle@260: newD.from_vp = prev_in_slot.vp; seanhalle@260: newD.from_task = prev_in_slot.task; seanhalle@260: newD.to_vp = returnSlv->slaveID; seanhalle@260: newD.to_task = returnSlv->assignCount; seanhalle@260: addToListOfArrays(Dependency,newD,processEnv->hwArcs); seanhalle@260: } seanhalle@260: prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous seanhalle@260: prev_in_slot.task = returnSlv->assignCount; seanhalle@260: processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = seanhalle@260: prev_in_slot; seanhalle@260: } seanhalle@260: #endif seanhalle@260: seanhalle@260: return( returnSlv ); seanhalle@260: } seanhalle@260: seanhalle@260: seanhalle@260: //================================================================= seanhalle@260: //#else //is MODE__MULTI_LANG seanhalle@260: //For multi-lang mode, first, get the constraint-env holder out of seanhalle@260: // the process, which is in the slave. seanhalle@260: //Second, get the magic number out of the request, use it to look up seanhalle@260: // the constraint Env within the constraint-env holder. seanhalle@260: //Then get the request handler out of the constr env seanhalle@260: constrEnvHolder = slave->process->constrEnvHolder; seanhalle@260: reqst = slave->request; seanhalle@260: langMagicNumber = reqst->langMagicNumber; seanhalle@260: semanticEnv = lookup( langMagicNumber, constrEnvHolder ); //a macro seanhalle@260: if( slave->reqst->type == taskEnd ) //end-task is special seanhalle@260: { //need to know what lang's task ended seanhalle@260: taskEndHandler = semanticEnv->taskEndHandler; seanhalle@260: (*taskEndHandler)( slave, reqst, semanticEnv ); //can put semantic data into task end reqst, for continuation, etc seanhalle@260: //this is a slot slave, get a new task for it seanhalle@260: if( !existsOverrideAssigner )//if exists, is set above, before loop seanhalle@260: { //search for task assigner that has work seanhalle@260: for( a = 0; a < num_assigners; a++ ) seanhalle@260: { if( taskAssigners[a]->hasWork ) seanhalle@260: { newTaskAssigner = taskAssigners[a]; seanhalle@260: (*newTaskAssigner)( slave, semanticEnv ); seanhalle@260: goto GotTask; seanhalle@260: } seanhalle@260: } seanhalle@260: goto NoTasks; seanhalle@260: } seanhalle@260: seanhalle@260: GotTask: seanhalle@260: continue; //have work, so do next iter of loop, don't call slave assigner seanhalle@260: } seanhalle@260: if( slave->typeOfVP == taskSlotSlv ) changeSlvType();//is suspended task seanhalle@260: //now do normal suspended slave request handler seanhalle@260: requestHandler = semanticEnv->requestHandler; seanhalle@260: //#endif seanhalle@260: seanhalle@260: seanhalle@260: } seanhalle@260: //If make it here, then was no task for this slot seanhalle@260: //slot empty, hand to Assigner to fill with a slave seanhalle@260: if( currSlot->needsSlaveAssigned ) seanhalle@260: { //Call plugin's Assigner to give slot a new slave seanhalle@260: HOLISTIC__Record_Assigner_start; seanhalle@260: seanhalle@260: //#ifdef MODE__MULTI_LANG seanhalle@260: NoTasks: seanhalle@260: //First, choose an Assigner.. seanhalle@260: //There are several Assigners, one for each langlet.. they all seanhalle@260: // indicate whether they have work available.. just pick the first seanhalle@260: // one that has work.. Or, if there's a Unified Assigner, call seanhalle@260: // that one.. So, go down array, checking.. seanhalle@260: if( !existsOverrideAssigner ) seanhalle@260: { for( a = 0; a < num_assigners; a++ ) seanhalle@260: { if( assigners[a]->hasWork ) seanhalle@260: { slaveAssigner = assigners[a]; seanhalle@260: goto GotAssigner; seanhalle@260: } seanhalle@260: } seanhalle@260: //no work, so just continue to next iter of scan loop seanhalle@260: continue; seanhalle@260: } seanhalle@260: //when exists override, the assigner is set, once, above, so do nothing seanhalle@260: GotAssigner: seanhalle@260: //#endif seanhalle@260: seanhalle@260: assignedSlaveVP = seanhalle@260: (*slaveAssigner)( semanticEnv, currSlot ); seanhalle@260: seanhalle@260: //put the chosen slave into slot, and adjust flags and state seanhalle@260: if( assignedSlaveVP != NULL ) seanhalle@260: { currSlot->slaveAssignedToSlot = assignedSlaveVP; seanhalle@260: assignedSlaveVP->animSlotAssignedTo = currSlot; seanhalle@260: currSlot->needsSlaveAssigned = FALSE; seanhalle@260: numSlotsFilled += 1; seanhalle@260: seanhalle@260: HOLISTIC__Record_Assigner_end; seanhalle@260: } seanhalle@260: }//if slot needs slave assigned seanhalle@260: }//for( slotIdx.. seanhalle@260: seanhalle@260: MEAS__Capture_Post_Master_Point; seanhalle@260: seanhalle@260: masterSwitchToCoreCtlr( masterVP ); seanhalle@260: flushRegisters(); seanhalle@260: DEBUG__printf(FALSE,"came back after switch to core -- so lock released!"); seanhalle@260: }//while(1) seanhalle@260: } seanhalle@260: