Previous: , Up: Component Imperative Statements   [Contents][Index]


10.5.5.5 Component defer

defer is a keyword that may be placed in front of an imperative statement.

defer-statement
              ::= "defer" argument-list? imperative-statement
argument-list ::= "(" ")" | "(" expression ("," expression)* ")"

defer indicates that the execution of the corresponding statement must be postponed at least until after returning back to the caller. Note that in order for the deferred statement to execute, the surrounding system must have reached an overall state where it can accept new activating events, i.e., this state is a system wide run to completion state.

The primary goal of defer is to decouple the execution of an imperative statement from the caller. This allows implementing an asynchronous interface almost as concisely as implementing it synchronously, as demonstrated by the example below.

interface ihelloworld
{
  in void hello ();
  out void world ();
  behavior
  {
    bool idle = true;
    on hello: world;
    [idle] on hello: idle = false;
    [!idle] on inevitable: {
      idle = true;
      world;
    }
  }
}

component synchronous_asynchronous
{
  provides ihelloworld h;
  behavior
  {
    bool synchronous = false;
    [synchronous] on h.hello (): h.world ();
    [!synchronous] on h.hello (): {
      synchronous = true;
      defer {
        synchronous = false;
        h.world ();
      }
    }
  }
}

Here we can observe the difference between synchronous and asynchronous behavior once more. When the synchronous boolean equals true the world action occurs in the context, e.g. between the hello and its return. When synchronous equals false the world action occurs after the return. This behavior is clearly depicted by the following state diagram.

images/defer

Perhaps the idle state might seem superfluous in the example above, however it is not. Besides resulting in component behavior which is not compliant with its interface, removing the idle state and the corresponding guard would allow a client to do multiple consecutive h.hello’s, which results in an overflow of the defer queue.

Besides state playing a role in avoiding defer queue overflow, there is another aspect related to state and the use of defer. In order for the deferred statement to execute, the component must remain in the same state as it was at the time of invoking defer. Anything that changes the state of the component after invoking defer but before the deferred statement executes will remove it from the queue, and thereby implicitly cancel it. This is demonstrated by the example below. Note that a data member variable is not part of the component state, and changing its value does not cancel the deferred statement.

interface ihellocruelworld
{
  in void hello ();
  in void cruel ();
  out void world ();
  behavior
  {
    bool idle = true;
    [idle] on hello: idle = false;
    [!idle] on inevitable: {
      idle = true;
      world;
    }
    on cruel: idle = true;
  }
}
component defer_cancel
{
  provides ihellocruelworld h;
  behavior
  {
    bool idle = true;
    [idle] on h.hello (): {
      idle = false;
      defer {
        idle = true;
        h.world ();
      }
    }
    on h.cruel (): idle = true;
  }
}

Here we see that the cruel event makes the component idle again and in compliance with the interface this implies that the world event can no longer occur. The corresponding component state diagram is depicted below.

images/defer-cancel

The ability to cancel a deferred statement is not always desirable. The way to influence the skip behavior is to add an argument list of state variables to the defer keyword. This limits the scope of the state which is observed by defer in deciding when to skip the execution. The two extreme cases are:

We can see an example of a defer argument list below.

interface ihelloworld
{
  in void hello ();
  out void world ();
  behavior
  {
    bool idle = true;
    on hello: world;
    [idle] on hello: idle = false;
    [!idle] on inevitable: {
      idle = true;
      world;
    }
  }
}

interface icruel
{
  in void cruel();
  behavior
  {
    on cruel: {}
  }
}

component defer_selection
{
  provides ihelloworld h;
  provides icruel c;
  behavior
  {
    bool synchronous = false;
    bool cruel = false;
    on c.cruel(): cruel = !cruel;
    [synchronous] on h.hello (): h.world ();
    [!synchronous] on h.hello (): {
      synchronous = true;
      defer(synchronous) {
        synchronous = false;
        h.world ();
      }
    }
  }
}

Here the execution of the deferred statement must remain unaffected by the change to the cruel state variable. We can achieve this by only observing the state variable as the example shows or not observing any state at all. The latter case is left as an exercise to the reader.


Previous: Component reply, Up: Component Imperative Statements   [Contents][Index]