RTSync Tutorial 6 - More on Synchronizers

In the last tutorial, synchronizers were introduced and two of their blocks were described. The other two blocks contained in a synchronizer are the trigger and exception blocks.

The trigger block is a rather complex block. Here, methods can be enabled or disabled, or event-triggered code can be called. There are three types of statements that can be put in the trigger section: enable statements, disable statements and action statements.

Enable and disable statements are fairly simplistic. These statements can enable or disable methods according to some condition. The syntax of these statements is as follows:

  enable actor.method when conditional_expression1;
  disable actor.method when conditional_expression2;

As soon as conditional_expression1 is true, the method will be enabled (by default all methods are enabled) and as soon as conditional_expression2 is true, the method will be disabled. Remember that once a method is disabled/enabled, the method will remain that way unless explicitly changed. This means that when conditional_expression2 becomes true, actor.method() will be disabled, but it won't actually become enabled again when conditional_expression becomes false unless an enable statement is created to tell the synchronizer to re-enable the method.

A problem with disabling methods is if one method tries to make a synchronized call (a call using the sync keyword) to a disabled method, it will block until the method is enabled again and finishes running. This can cause some unpredictable results, as some actors will then stall when they should be running.

The third statement that can be used in the trigger block is the action statement. This statement simply executes some code whenever a particular method is called. This allows for the synchronizer to take some action when a particular method is called. The syntax for the statement is as follows:

  action(actor.method)
  {
      executable_code
  }

Whenever actor.method() is called, executable_code is executed. Why is this needed, if executable_code can just be placed in actor.method()? One reason this is needed is that actor.method() does not have access to the synchronizer's variables, so for example if the synchronizer would like to keep track of how many times this method has been called, it can keep a member variable here and increment the variable each time this action block is executed (and possibly disabling the method or enabling another method when the variable hits a certain value, or do something else).

The fourth block of the synchronizers is the exception block. This is a very simple block, with a very simple syntax:

  exception{
      exception_code
      return_statement
  }

When a timing violation occurs in this synchronizer, exception_code is executed. A timing violation occurs when a message being sent is not sent before the deadline has passed (the car has crashed into a tree, or missed the turn).

The one difference between the exception block and other blocks is that the exception block will return a value depending on what the system should do when the exception is thrown. The exception block may return one of three values:

TERMINATE: Terminate the entire system, the program on all computers will be shut down.
KILLNODE: Terminate the system on this computer, systems on other computers are unaffected.
CONTINUE: Continue running the program on all systems.

If no return statement is specified, the default return value is TERMINATE.