[Top] [Prev] [TOC] [Next] [Bottom]

Porting the TargetRTS for C++


TargetRTS configuration definitions

Much of the configurability of the TargetRTS is done at the source code file level: target-specific source files override common source files. This is illustrated in the next section on platform-specific implementations. However, configurability is also available within a source file using C preprocessor definitions. The configuration is set in two C++ header files:

Platform-specific implementation

The implementation of the TargetRTS is contained in the $RTS_HOME/src directory. In this directory, there is a subdirectory for each class. In general, within each subdirectory there is one source file for each method in the class. Wherever possible, the name of the source file matches the name of the method.

To port the TargetRTS to a new platform, it may be necessary to replace some of these methods. Additionally, some of the methods that do not have default behaviors must be provided. The target-specific source is placed in a subdirectory of $RTS_HOME/src/target/<target_base>, where <target_base> is the target name without the `S' or `T'. For the remainder of this section, the target directory is referred to as $TARGET_SRC. For example, the target source directory for <target> PSOS2T is $RTS_HOME/src/target/PSOS2. This directory provides an overlay to the $RTS_HOME/src directory. When the TargetRTS loadbuild tools search for the source for a method, it searches first in the $TARGET_SRC directory then in RTS_HOME/src.

Note: There is only a single source directory for all configurations of the TargetRTS for a given platform. C++ preprocessor macros, such as USE_THREADS, may be used to differentiate code for specific configurations.

There is a sample port in the sample subdirectory to use as a template for a port to a new target. These implementations can be incorporated into a target implementation by copying or creating soft links for the contents of these subdirectories into the $TARGET_SRC directory. You may also want to search the other target subdirectories to verify that the implementation of various TargetRTS classes resembles your target RTOS. You can copy any required code to the new $TARGET_SRC directory.

Table 6 on page 49 shows the classes and functions that must be provided in any port of the TargetRTS. These are the minimum requirements for a new port, as most ports will include changes to more classes than those listed.
Required TargetRTS Classes and Functions

Required TargetRTS Classes and Functions


RTTimespec::getclock()


RTThread::RTThread()


RTMutex


RTSyncObject

The remainder of this section discusses the most common required implementation code required for a new target.

Main function

In order for the execution of the TargetRTS to begin, code must be provided to call RTMain::entryPoint( int argc, const char * const * argv ) passing in the arguments to the program. This code is placed in the file $TARGET_SRC/MAIN/main.cc. See the description of the RTMain class in the C++ Target Guide for more information on entryPoint.

On many platforms, this is the code for the main function, which simply passes argc and argv directly. However, on other platforms, these parameters must be constructed. For example, with VxWorks, the arguments to the program are placed on the stack. An array of strings containing the arguments must be explicitly created.

If the platform does not provide a mechanism for passing arguments to an executable, the arguments for entryPoint can be defined in the toolset. These arguments are made available by the code generator in the global variables default_argv and default_argc. The code in main.cc must explicitly pass these values to entryPoint. For more information, see "Application-specific command line arguments" on page 115 of the C++ Language Guide.

Class RTMain

RTMain::entryPoint() calls a number of methods for target-specific initialization and shutdown. For a more detailed discussion of class RTMain, see the description of the RTMain class in the C++ Target Guide. These methods are as follows:

Method RTTimespec::getclock()

To implement the Timing service, the TargetRTS uses the time of day clock. The method RTTimespec::getclock(), found in the file $TARGET_SRC/RTTimespec/getclock.cc, gets the time of day from the operating system. There is no default implementation of this method and it must be provided by the target. The format of this time of day is the POSIX-style struct timespec which contains two fields: the number of seconds and the number of nanoseconds from some fixed point of time. This fixed point is usually the Universal Time reference point of January 1, 1970. This does not need to be the case. However, to support absolute time-outs, the
TargetRTS assumes that the reference time is midnight of some day.

Class RTThread constructor

To support multi-threading, the TargetRTS provides the class RTThread. See the description of the RTThread class in the C++ Target Guide for more information. The target implementation must provide the constructor for this class in the file $TARGET_SRC/RTThread/ct.cc.

Class RTMutex

