RTSync - Overview

The principle behind RTSync is to provide a time-constrained, distributed programming language in a familiar setting. The programmer does not need to know about networking, only how to program using the C++ language.

The code that is included in the tarball contains two main components: the compiler and the run- time environment. The compiler is responsible for converting the RTSync code into C++ code and performing a simple analysis of the timing constraints. The run-time environment is responsible for handling the networking components of the system and enforcing the time constraints.

Compiler Overview

The compiler uses a large tree to analyze the code. The syntax of the language is specified in the two files: parser.yacc and scanner.lex. The programs lex and yacc are required to compile the compiler, since these two programs are what generate the large tree. After the tree is constructed, Several “visitors” are created and traverse through the tree. Each segment of the code has a certain label, for example all the code in a synchronizer will be contained in a synchronizer node. The children of this node are the various parts of the synchronizer, such as the variable declarations, the initialization block, the constraint block, etc. Each of those blocks may then have some children as well.

There are three types of visitor: the code visitor, the scope visitor and the global synchronizer visitor. The code visitor traverses the tree and outputs the C++ code, the scope visitor does type- checking and scope-checking on identifiers, and the global synchronizer visitor is a special visitor that handles global synchronizers. When the compiler is run and the tree has been generated, the code visitor then the scope visitor scans over the code and begins to convert it to C++ code. If a global synchronizer is encountered, a global synchronizer visitor is created to analyze it.

After the code has all been generated, a “sanity check” is done. What this does is checks the timing constraints of the synchronizers to see if there are any impossible situations (like if a minimum constraint is less than a maximum constraint).

If all goes well while compiling the code, an output file is created that is compilable by a C++ compiler. Note that the boost and POSIX libraries are required to compile this file.

Run-Time Environment (RTE) Overview

The RTSync run-time system is designed to be a message-based, distributed system. Each computer that is running the program has an object created called the “postmaster”. The postmaster handles connecting to the other computers, sending messages and handling communications between actors and synchronizers. When a postmaster is created, it can either run a method or it can just start and wait for messages from other postmasters.

The handling of timing constraints and trigger execution is done by the synchronizer object. All synchronizers inherit from the synchronizer class that provides the necessary method prototypes for the synchronizers generated by the RTSync compiler. These include the proper methods for constraint checking, action notification, and trigger polling. Constraint checking is simple, when a method is called, a notification is sent to the synchronizer that contains information about when the method was sent and received. If this notification violates a timing constraint, then an exception is thrown by calling the generated exception handler. Action notification is done by using an action listener pattern, where the synchronizer must define a method called notify_action() that takes as parameters information about a method call. When this method is called, then the synchronizer runs through the action statements in the trigger block to see if this particular method call should trigger an action. Finally the trigger polling is where the synchronizer checks all of the enable/disable statements to see if any methods should be enabled or disabled.

The actor objects simply have their methods redefined using C++ code, and a few functions that handle the receiving of messages from the postmaster. When the message is received, the proper method is run and a message is then sent back to the postmaster with the appropriate information added (such as the time the message was actually received).