Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
comparison AnimationMaster.c @ 261:dafae55597ce
Getting closer -- added PRServ as built-in langlet (but still just copy)
about to rework a lot of the Master code.. possibly eliminate core controller
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Tue, 23 Oct 2012 23:46:17 -0700 |
| parents | 999f2966a3e5 |
| children | a5fa1e087c7e |
comparison
equal
deleted
inserted
replaced
| 9:f93b7a95183a | 10:dd554750655b |
|---|---|
| 8 | 8 |
| 9 #include <stdio.h> | 9 #include <stdio.h> |
| 10 #include <stddef.h> | 10 #include <stddef.h> |
| 11 | 11 |
| 12 #include "PR.h" | 12 #include "PR.h" |
| 13 | 13 #include "VSs_impl/VSs.h" |
| 14 | |
| 15 inline void | |
| 16 replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv ); | |
| 14 | 17 |
| 15 | 18 |
| 16 /*The animationMaster embodies most of the animator of the language. The | 19 /*The animationMaster embodies most of the animator of the language. The |
| 17 * animator is what emodies the behavior of language constructs. | 20 * animator is what emodies the behavior of language constructs. |
| 18 * As such, it is the animationMaster, in combination with the plugin | 21 * As such, it is the animationMaster, in combination with the plugin |
| 35 * | 38 * |
| 36 * | 39 * |
| 37 * | 40 * |
| 38 */ | 41 */ |
| 39 | 42 |
| 40 | 43 |
| 41 //===================== The versions of the Animation Master ================= | 44 //===================== The versions of the Animation Master ================= |
| 42 // | 45 // |
| 43 //============================================================================== | 46 //============================================================================== |
| 44 | 47 |
| 45 /* 1) This version is for a single language, that has only slaves, no tasks, | 48 /* 1) This version is for a single language, that has only slaves, no tasks, |
| 103 *Implementation Details: | 106 *Implementation Details: |
| 104 * | 107 * |
| 105 *There is a separate masterVP for each core, but a single semantic | 108 *There is a separate masterVP for each core, but a single semantic |
| 106 * environment shared by all cores. Each core also has its own scheduling | 109 * environment shared by all cores. Each core also has its own scheduling |
| 107 * slots, which are used to communicate slaves between animationMaster and | 110 * slots, which are used to communicate slaves between animationMaster and |
| 108 * coreController. There is only one global variable, _PRMasterEnv, which | 111 * coreController. There is only one global variable, _PRTopEnv, which |
| 109 * holds the semantic env and other things shared by the different | 112 * holds the semantic env and other things shared by the different |
| 110 * masterVPs. The request handler and Assigner are registered with | 113 * masterVPs. The request handler and Assigner are registered with |
| 111 * the animationMaster by the language's init function, and a pointer to | 114 * the animationMaster by the language's init function, and a pointer to |
| 112 * each is in the _PRMasterEnv. (There are also some pthread related global | 115 * each is in the _PRTopEnv. (There are also some pthread related global |
| 113 * vars, but they're only used during init of PR). | 116 * vars, but they're only used during init of PR). |
| 114 *PR gains control over the cores by essentially "turning off" the OS's | 117 *PR gains control over the cores by essentially "turning off" the OS's |
| 115 * scheduler, using pthread pin-to-core commands. | 118 * scheduler, using pthread pin-to-core commands. |
| 116 * | 119 * |
| 117 *The masterVPs are created during init, with this animationMaster as their | 120 *The masterVPs are created during init, with this animationMaster as their |
| 120 *A "seed slave" is also created during init -- this is equivalent to the | 123 *A "seed slave" is also created during init -- this is equivalent to the |
| 121 * "main" function in C, and acts as the entry-point to the PR-language- | 124 * "main" function in C, and acts as the entry-point to the PR-language- |
| 122 * based application. | 125 * based application. |
| 123 *The masterVPs share a single system-wide master-lock, so only one | 126 *The masterVPs share a single system-wide master-lock, so only one |
| 124 * masterVP may be animated at a time. | 127 * masterVP may be animated at a time. |
| 125 *The core controllers access _PRMasterEnv to get the masterVP, and when | 128 *The core controllers access _PRTopEnv to get the masterVP, and when |
| 126 * they start, the slots are all empty, so they run their associated core's | 129 * they start, the slots are all empty, so they run their associated core's |
| 127 * masterVP. The first of those to get the master lock sees the seed slave | 130 * masterVP. The first of those to get the master lock sees the seed slave |
| 128 * in the shared semantic environment, so when it runs the Assigner, that | 131 * in the shared semantic environment, so when it runs the Assigner, that |
| 129 * returns the seed slave, which the animationMaster puts into a scheduling | 132 * returns the seed slave, which the animationMaster puts into a scheduling |
| 130 * slot then switches to the core controller. That then switches the core | 133 * slot then switches to the core controller. That then switches the core |
| 158 RequestHandler requestHandler; | 161 RequestHandler requestHandler; |
| 159 void *semanticEnv; | 162 void *semanticEnv; |
| 160 int32 thisCoresIdx; | 163 int32 thisCoresIdx; |
| 161 | 164 |
| 162 //======================== Initializations ======================== | 165 //======================== Initializations ======================== |
| 163 masterEnv = (MasterEnv*)_VMSMasterEnv; | 166 masterEnv = (MasterEnv*)_PRTopEnv; |
| 164 | 167 |
| 165 thisCoresIdx = masterVP->coreAnimatedBy; | 168 thisCoresIdx = masterVP->coreAnimatedBy; |
| 166 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; | 169 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; |
| 167 | 170 |
| 168 requestHandler = masterEnv->requestHandler; | 171 requestHandler = masterEnv->requestHandler; |
| 194 currSlot->workIsDone = FALSE; | 197 currSlot->workIsDone = FALSE; |
| 195 currSlot->needsSlaveAssigned = TRUE; | 198 currSlot->needsSlaveAssigned = TRUE; |
| 196 SlaveVP *currSlave = currSlot->slaveAssignedToSlot; | 199 SlaveVP *currSlave = currSlot->slaveAssignedToSlot; |
| 197 | 200 |
| 198 justAddedReqHdlrChg(); | 201 justAddedReqHdlrChg(); |
| 199 //handle the request, either by VMS or by the language | 202 //handle the request, either by PR or by the language |
| 200 if( currSlave->requests->reqType != LangReq ) | 203 if( currSlave->requests->reqType != LangReq ) |
| 201 { //The request is a standard VMS one, not one defined by the | 204 { //The request is a standard PR one, not one defined by the |
| 202 // language, so VMS handles it, then queues slave to be assigned | 205 // language, so PR handles it, then queues slave to be assigned |
| 203 handleReqInVMS( currSlave ); | 206 handleReqInPR( currSlave ); |
| 204 writePrivQ( currSlave, VMSReadyQ ); //Q slave to be assigned below | 207 writePrivQ( currSlave, PRReadyQ ); //Q slave to be assigned below |
| 205 } | 208 } |
| 206 else | 209 else |
| 207 { MEAS__startReqHdlr; | 210 { MEAS__startReqHdlr; |
| 208 | 211 |
| 209 //Language handles request, which is held inside slave struc | 212 //Language handles request, which is held inside slave struc |
| 270 PRConstrEnvHolder *constrEnvHolder; | 273 PRConstrEnvHolder *constrEnvHolder; |
| 271 int32 langMagicNumber; | 274 int32 langMagicNumber; |
| 272 //#endif | 275 //#endif |
| 273 | 276 |
| 274 //======================== Initializations ======================== | 277 //======================== Initializations ======================== |
| 275 masterEnv = (MasterEnv*)_PRMasterEnv; | 278 masterEnv = (MasterEnv*)_PRTopEnv; |
| 276 | 279 |
| 277 thisCoresIdx = masterVP->coreAnimatedBy; | 280 thisCoresIdx = masterVP->coreAnimatedBy; |
| 278 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; | 281 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; |
| 279 | 282 |
| 280 requestHandler = masterEnv->requestHandler; | 283 requestHandler = masterEnv->requestHandler; |
| 496 PRConstrEnvHolder *constrEnvHolder; | 499 PRConstrEnvHolder *constrEnvHolder; |
| 497 int32 langMagicNumber; | 500 int32 langMagicNumber; |
| 498 //#endif | 501 //#endif |
| 499 | 502 |
| 500 //======================== Initializations ======================== | 503 //======================== Initializations ======================== |
| 501 masterEnv = (MasterEnv*)_PRMasterEnv; | 504 masterEnv = (MasterEnv*)_PRTopEnv; |
| 502 | 505 |
| 503 thisCoresIdx = masterVP->coreAnimatedBy; | 506 thisCoresIdx = masterVP->coreAnimatedBy; |
| 504 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; | 507 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; |
| 505 | 508 |
| 506 requestHandler = masterEnv->requestHandler; | 509 requestHandler = masterEnv->requestHandler; |
| 612 //This is the master when both multi-lang and multi-process modes are turned on | 615 //This is the master when both multi-lang and multi-process modes are turned on |
| 613 //#ifdef MODE__MULTI_LANG | 616 //#ifdef MODE__MULTI_LANG |
| 614 //#ifdef MODE__MULTI_PROCESS | 617 //#ifdef MODE__MULTI_PROCESS |
| 615 void animationMaster( void *initData, SlaveVP *masterVP ) | 618 void animationMaster( void *initData, SlaveVP *masterVP ) |
| 616 { | 619 { |
| 620 int32 slotIdx; | |
| 621 // int32 numSlotsFilled; | |
| 622 AnimSlot *currSlot; | |
| 617 //Used while scanning and filling animation slots | 623 //Used while scanning and filling animation slots |
| 618 int32 slotIdx, numSlotsFilled; | 624 AnimSlot **animSlots; |
| 619 AnimSlot *currSlot, **animSlots; | |
| 620 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner | |
| 621 | 625 |
| 622 //Local copies, for performance | 626 //Local copies, for performance |
| 623 MasterEnv *masterEnv; | 627 MasterEnv *masterEnv; |
| 624 SlaveAssigner slaveAssigner; | |
| 625 RequestHandler requestHandler; | |
| 626 PRSemEnv *semanticEnv; | |
| 627 int32 thisCoresIdx; | 628 int32 thisCoresIdx; |
| 628 | |
| 629 SlaveVP *slave; | |
| 630 PRProcess *process; | |
| 631 PRConstrEnvHolder *constrEnvHolder; | |
| 632 int32 langMagicNumber; | |
| 633 | 629 |
| 634 //======================== Initializations ======================== | 630 //======================== Initializations ======================== |
| 635 masterEnv = (MasterEnv*)_PRMasterEnv; | 631 masterEnv = (MasterEnv*)_PRTopEnv; |
| 636 | 632 |
| 637 thisCoresIdx = masterVP->coreAnimatedBy; | 633 thisCoresIdx = masterVP->coreAnimatedBy; |
| 638 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; | 634 animSlots = masterEnv->allAnimSlots[thisCoresIdx]; |
| 639 | 635 |
| 640 requestHandler = masterEnv->requestHandler; | |
| 641 slaveAssigner = masterEnv->slaveAssigner; | |
| 642 semanticEnv = masterEnv->semanticEnv; | |
| 643 | |
| 644 //initialize, for non-multi-lang, non multi-proc case | |
| 645 // default handler gets put into master env by a registration call by lang | |
| 646 endTaskHandler = masterEnv->defaultTaskHandler; | |
| 647 | |
| 648 HOLISTIC__Insert_Master_Global_Vars; | 636 HOLISTIC__Insert_Master_Global_Vars; |
| 649 | 637 |
| 650 //======================== animationMaster ======================== | 638 //======================== animationMaster ======================== |
| 651 //Do loop gets requests handled and work assigned to slots.. | 639 //Do loop gets requests handled and work assigned to slots.. |
| 652 // work can either be a task or a resumed slave | 640 // work can either be a task or a resumed slave |
| 653 //Having two cases makes this logic complex.. can be finishing either, and | 641 //Having two cases makes this logic complex.. can be finishing either, and |
| 654 // then the next available work may be either.. so really have two distinct | 642 // then the next available work may be either.. so really have two distinct |
| 655 // loops that are inter-twined.. | 643 // loops that are inter-twined.. |
| 656 while(1){ | 644 while(1) |
| 657 | 645 { |
| 658 MEAS__Capture_Pre_Master_Point | 646 MEAS__Capture_Pre_Master_Point |
| 659 | 647 |
| 660 //Scan the animation slots | 648 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) |
| 661 numSlotsFilled = 0; | 649 { |
| 662 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++) | 650 currSlot = animSlots[ slotIdx ]; |
| 663 { | 651 |
| 664 currSlot = animSlots[ slotIdx ]; | 652 masterFunction_multiLang( currSlot ); |
| 653 } | |
| 654 | |
| 655 MEAS__Capture_Post_Master_Point; | |
| 656 | |
| 657 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master | |
| 658 flushRegisters(); | |
| 659 } | |
| 660 } | |
| 661 #endif //MODE__MULTI_LANG | |
| 662 #endif //MODE__MULTI_PROCESS | |
| 663 | |
| 664 inline | |
| 665 void | |
| 666 masterFunction_multiLang( AnimSlot *currSlot ) | |
| 667 { //Scan the animation slots | |
| 668 int32 magicNumber; | |
| 669 SlaveVP *slave; | |
| 670 SlaveVP *assignedSlaveVP; | |
| 671 PRSemEnv *semanticEnv; | |
| 672 PRReqst *req; | |
| 673 RequestHandler requestHandler; | |
| 665 | 674 |
| 666 //Check if newly-done slave in slot, which will need request handled | 675 //Check if newly-done slave in slot, which will need request handled |
| 667 if( currSlot->workIsDone ) | 676 if( currSlot->workIsDone ) |
| 668 { currSlot->workIsDone = FALSE; | 677 { currSlot->workIsDone = FALSE; |
| 669 | 678 |
| 672 | 681 |
| 673 | 682 |
| 674 //process the request made by the slave (held inside slave struc) | 683 //process the request made by the slave (held inside slave struc) |
| 675 slave = currSlot->slaveAssignedToSlot; | 684 slave = currSlot->slaveAssignedToSlot; |
| 676 | 685 |
| 677 //check if the completed work was a task.. | 686 //check if the slave was doing a task.. |
| 678 if( slave->taskMetaInfo->isATask ) | 687 //Action depends on both on the request type, and whether it's on |
| 679 { | 688 // a generic slave vs a suspended task |
| 680 if( slave->reqst->type == TaskEnd ) | 689 if( slave->metaTask->taskType == AtomicTask || |
| 681 { //do task end handler, which is registered separately | 690 slave->metaTask->taskType == SuspendedTask ) |
| 682 //note, end hdlr may use semantic data from reqst.. | 691 { |
| 683 //get end-task handler | 692 switch( slave->request->reqType ) |
| 684 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv ); | 693 { case TaskEnd: |
| 685 taskEndHandler = slave->taskMetaInfo->endTaskHandler; | 694 { PRHandle_EndTask( slave ); //if free task slave, update count, put into recycle Q -- do handler before lang's handler |
| 686 | 695 |
| 687 (*taskEndHandler)( slave, semanticEnv ); | 696 //do task end handler, which is registered separately |
| 688 | 697 //note, end hdlr may use semantic data from reqst.. |
| 689 goto AssignWork; | 698 //get end-task handler |
| 690 } | 699 |
| 691 else //is a task, and just suspended | 700 RequestHandler |
| 692 { //turn slot slave into free task slave & make replacement | 701 taskEndHandler = slave->metaTask->reqHandler; |
| 693 if( slave->typeOfVP == TaskSlotSlv ) changeSlvType(); | 702 semanticEnv = PR_int__give_sem_env_for_slave( slave, |
| 694 | 703 slave->request->langMagicNumber ); |
| 695 //goto normal slave request handling | 704 (*taskEndHandler)( slave, semanticEnv ); |
| 696 goto SlaveReqHandling; | 705 |
| 697 } | 706 goto AssignWork; |
| 707 } | |
| 708 case TaskCreate: | |
| 709 { PRHandle_CreateTask( slave ); | |
| 710 justCopied_check; | |
| 711 RequestHandler | |
| 712 taskCreateHandler = slave->metaTask->reqHandler; | |
| 713 semanticEnv = PR_int__give_sem_env_for_slave( slave, | |
| 714 slave->request->langMagicNumber ); | |
| 715 (*taskCreateHandler)( slave, semanticEnv ); | |
| 716 | |
| 717 want_to_resume_creating_slave; | |
| 718 goto AssignWork; | |
| 719 } | |
| 720 default: | |
| 721 { //is a task, and just suspended, so tied to a free task slave | |
| 722 //First turn slot slave into free task slave & make replacement | |
| 723 if( slave->typeOfVP == TaskSlotSlv ) | |
| 724 replaceWithNewSlotSlv( slave, slave->processSlaveIsIn->processEnv ); | |
| 725 | |
| 726 //goto normal slave request handling | |
| 727 goto SlaveReqHandling; | |
| 728 } | |
| 729 } | |
| 698 } | 730 } |
| 699 else //is a slave that suspended | 731 else //is a slave that suspended |
| 700 { | 732 { |
| 701 | 733 |
| 702 SlaveReqHandling: | 734 SlaveReqHandling: |
| 703 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) | 735 //Q: put the switch in inline call, to clean up code? |
| 704 | 736 req = slave->request; |
| 737 switch( req->reqType ) | |
| 738 { case SlvCreate: PRHandle_CreateSlave( slave ); break; | |
| 739 case SlvDissipate: PRHandle_Dissipate( slave ); break; | |
| 740 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own semantic env | |
| 741 case Hardware: //for future expansion | |
| 742 case IO: //for future expansion | |
| 743 case OSCall: //for future expansion | |
| 744 case Language: //normal sem request | |
| 745 magicNumber = slave->request->langMagicNumber; | |
| 746 semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber ); | |
| 747 requestHandler = semanticEnv->requestHdlr; | |
| 748 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave) | |
| 749 } | |
| 750 | |
| 705 HOLISTIC__Record_AppResponder_end; | 751 HOLISTIC__Record_AppResponder_end; |
| 706 MEAS__endReqHdlr; | 752 MEAS__endReqHdlr; |
| 707 | 753 |
| 708 goto AssignWork; | 754 goto AssignWork; |
| 709 } | 755 } |
| 710 } //if has suspended slave that needs handling | 756 } //if has suspended slave that needs handling |
| 711 | 757 |
| 712 //if slot empty, hand to Assigner to fill with a slave | 758 //End up here when the slot did not have ended work in it (no req) |
| 759 //So, here, if slot empty, look for work to fill the slot | |
| 713 if( currSlot->needsSlaveAssigned ) | 760 if( currSlot->needsSlaveAssigned ) |
| 714 { //Scan sem environs, looking for one with ready work. | 761 { HOLISTIC__Record_Assigner_start; |
| 715 // call the Assigner for that sem Env, to give slot a new slave | |
| 716 HOLISTIC__Record_Assigner_start; | |
| 717 | 762 |
| 718 AssignWork: | 763 AssignWork: |
| 719 | 764 //Scan sem environs, looking for semEnv with ready work. |
| 765 // call the Assigner for that sem Env, to get a slave for the slot | |
| 720 assignedSlaveVP = assignWork( semanticEnv, currSlot ); | 766 assignedSlaveVP = assignWork( semanticEnv, currSlot ); |
| 721 | 767 |
| 722 //put the chosen slave into slot, and adjust flags and state | 768 //put the chosen slave into slot, and adjust flags and state |
| 723 if( assignedSlaveVP != NULL ) | 769 if( assignedSlaveVP != NULL ) |
| 724 { currSlot->slaveAssignedToSlot = assignedSlaveVP; | 770 { currSlot->slaveAssignedToSlot = assignedSlaveVP; |
| 725 assignedSlaveVP->animSlotAssignedTo = currSlot; | 771 assignedSlaveVP->animSlotAssignedTo = currSlot; |
| 726 currSlot->needsSlaveAssigned = FALSE; | 772 currSlot->needsSlaveAssigned = FALSE; |
| 727 numSlotsFilled += 1; | |
| 728 } | 773 } |
| 729 else | 774 else |
| 730 { | 775 { currSlot->needsSlaveAssigned = TRUE; //local write |
| 731 currSlot->needsSlaveAssigned = TRUE; //local write | |
| 732 } | 776 } |
| 733 HOLISTIC__Record_Assigner_end; | 777 HOLISTIC__Record_Assigner_end; |
| 734 }//if slot needs slave assigned | 778 }//if slot needs slave assigned |
| 735 }//for( slotIdx.. | |
| 736 | |
| 737 MEAS__Capture_Post_Master_Point; | |
| 738 | |
| 739 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master | |
| 740 flushRegisters(); | |
| 741 }//while(1) | |
| 742 } | 779 } |
| 743 #endif //MODE__MULTI_LANG | 780 |
| 744 #endif //MODE__MULTI_PROCESS | 781 //========================================================================== |
| 745 | 782 /*When a task in a slot slave suspends, the slot slave has to be changed to |
| 746 | 783 * a free task slave, then the slot slave replaced. The replacement can be |
| 747 /*This does three things: | 784 * either a recycled free task slave that finished it's task and has been |
| 748 * 1) ask for a slave ready to resume | 785 * idle in the recycle queue, or else create a new slave to be the slot slave. |
| 749 * 2) if none, then ask for a task, and assign to the slot slave | 786 *The master only calls this with a slot slave that needs to be replaced. |
| 750 * 3) if none, then prune former task slaves waiting to be recycled. | 787 */ |
| 751 * | 788 inline void |
| 752 //Have two separate assigners in each semantic env, | 789 replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcessEnv *processEnv ) |
| 753 // which keeps its own work in its own structures.. the master, here, | 790 { SlaveVP *newSlotSlv; |
| 754 // searches through the semantic environs, takes the first that has work | 791 VSsSemData *semData; |
| 755 // available, and whatever it returns is assigned to the slot.. | 792 |
| 756 //However, also have an override assigner.. because static analysis tools know | 793 fixMe__still_VSs_stuff_in_here; |
| 757 // which languages are grouped together.. and the override enables them to | 794 //get a new slave to be the slot slave |
| 758 // generate a custom assigner that uses info from all the languages in a | 795 newSlotSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ ); |
| 759 // unified way.. Don't really expect this to happen, but making it possible. | 796 if( newSlotSlv == NULL ) |
| 797 { newSlotSlv = PR_int__create_slaveVP( &idle_fn, NULL, processEnv, 0); | |
| 798 //just made a new free task slave, so count it | |
| 799 processEnv->numLiveFreeTaskSlvs += 1; | |
| 800 } | |
| 801 | |
| 802 //set slave values to make it the slot slave | |
| 803 newSlotSlv->metaTask = NULL; | |
| 804 newSlotSlv->typeOfVP = TaskSlotSlv; | |
| 805 newSlotSlv->needsTaskAssigned = TRUE; | |
| 806 | |
| 807 //a slot slave is pinned to a particular slot on a particular core | |
| 808 //Note, this happens before the request is seen by handler, so nothing | |
| 809 // has had a chance to change the coreAnimatedBy or anything else.. | |
| 810 newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo; | |
| 811 newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy; | |
| 812 | |
| 813 //put it into the slot slave matrix | |
| 814 int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; | |
| 815 int32 coreNum = requestingSlv->coreAnimatedBy; | |
| 816 processEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv; | |
| 817 | |
| 818 //Fix up requester, to be an extra slave now (but not an ended one) | |
| 819 // because it's active, doesn't go into freeTaskSlvRecycleQ | |
| 820 requestingSlv->typeOfVP = FreeTaskSlv; | |
| 821 } | |
| 822 | |
| 823 | |
| 824 | |
| 825 /*This does: | |
| 826 * 1) searches the semantic environments for one with work ready | |
| 827 * if finds one, asks its assigner to return work | |
| 828 * 2) checks what kind of work: new task, resuming task, resuming slave | |
| 829 * if new task, gets the slot slave and assigns task to it and returns slave | |
| 830 * else, gets the slave attached to the metaTask and returns that. | |
| 831 * 3) if no work found, then prune former task slaves waiting to be recycled. | |
| 832 * If no work and no slaves to prune, check for shutdown conditions. | |
| 833 * | |
| 834 * Semantic env keeps its own work in its own structures, and has its own | |
| 835 * assigner. It chooses | |
| 836 * However, include a switch that switches-in an override assigner, which | |
| 837 * sees all the work in all the semantic env's. This is most likely | |
| 838 * generated by static tools and included in the executable. That means it | |
| 839 * has to be called via a registered pointer from here. The idea is that | |
| 840 * the static tools know which languages are grouped together.. and the | |
| 841 * override enables them to generate a custom assigner that uses info from | |
| 842 * all the languages in a unified way.. Don't really expect this to happen, | |
| 843 * but am making it possible. | |
| 760 */ | 844 */ |
| 761 inline SlaveVP * | 845 inline SlaveVP * |
| 762 assignWork( PRProcessEnv *processEnv, AnimSlot *slot ) | 846 assignWork( PRProcess *process, AnimSlot *slot ) |
| 763 { SlaveVP *returnSlv; | 847 { SlaveVP *returnSlv; |
| 764 //VSsSemEnv *semEnv; | 848 //VSsSemEnv *semEnv; |
| 765 //VSsSemData *semData; | 849 //VSsSemData *semData; |
| 766 int32 coreNum, slotNum; | 850 int32 coreNum, slotNum; |
| 767 PRTaskMetaInfo *newTaskStub; | 851 PRMetaTask *newMetaTask, *assignedMetaTask; |
| 768 SlaveVP *freeTaskSlv; | 852 SlaveVP *freeTaskSlv; |
| 769 | 853 |
| 770 | 854 coreNum = slot->coreSlotIsOn; |
| 771 //master has to handle slot slaves.. so either assigner returns | 855 |
| 772 // taskMetaInfo or else two assigners, one for slaves, other for tasks.. | 856 if( _PRTopEnv->overrideAssigner != NULL ) |
| 773 semEnvs = processEnv->semEnvs; | 857 { assignedMetaTask = (*_PRTopEnv->overrideAssigner)( process, slot ); |
| 774 numEnvs = processEnv->numSemEnvs; | 858 if( assignedMetaTask != NULL ) |
| 775 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) | 859 { |
| 860 //have work, so reset Done flag (caused by work generated on other core) | |
| 861 if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf | |
| 862 process->coreIsDone[coreNum] = FALSE; //don't just write always | |
| 863 | |
| 864 switch( assignedMetaTask->taskType ) | |
| 865 { case GenericSlave: goto AssignSlave; | |
| 866 case ResumedTask: goto AssignSlave; | |
| 867 case NewTask: goto AssignNewTask; | |
| 868 case default: PR_int__throw_exception( "unknown task type ret by assigner" ); | |
| 869 } | |
| 870 } | |
| 871 else | |
| 872 goto NoWork; | |
| 873 } | |
| 874 | |
| 875 //If here, then no override assigner, so search semantic envs for work | |
| 876 int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner; | |
| 877 semEnvs = process->semEnvs; | |
| 878 numEnvs = process->numSemEnvs; | |
| 879 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash AND array | |
| 776 { semEnv = semEnvs[envIdx]; | 880 { semEnv = semEnvs[envIdx]; |
| 777 if( semEnv->hasWork ) | 881 if( semEnv->hasWork ) |
| 778 { assigner = semEnv->assigner; | 882 { assigner = semEnv->assigner; |
| 779 retTaskMetaInfo = (*assigner)( semEnv, slot ); | 883 assignedMetaTask = (*assigner)( semEnv, slot ); |
| 780 | 884 |
| 781 return retTaskMetaInfo; //quit, have work | 885 //have work, so reset Done flag (caused by work generated on other core) |
| 886 if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf | |
| 887 process->coreIsDone[coreNum] = FALSE; //don't just write always | |
| 888 | |
| 889 switch( assignedMetaTask->taskType ) | |
| 890 { case GenericSlave: goto AssignSlave; | |
| 891 case ResumedTask: goto AssignSlave; | |
| 892 case NewTask: goto AssignNewTask; | |
| 893 case default: PR_int__throw_exception( "unknown task type ret by assigner" ); | |
| 894 } | |
| 782 } | 895 } |
| 783 } | 896 } |
| 784 | 897 |
| 785 coreNum = slot->coreSlotIsOn; | 898 NoWork: |
| 786 slotNum = slot->slotIdx; | 899 //No work, if reach here.. |
| 787 | 900 //no task, so prune the recycle pool of free task slaves |
| 788 //first try to get a ready slave | 901 freeTaskSlv = readPrivQ( process->freeTaskSlvRecycleQ ); |
| 789 returnSlv = getReadySlave(); | 902 if( freeTaskSlv != NULL ) |
| 790 | 903 { //delete, so that bound the num extras, and deliver shutdown cond |
| 791 if( returnSlv != NULL ) | 904 deleteExtraneousFreeTaskSlv( freeTaskSlv, process ); |
| 792 { returnSlv->coreAnimatedBy = coreNum; | 905 //then return NULL |
| 793 | 906 returnSlv = NULL; |
| 794 //have work, so reset Done flag (when work generated on other core) | 907 |
| 795 if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf | 908 goto ReturnTheSlv; |
| 796 processEnv->coreIsDone[coreNum] = FALSE; //don't just write always | 909 } |
| 910 else | |
| 911 { //candidate for shutdown.. all extras dissipated, and no tasks | |
| 912 // and no ready to resume slaves, so no way to generate | |
| 913 // more work (on this core -- other core might have work still) | |
| 914 if( process->numLiveFreeTaskSlvs == 0 && | |
| 915 process->numLiveGenericSlvs == 0 ) | |
| 916 { //This core sees no way to generate more tasks, so say it | |
| 917 if( process->coreIsDone[coreNum] == FALSE ) | |
| 918 { process->numCoresDone += 1; | |
| 919 process->coreIsDone[coreNum] = TRUE; | |
| 920 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE | |
| 921 process->shutdownInitiated = TRUE; | |
| 922 | |
| 923 #else | |
| 924 if( process->numCoresDone == NUM_CORES ) | |
| 925 { //means no cores have work, and none can generate more | |
| 926 process->shutdownInitiated = TRUE; | |
| 927 } | |
| 928 #endif | |
| 929 } | |
| 930 } | |
| 931 //check if shutdown has been initiated by this or other core | |
| 932 if( process->shutdownInitiated ) | |
| 933 { returnSlv = PR_SS__create_shutdown_slave(); | |
| 934 } | |
| 935 else | |
| 936 returnSlv = NULL; | |
| 937 | |
| 938 goto ReturnTheSlv; | |
| 939 } //if( freeTaskSlv != NULL ) | |
| 940 | |
| 941 | |
| 942 AssignSlave: | |
| 943 { //get slave pointed to by meta task. | |
| 944 returnSlv = assignedMetaTask->slaveAssignedTo; | |
| 945 | |
| 946 returnSlv->coreAnimatedBy = coreNum; | |
| 797 | 947 |
| 798 goto ReturnTheSlv; | 948 goto ReturnTheSlv; |
| 799 } | 949 } |
| 800 | 950 |
| 801 //were no slaves, so try to get a ready task.. | 951 AssignNewTask: |
| 802 newTaskStub = getTaskStub(); | |
| 803 | |
| 804 if( newTaskStub != NULL ) | |
| 805 { | 952 { |
| 806 //get the slot slave to assign the task to.. | 953 //get the slot slave to assign the task to.. |
| 807 returnSlv = processEnv->slotTaskSlvs[coreNum][slotNum]; | 954 coreNum = slot->coreSlotIsOn; |
| 955 slotNum = slot->slotIdx; | |
| 956 returnSlv = process->slotTaskSlvs[coreNum][slotNum]; | |
| 808 | 957 |
| 809 //point slave to task's function, and mark slave as having task | 958 //point slave to task's function, and mark slave as having task |
| 810 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv, | 959 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv, |
| 811 newTaskStub->taskType->fn, newTaskStub->args ); | 960 assignedMetaTask->topLevelFn, assignedMetaTask->initData ); |
| 812 returnSlv->taskStub = newTaskStub; | 961 returnSlv->metaTask = assignedMetaTask; |
| 813 newTaskStub->slaveAssignedTo = returnSlv; | 962 assignedMetaTask->slaveAssignedTo = returnSlv; |
| 814 returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type | 963 returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type |
| 815 | 964 |
| 816 //have work, so reset Done flag, if was set | 965 //have work, so reset Done flag, if was set |
| 817 if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf | 966 if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf |
| 818 processEnv->coreIsDone[coreNum] = FALSE; //don't just write always | 967 process->coreIsDone[coreNum] = FALSE; //don't just write always |
| 819 | 968 |
| 820 goto ReturnTheSlv; | 969 goto ReturnTheSlv; |
| 821 } | 970 } |
| 822 else | |
| 823 { //no task, so prune the recycle pool of free task slaves | |
| 824 freeTaskSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ ); | |
| 825 if( freeTaskSlv != NULL ) | |
| 826 { //delete to bound the num extras, and deliver shutdown cond | |
| 827 handleDissipate( freeTaskSlv, processEnv ); | |
| 828 //then return NULL | |
| 829 returnSlv = NULL; | |
| 830 | |
| 831 goto ReturnTheSlv; | |
| 832 } | |
| 833 else | |
| 834 { //candidate for shutdown.. if all extras dissipated, and no tasks | |
| 835 // and no ready to resume slaves, then no way to generate | |
| 836 // more tasks (on this core -- other core might have task still) | |
| 837 if( processEnv->numLiveExtraTaskSlvs == 0 && | |
| 838 processEnv->numLiveThreadSlvs == 0 ) | |
| 839 { //This core sees no way to generate more tasks, so say it | |
| 840 if( processEnv->coreIsDone[coreNum] == FALSE ) | |
| 841 { processEnv->numCoresDone += 1; | |
| 842 processEnv->coreIsDone[coreNum] = TRUE; | |
| 843 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE | |
| 844 processEnv->shutdownInitiated = TRUE; | |
| 845 | |
| 846 #else | |
| 847 if( processEnv->numCoresDone == NUM_CORES ) | |
| 848 { //means no cores have work, and none can generate more | |
| 849 processEnv->shutdownInitiated = TRUE; | |
| 850 } | |
| 851 #endif | |
| 852 } | |
| 853 } | |
| 854 //check if shutdown has been initiated by this or other core | |
| 855 if(processEnv->shutdownInitiated) | |
| 856 { returnSlv = PR_SS__create_shutdown_slave(); | |
| 857 } | |
| 858 else | |
| 859 returnSlv = NULL; | |
| 860 | |
| 861 goto ReturnTheSlv; //don't need, but completes pattern | |
| 862 } //if( freeTaskSlv != NULL ) | |
| 863 } //if( newTaskStub == NULL ) | |
| 864 //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL | |
| 865 | 971 |
| 866 | 972 |
| 867 ReturnTheSlv: //All paths goto here.. to provide single point for holistic.. | 973 ReturnTheSlv: //All paths goto here.. to provide single point for holistic.. |
| 868 | 974 |
| 869 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC | 975 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC |
| 870 if( returnSlv == NULL ) | 976 if( returnSlv == NULL ) |
| 871 { returnSlv = processEnv->idleSlv[coreNum][slotNum]; | 977 { returnSlv = process->idleSlv[coreNum][slotNum]; |
| 872 | 978 |
| 873 //things that would normally happen in resume(), but idle VPs | 979 //things that would normally happen in resume(), but idle VPs |
| 874 // never go there | 980 // never go there |
| 875 returnSlv->assignCount++; //gives each idle unit a unique ID | 981 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID |
| 876 Unit newU; | 982 Unit newU; |
| 877 newU.vp = returnSlv->slaveID; | 983 newU.vp = returnSlv->slaveID; |
| 878 newU.task = returnSlv->assignCount; | 984 newU.task = returnSlv->numTimesAssignedToASlot; |
| 879 addToListOfArrays(Unit,newU,processEnv->unitList); | 985 addToListOfArrays(Unit,newU,process->unitList); |
| 880 | 986 |
| 881 if (returnSlv->assignCount > 1) //make a dependency from prev idle unit | 987 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit |
| 882 { Dependency newD; // to this one | 988 { Dependency newD; // to this one |
| 883 newD.from_vp = returnSlv->slaveID; | 989 newD.from_vp = returnSlv->slaveID; |
| 884 newD.from_task = returnSlv->assignCount - 1; | 990 newD.from_task = returnSlv->numTimesAssignedToASlot - 1; |
| 885 newD.to_vp = returnSlv->slaveID; | 991 newD.to_vp = returnSlv->slaveID; |
| 886 newD.to_task = returnSlv->assignCount; | 992 newD.to_task = returnSlv->numTimesAssignedToASlot; |
| 887 addToListOfArrays(Dependency, newD ,processEnv->ctlDependenciesList); | 993 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList); |
| 888 } | 994 } |
| 889 } | 995 } |
| 890 else //have a slave will be assigned to the slot | 996 else //have a slave will be assigned to the slot |
| 891 { //assignSlv->numTimesAssigned++; | 997 { //assignSlv->numTimesAssigned++; |
| 892 //get previous occupant of the slot | 998 //get previous occupant of the slot |
| 893 Unit prev_in_slot = | 999 Unit prev_in_slot = |
| 894 processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; | 1000 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; |
| 895 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency | 1001 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency |
| 896 { Dependency newD; // is a hardware dependency | 1002 { Dependency newD; // is a hardware dependency |
| 897 newD.from_vp = prev_in_slot.vp; | 1003 newD.from_vp = prev_in_slot.vp; |
| 898 newD.from_task = prev_in_slot.task; | 1004 newD.from_task = prev_in_slot.task; |
| 899 newD.to_vp = returnSlv->slaveID; | 1005 newD.to_vp = returnSlv->slaveID; |
| 900 newD.to_task = returnSlv->assignCount; | 1006 newD.to_task = returnSlv->numTimesAssignedToASlot; |
| 901 addToListOfArrays(Dependency,newD,processEnv->hwArcs); | 1007 addToListOfArrays(Dependency,newD,process->hwArcs); |
| 902 } | 1008 } |
| 903 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous | 1009 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous |
| 904 prev_in_slot.task = returnSlv->assignCount; | 1010 prev_in_slot.task = returnSlv->numTimesAssignedToASlot; |
| 905 processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = | 1011 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = |
| 906 prev_in_slot; | 1012 prev_in_slot; |
| 907 } | 1013 } |
| 908 #endif | 1014 #endif |
| 909 | 1015 |
| 910 return( returnSlv ); | 1016 return( returnSlv ); |
| 911 } | 1017 } |
| 912 | 1018 |
| 1019 | |
| 1020 /*In creator, only PR related things happen, and things in the langlet whose | |
| 1021 * creator construct was used. | |
| 1022 *Other langlet still gets a chance to create semData -- but by registering a | |
| 1023 * "createSemData" handler in the semEnv. When a construct of the langlet | |
| 1024 * calls "PR__give_sem_data()", if there is no semData for that langlet, | |
| 1025 * the PR will call the creator in the langlet's semEnv, place whatever it | |
| 1026 * makes as the semData in that slave for that langlet, and return that semData | |
| 1027 * | |
| 1028 *So, as far as counting things, a langlet is only allowed to count creation | |
| 1029 * of slaves it creates itself.. may have to change this later.. add a way for | |
| 1030 * langlet to register a trigger Fn called each time a slave gets created.. | |
| 1031 * need more experience with what langlets will do at create time.. think Cilk | |
| 1032 * has interesting create behavior.. not sure how that will differ in light | |
| 1033 * of true tasks and langlet approach. Look at it after all done and start | |
| 1034 * modifying the langs to be langlets.. | |
| 1035 * | |
| 1036 *PR itself needs to create the slave, then update numLiveSlaves in process, | |
| 1037 * copy processID from requestor to newly created | |
| 1038 */ | |
| 1039 PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv ) | |
| 1040 { SlaveVP *newSlv; | |
| 1041 PRMetaTask metaTask; | |
| 1042 PRProcess *process; | |
| 1043 | |
| 1044 process = requestingSlv->processSlaveIsIn; | |
| 1045 newSlv = PR_int__create_slaveVP(); | |
| 1046 newSlv->typeOfVP = GenericSlv; | |
| 1047 newSlv->processSlaveIsIn = process; | |
| 1048 process->numLiveGenericSlaves += 1; | |
| 1049 metaTask = PR_int__create_slave_meta_task(); | |
| 1050 metaTask->taskID = req->ID; | |
| 1051 metaTask->taskType = GenericSlave; | |
| 1052 | |
| 1053 (*req->handler)(newSlv); | |
| 1054 } | |
| 1055 | |
| 1056 /*The dissipate handler has to update the number of slaves of the type, within | |
| 1057 * the process, and call the langlet handler linked into the request, | |
| 1058 * and after that returns, then call the PR function that frees the slave state | |
| 1059 * (or recycles the slave). | |
| 1060 * | |
| 1061 *The PR function that frees the slave state has to also free all of the | |
| 1062 * semData in the slave.. or else reset all of the semDatas.. by, say, marking | |
| 1063 * them, then in PR__give_semData( magicNum ) call the langlet registered | |
| 1064 * "resetSemData" Fn. | |
| 1065 */ | |
| 1066 PRHandle_Dissipate( SlaveVP *slave ) | |
| 1067 { PRProcess *process; | |
| 1068 void *semEnv; | |
| 1069 | |
| 1070 process = slave->processSlaveIsIn; | |
| 1071 | |
| 1072 //do the language's dissipate handler | |
| 1073 semEnv = PR_int__give_sem_env_for( slave, slave->request->langMagicNumber ); | |
| 1074 (*slave->request->handler)( slave, semEnv ); | |
| 1075 | |
| 1076 process->numLiveGenericSlaves -= 1; | |
| 1077 PR_int__dissipate_slaveVP_multilang( slave ); //recycles and resets semDatas | |
| 1078 | |
| 1079 //check End Of Process Condition | |
| 1080 if( process->numLiveTasks == 0 && | |
| 1081 process->numLiveGenericSlaves == 0 ) | |
| 1082 signalEndOfProcess; | |
| 1083 } | |
| 1084 | |
| 1085 /*Create task is a special form, that has PR behavior in addition to plugin | |
| 1086 * behavior. Master calls this first, and this in turn calls the plugin's | |
| 1087 * create task handler. | |
| 1088 */ | |
| 1089 inline void | |
| 1090 PRHandle_CreateTask( TopLevelFn topLevelFn, void *initData, PRReqst *req, | |
| 1091 SlaveVP *requestingSlv ) | |
| 1092 { PRMetaTask *metaTask; | |
| 1093 PRProcess *process; | |
| 1094 void *semEnv, _langMetaTask; | |
| 1095 PRLangMetaTask *langMetaTask; | |
| 1096 | |
| 1097 process = requestingSlv->processSlaveIsIn; | |
| 1098 | |
| 1099 metaTask = PR_int__create_meta_task( req ); | |
| 1100 metaTask->taskID = req->ID; //may be NULL | |
| 1101 metaTask->topLevelFn = topLevelFn; | |
| 1102 metaTask->initData = initData; | |
| 1103 | |
| 1104 process->numLiveTasks += 1; | |
| 913 | 1105 |
| 914 //================================================================= | 1106 //plugin tracks tasks ready, and has its own assigner, so task doesn't |
| 915 //#else //is MODE__MULTI_LANG | 1107 // come back from lang's handler -- it's consumed and stays in semEnv. |
| 916 //For multi-lang mode, first, get the constraint-env holder out of | 1108 //But handler gives back the language-specific meta-task it creates, and |
| 917 // the process, which is in the slave. | 1109 // then hook that into the PR meta-task |
| 918 //Second, get the magic number out of the request, use it to look up | 1110 //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size |
| 919 // the constraint Env within the constraint-env holder. | 1111 // of the lang's metaTask, and alloc's that plus the prolog and returns |
| 920 //Then get the request handler out of the constr env | 1112 // ptr to position just above the prolog) |
| 921 constrEnvHolder = slave->process->constrEnvHolder; | 1113 semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req |
| 922 reqst = slave->request; | 1114 _langMetaTask = (*requestingSlv->request->handler)(req, semEnv); |
| 923 langMagicNumber = reqst->langMagicNumber; | 1115 langMetaTask = (PRLangMetaTask *)_langMetaTask; |
| 924 semanticEnv = lookup( langMagicNumber, constrEnvHolder ); //a macro | 1116 metaTask->langMetaTask = langMetaTask; |
| 925 if( slave->reqst->type == taskEnd ) //end-task is special | 1117 langMetaTask->protoMetaTask = metaTask; |
| 926 { //need to know what lang's task ended | 1118 |
| 927 taskEndHandler = semanticEnv->taskEndHandler; | 1119 return; |
| 928 (*taskEndHandler)( slave, reqst, semanticEnv ); //can put semantic data into task end reqst, for continuation, etc | |
| 929 //this is a slot slave, get a new task for it | |
| 930 if( !existsOverrideAssigner )//if exists, is set above, before loop | |
| 931 { //search for task assigner that has work | |
| 932 for( a = 0; a < num_assigners; a++ ) | |
| 933 { if( taskAssigners[a]->hasWork ) | |
| 934 { newTaskAssigner = taskAssigners[a]; | |
| 935 (*newTaskAssigner)( slave, semanticEnv ); | |
| 936 goto GotTask; | |
| 937 } | |
| 938 } | |
| 939 goto NoTasks; | |
| 940 } | |
| 941 | |
| 942 GotTask: | |
| 943 continue; //have work, so do next iter of loop, don't call slave assigner | |
| 944 } | |
| 945 if( slave->typeOfVP == taskSlotSlv ) changeSlvType();//is suspended task | |
| 946 //now do normal suspended slave request handler | |
| 947 requestHandler = semanticEnv->requestHandler; | |
| 948 //#endif | |
| 949 | |
| 950 | |
| 951 } | |
| 952 //If make it here, then was no task for this slot | |
| 953 //slot empty, hand to Assigner to fill with a slave | |
| 954 if( currSlot->needsSlaveAssigned ) | |
| 955 { //Call plugin's Assigner to give slot a new slave | |
| 956 HOLISTIC__Record_Assigner_start; | |
| 957 | |
| 958 //#ifdef MODE__MULTI_LANG | |
| 959 NoTasks: | |
| 960 //First, choose an Assigner.. | |
| 961 //There are several Assigners, one for each langlet.. they all | |
| 962 // indicate whether they have work available.. just pick the first | |
| 963 // one that has work.. Or, if there's a Unified Assigner, call | |
| 964 // that one.. So, go down array, checking.. | |
| 965 if( !existsOverrideAssigner ) | |
| 966 { for( a = 0; a < num_assigners; a++ ) | |
| 967 { if( assigners[a]->hasWork ) | |
| 968 { slaveAssigner = assigners[a]; | |
| 969 goto GotAssigner; | |
| 970 } | |
| 971 } | |
| 972 //no work, so just continue to next iter of scan loop | |
| 973 continue; | |
| 974 } | |
| 975 //when exists override, the assigner is set, once, above, so do nothing | |
| 976 GotAssigner: | |
| 977 //#endif | |
| 978 | |
| 979 assignedSlaveVP = | |
| 980 (*slaveAssigner)( semanticEnv, currSlot ); | |
| 981 | |
| 982 //put the chosen slave into slot, and adjust flags and state | |
| 983 if( assignedSlaveVP != NULL ) | |
| 984 { currSlot->slaveAssignedToSlot = assignedSlaveVP; | |
| 985 assignedSlaveVP->animSlotAssignedTo = currSlot; | |
| 986 currSlot->needsSlaveAssigned = FALSE; | |
| 987 numSlotsFilled += 1; | |
| 988 | |
| 989 HOLISTIC__Record_Assigner_end; | |
| 990 } | |
| 991 }//if slot needs slave assigned | |
| 992 }//for( slotIdx.. | |
| 993 | |
| 994 MEAS__Capture_Post_Master_Point; | |
| 995 | |
| 996 masterSwitchToCoreCtlr( masterVP ); | |
| 997 flushRegisters(); | |
| 998 DEBUG__printf(FALSE,"came back after switch to core -- so lock released!"); | |
| 999 }//while(1) | |
| 1000 } | 1120 } |
| 1001 | 1121 |
| 1122 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task | |
| 1123 * suspended at some point in its code. | |
| 1124 *For 1, just decr count of live tasks (and check for end condition) -- the | |
| 1125 * master loop will decide what goes into the slot freed up by this task end, | |
| 1126 * so, here, don't worry about assigning a new task to the slot slave. | |
| 1127 *For 2, the task's slot slave has been converted to a free task slave, which | |
| 1128 * now has nothing more to do, so send it to the recycle Q (which includes | |
| 1129 * freeing all the semData and meta task structs alloc'd for it). Then | |
| 1130 * decrement the live task count and check end condition. | |
| 1131 * | |
| 1132 *PR has to update count of live tasks, and check end of process condition. | |
| 1133 * There are constructs that wait for a process to end, so when end detected, | |
| 1134 * have to resume what's waiting.. | |
| 1135 *Thing is, the wait is used in "main", so it's an OS thread. That means | |
| 1136 * PR internals have to do OS thread signaling. Want to do that in the | |
| 1137 * core controller, which has the original stack of an OS thread. | |
| 1138 * | |
| 1139 *So here, when detect process end, signal to the core controller, which will | |
| 1140 * then do the condition variable notify to the OS thread that's waiting. | |
| 1141 */ | |
| 1142 inline void | |
| 1143 PRHandle_EndTask( SlaveVP *requestingSlv ) | |
| 1144 { void *semEnv; | |
| 1145 PRReqst *req; | |
| 1146 PRMetaTask *metaTask; | |
| 1147 PRProcess *process; | |
| 1148 | |
| 1149 req = requestingSlv->request; | |
| 1150 semEnv = PR_int__give_semEnv_of_req( req, requestingSlv ); //magic num in req | |
| 1151 metaTask = req->metaTask; | |
| 1152 //Want to keep PRMetaTask hidden from plugin, so extract semReq.. | |
| 1153 (*req->handler)( metaTask, req->semReq, semEnv ); | |
| 1154 | |
| 1155 recycleFreeTaskSlave( requestingSlv ); | |
| 1156 | |
| 1157 process->numLiveTasks -= 1; | |
| 1158 | |
| 1159 //check End Of Process Condition | |
| 1160 if( process->numLiveTasks == 0 && | |
| 1161 process->numLiveGenericSlaves == 0 ) | |
| 1162 signalEndOfProcessToCoreCtlr; | |
| 1163 } | |
| 1164 | |
| 1165 |