In the multi-threaded TargetRTS, shared resources are protected using mutexes implemented by the class RTMutex. See the description of the RTMutex class in the C++ Target Guide for more information. There is no default declaration or implementation of RTMutex that must be supplied by the target. The header file for the RTMutex class should be placed in the file $TARGET_SRC/RTMutex.h. There are four methods to RTMutex:

Class RTSyncObject

An additional synchronization mechanism used by the TargetRTS is implemented by class RTSyncObject. See the description of the RTSyncObject class in the C++ Target Guide for more information. Many operating systems provide what is known as a `binary semaphore'. A synchronization object is essentially the same thing. Many implementations of a semaphore, however, do not provide a wait (or `pend') with time-out. The lack of this time-out feature requires the use of a more heavyweight implementation using a mutex and a condition variable (POSIX condition variables have a `timedwait' feature). A description of each method can be found in the $(RTS_HOME)/src/target/sample/RTSyncObject directory. There is no default declaration or implementation. The header file for the RTSyncObject should be in the file $TARGET_SRC/RTSyncObject.h. The implementation of five methods is required:

Class RTDiagStream

The RTDiagStream class handles output of diagnostic messages to the standard output. If your target does not support the fputs() function then you must supply a replacement for the RTDiagStream::write() function. This function outputs a string to the standard output device.

Class RTDebuggerInput

The RTDebuggerInput class handles the input to the TargetRTS debugger. If your target system does not support the fgetc() function, then you must supply a replacement for the RTDebuggerInput::nextChar() function. This function reads individual characters from the standard input device.

Class RTTcpSocket

The RTTcpSocket class provides an interface from the TargetRTS to the sockets library of the target operating system. Many operating systems provide the familiar BSD sockets interface. If this is the case then little modification is necessary. Typically, small changes to data types are needed to satisfy the sockets interface.

Class RTIOMonitor

The RTIOMonitor class is used to monitor activity on a set of TCP/IP sockets. This class makes use of file descriptor sets and the select() function. There may be differences in the way these sets are implemented on your target operating system.

Class RTIOController

The RTIOController is the class used by the ioController thread in the external layer. It makes use of several TCP sockets calls. Problems encountered here will be similar to those described in "Class RTTcpSocket" on page 51.

File main.cc

The file main.cc contains the main function for the TargetRTS and therefore the entire application. Some operating systems already have a main function defined. This file must be modified to take this into account. A typical solution is to create a root thread, which in turn calls the entry point to the
TargetRTS (RTMain::entryPoint).

Adding new files to the TargetRTS

If you create a new file for an existing class or you are adding a new class to the TargetRTS then you must add the new file names to a manifest file for the TargetRTS. This must be done in order for the dependency calculations to include the new files and thus include them into the TargetRTS.

The MANIFEST.cpp file

This file lists all the elements of the run-time system. There is one entry per line. Each entry has three or more fields separated by whitespace. The first names a make variable, which will include the name of the object file for that entry. The second field is a directory name. The third field is the base name of a file. By convention the directory name and file name typically correspond to the class name and member name, respectively. The fourth and subsequent fields, if present, give an expression that evaluates to zero when the element should be excluded. Note that the expression is evaluated by Perl and so should be of a form that it can handle.

If you have added a new file to the TargetRTS, you must have an entry in the MANIFEST.cpp file for the file. By convention, the entry should be placed next to the other files for the specific class that you have modified. If you are adding a class then place the entries next to the super class if it exists or next to similar classes in the manifest file.

Regenerating make dependencies

If a file has been overridden in $(RTS_HOME)/target/src/<target_name> directory or a new file has been added to the MANIFEST.cpp you must regenerate the make dependencies in order for the modification to be included in the new TargetRTS. This is done by removing the depend.mk file in the build directory ($(RTS_HOME)/build-<platform_name>). This will cause the dependencies to be recalculated and a new depend.mk file to be created.

Note that include statements should not normally be put in areas considered conditional by the pre-processor (that is, between #if/#endif pairs). The dependency discovery script does not evaluate expressions used in preprocessor #if statements, and assumes these expressions to be true. Consequently, the dependency discovery script may capture more include statements than the preprocessor. However, although it may calculate more dependencies than the optimal amount, the dependency discovery script does detect and avoid endless loops of #include statements.



[Top] [Prev] [TOC] [Next] [Bottom]

support@objectime.com
Copyright © 1998, ObjecTime Limited. All rights reserved.