VR-Forces 4.3.1 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
13.6 - Executing a Plan

Table of Contents

To execute a DtPlan, its tick() function must be called.

DtPlans are ticked by the DtVrfObjectPlanManager that owns them. When the DtCgf is ticked, it ticks the DtVrfObjectManager, which ticks each DtVrfObject. DtVrfObject::tick() ticks the DtVrfObjectPlanManager. The remainder of this section discusses the details of how a DtPlan advances through its statements during execution.

13.6.1 The Initial Execution State

A plan's current statement is returned by the DtPlan::currentStmt() member function and is actually just the top entry on its execution stack (myExecutionStack). The execution stack is a list of DtStmtIndex (stmtIndex.h) objects. (DtStmntIndex is a type of smart pointer used to reference DtSimStatements.) If the execution stack is empty, currentStmt() returns an empty statement index. This is the initial state of a plan prior to execution.

13.6.2 Starting the Plan

Execution of a plan begins when the DtSimTaskManager accesses the plan for an object through its DtVrfObjectPlanManager and calls awaitingTask() on it. This starts the following process:

  1. The myAwaitingTaskFlag is set inside the DtPlan.
  2. If it is at the start of the plan (the plan is not complete, the current statement on the execution stack is NULL, and there is a valid main block), the processAwaitingTask() calls executeBlock() to start execution of the main block (myMainBlock, a DtPlanBlock) of statements. The executeBlock() function does the following:
    1. Calls setIsComplete(false), initializing the execution status of the plan to ‘not complete'.
    2. Calls setTaskRequestPending(true), indicating that the plan is waiting for a task request (an awaitingTask() call) from the entity.
    3. If the main block of statements is empty, it calls the block's DtPlanBlock::exitFromBlock() function. The plan's execution state is set to complete. If there are statements in the main block, it calls setCurrentStmt() with the first statement in the block.
    4. Calls executeStatement(). This calls the current statement's DtSimStatement::execute() function. If executeStatement() did not change the task request pending status (that is, it did not send a task to an entity), it calls continuePlan() to advance plan execution.

Each derived type of DtSimStatement implements execute() differently. The DtSimTask and DtSetDataRequestStmts execute() functions send DtTask and DtSetDataRequest statements to the entity, respectively. DtWhenStmts register themselves as triggers in the DtPlan when they are executed. As a trigger, the conditional expression in a When statement gets evaluated every tick by the DtPlan. When the condition evaluates to true, then it executes its block of statements. Triggers are discussed in more detail in 13.6.5 Triggers (or When Statements) and 13.9 - Triggers.

13.6.3 Advancing Through a Plan

The continuePlan() member function continues the execution cycle. The first time through it is called as a result of the executeBlock() member function being called on the plan’s main block. (For details, please see 13.6.2 Starting the Plan.) The protected DtPlan::continuePlan() member function continues the plan execution cycle until either the myTaskRequestPending flag is cleared, or the myIsComplete flag gets set. The execution cycle consists of alternating calls to DtPlan::stepStatement() to step the current statement pointer to the next statement, and DtPlan::executeStatement() to execute it. The loop begins with a step because the plan's current statement actually indicates the last statement executed - the one that sent the entity its previous task.

In continuePlan(), the execution cycle proceeds as follows:

  1. If the plan is complete, we are done, so return.
  2. Initialize the task request pending state to TRUE.
  3. While there is still a task request pending, call stepStatement() to advance to the next statement in the plan.
  4. If the plan is complete or there is no task request pending, we are done, so return.
  5. Call executeStatement(). This calls the current statement's execute() function.

When an entity requests a task from its plan, the plan sets its internal myTaskRequestPending flag, which remains true until a statement is executed that causes a task to be sent back to the entity. The task pending flag is used to decide when to halt the execution cycle in the member function DtPlan::continuePlan().

13.6.4 Completing a Plan

When an entity reaches the end of its plan, the plan's myIsComplete flag is set to true. This halts further execution of the plan's statements. However, pending triggers are still tested and can still fire, causing execution to resume at the start of the trigger block.

13.6.5 Triggers (or When Statements)

When statements are special kinds of statements, known as triggers. When a When statement gets executed (DtWhen::execute() is called), it creates a DtSimTrigger object and registers it with the plan as a pending trigger by calling DtPlan::addTrigger(). Each plan keeps a list of pending triggers (myPendingTriggers). In its tick() function, it periodically checks their associated conditions to determine if they should be fired. If a trigger fires, the plan must keep track of which statement was interrupted so that after the trigger block completes, execution can resume with the statement following the interrupted statement. It does so using a stack of statement index objects (myExecutionStack), stored in a DtList.

13.6.6 Abandoning a Plan

You can have an entity abandon execution of its plan by accessing its DtPlan through its DtVrfObjectPlanManager and calling abandonPlan() on it.This results in the plan setting its status to complete.

[<< Examining and Changing Plans] [Home] [Top of Page] [Statements >>]


Document ID: Generated on Wed Jul 29 00:55:00 EDT 2015 from SVN revision 155257
Copyright © 2005-2015 VT MÄK. All Rights Reserved (www.mak.com)