![]() |
![]() |
![]() |
![]() |
![]() |
Tight Integration
The source file and examples for Tight Integrations are not included in the standard delivery. They are available as free downloads from the IBM Rational Support web site.
There are two models of Tight Integration. In the Standard Model one SDL process instance is mapped to one OS task. In the Instance Set Model an entire instance set (all instances of a process) is mapped to one OS task. Scheduling between OS tasks is managed by the RTOS scheduler; this means that preemption is normally used, though only on an instance set level in the Instance Set Model. SDL semantics are preserved in a Tight Integration, for example setting a timer implies an automatic reset first.
The start-up of a system, i.e. creation of static processes, initialization of synonyms and creation of an environment task and a timer task, is handled by a generated initialization function called yInit. Normally this function is called from another initialization function, where some additional initializations take place before the yInit function is called.
Timers in the system are handled by one central timer task. This task receives messages1, each containing a request to set a timer, and will send messages back as the timers expire.
Common Features
File Structure
The files related to the tight integration concept can be found in the following directory structure after extracting the RTOS integration: .../RTOS/TightIntegrations/<RTOS>/TightIntegration/. The same files are used for both the Standard Model and the Instance Set Model.
Each RTOS directory contains the following files:
- sct<RTOS>.h:
- This file contains the second level of macros (see the comments for scttypes.h in The Integration Packages). All macros are using OS-specific calls or types.
- sct<RTOS>.c:
- sdt2<RTOS>.c:
- Most RTOS require that signals/messages are represented with an integer value. This is the source file for a utility program for generating signal identities. Each signal will be assigned an integer value. The output will be a file with the suffix .hs. This file is automatically included in the application.
- In the SDL Suite, the .hs file can also be generated by the SDL to C Compiler by turning on the option Generate signal number file in the Make dialog. The .hs file is included in the application if the compilation switch XINCLUDE_HS_FILE is set.
The SDL_PId Type
The SDL_PId (SDL Process ID) type has different meanings in the Standard and the Instance Set Models. In the Standard Model it represents the message queue, while it represents the process instance in the Instance Set Model. This is because the entire instance set will have the same message queue in the last case.
#ifdef X_ONE_TASK_PER_INSTANCE_SETtypedef xEPrsNode SDL_PId;#elsetypedef MSG_Q_ID SDL_PId;#endifSignals
The signal header consists of a struct with information needed to handle the signal inside an SDL system. The signal header struct is defined in the RTOS-specific file sct<RTOS>.h.
typedef struct xSignalHeaderStruct *xSignalHeader;typedef struct xSignalHeaderStruct {int SignalCode;xSignalHeader Pre, Suc;SDL_PId Sender;void *SigP;#ifdef X_ONE_TASK_PER_INSTANCE_SETSDL_PId Receiver;#endif#ifdef XMSC_TRACEint SignalId;int IsTimer;#endif} xSignalHeaderRec;The signal header stores SignalCode, in this case an integer, two pointers Pre and Suc used when saving the signal in the save queue, and Sender, holding the SDL_PId of the sending SDL process. In the Instance Set Model there is an extra parameter Receiver, necessary to make a distinction between the SDL processes in an instance set task.
If the signal contains parameters they are allocated in the same function call. Example:
OutputSignalPtr = xAlloc (sizeof (xSignalHeaderRec) + sizeof(yPDef_z05_s2));The second parameter to the xAlloc function is a struct representing the signal parameters of the signal. In this case, with one integer, it is defined in the following way:
typedef struct {SIGNAL_VARSSDL_Integer Param1;} yPDef_z05_s2;The macro SIGNAL_VARS is in most RTOS empty.
There is an extra element in the SignalHeader defined as a void pointer. This pointer SigP is set to point to the parameter area.
OutputSignalPtr->SigP = OutputSignalPtr+1;This pointer is used in the Signal-Free-Function to address the parameter-part of either a signal-structure as also a timer-signal-structure.
The SDL signal parameters are always named Param1, Param2, etc.
Assignment of the signal parameter is done in generated code and not in a macro. Example:
SIGNAL_ALLOC_ERRORyAssF_SDL_Integer(((yPDef_z05_s2*)OUTSIGNAL_DATA_PTR)->Param1 ,yVarP->z023_param1,XASS);The macro OUTSIGNAL_DATA_PTR macro is defined:
#define OUTSIGNAL_DATA_PTR (yOutputSignalPtr->SigP)After expansion of the whole expression the code will be:
((yPDef_z05_s2 *) ((xSignalHeader) yOutputSignalPtr + 1))->Param1 = yVarP->z023_param1;Signal reception
The support function xInputSignal is used for receiving signals in both models of Tight Integration. The implementation and the parameters are different though.
Timer Signals
A timer signal is defined similarly to an ordinary signal but will contain some additional elements representing time-out time, etc. The timer header struct looks like this:
typedef struct xTimerHeaderStruct *xTimerHeader;typedef struct xTimerHeaderStruct {int SignalCode;xTimerHeader Pre, Suc;SDL_PId Sender;void *SigP;#ifdef X_ONE_TASK_PER_INSTANCE_SETSDL_PId Receiver;#endif#ifdef XMSC_TRACEint SignalId;int IsTimer;#endifSDL_Time TimerTime;int TimerToSetOrReset;xbool (* yEq)();xbool TestParams;xTimerHeader Param;} xTimerHeaderRec;
An ordinary signal is identical to the first part of a timer signal. This makes it possible to type-cast between the two types as long as only elements in the common part of the headers are used.
Time
When the System time is required, for example when using NOW, the macro SDL_NOW is used. The macro is in turn mapped to the function SDL_Clock() (in sctos.c). This function is implemented differently depending on the RTOS representation of time. In VxWorks it returns the result of calling the RTOS function tickGet. SDL_Time is normally implemented as int or unsigned long int.
Mapping Between SDL Time and RTOS Time
The macro SDL_DURATION_LIT specifies the mapping between the SDL time in seconds and the local RTOS representation of time. In VxWorks the system time is given in ticks and the translation is defined as follows:
#define SDL_DURATION_LIT(R,I,D) \((I)*1000 + (D)/1000000)R is the real type representation of the time in seconds. I and D are the integer and decimal parts of an integer type representation of the time. I is in seconds and D in nanoseconds. The code generator will generate all three numbers but either R, or I and D will be used depending on the RTOS.
Timers
All timer activity in the SDL system is handled by a dedicated timer task. The timer task accepts requests in the form of messages (in VxWorks). It then keeps the requests for setting a timer sorted in a timer queue and uses some OS mechanism to wait for the first request to time out. The mechanism used can be either an OS timer, or a timeout in the waiting for new requests. When a request times out, the timer task sends a signal back to the task that first sent the request. The function calls and OS signaling involved in setting and waiting for an SDL timer can be viewed in Figure 572.
To be able to implement the full semantics of SDL timers a number of support functions have been implemented:
- xSDLActive
- xSDLActiveInTimerTask
- xSDLReset
- Resets an SDL timer by sending a request to the timer task. While waiting for a reply all new signals to the calling task are saved in the save queue. In the case of an Instance Set Model Tight Integration this means that no instance of the process can execute a transition until a reply is received. If the reply states that the timer couldn't be found it might be in the save queue or the input queue of the task because it has recently expired. If so, it is simply removed. SDL semantics require that a reset is always performed implicitly prior to setting a timer.
- xSDLResetInTimerTask
- Called by the timer task when a request has been made for resetting a timer. Checks the timer queue to see if the timer to reset is there. If the timer is found, it is removed and the data area it holds is freed. A message is sent back to the task that made the request, telling whether the timer was found or not.
- xSDLSet
Addressing SDL Processes
There are two ways to address SDL processes from an external task. Either the xFindReceiver function can be called to find an arbitrary receiver, or the file pidlist.pr can be used to provide a list of the SDL processes and then address the receiver explicitly via the input queue ID of its OS task.
The xFindReceiver Function
When sending a signal into the SDL system where the receiver is not known a support function called xFindReceiver can be used. This function takes the following parameters:
- The ID of the signal
- The sender ID (in this case an SDL_PId representing the environment)
- An optional VIA-list.
The following files are needed to get access to SDL types, signal numbers and signal parameter types: scttypes.h, <system_name>.hs and <system_name>.ifc.
Example of how to use the xFindReceiver function:
#include "scttypes.h"#include "<system_name>.ifc"#include "<system_name>.hs"void MyExtTask(void) {xSignalHeader yOutputSignalPtr;int Err;/*Allocate signal header and signal parameterbuffer */yOutputSignalPtr =(xSignalHeader)xAlloc(sizeof(xSignalHeaderRec)+ sizeof(yPDef_go);/*Setup signal header */yOutputSignalPtr->SignalCode = go;yOutputSignalPtr->Sender = xEnvPId;/*Give value 100 to integer parameter */((yPDef_go *)(yOutputSignalPtr+1))->Param1 = 100;/*Send signal from environment */Err = msgQSend(xFindReceiver(go, xEnvPrs, 0),(char*) yOutputSignalPtr,sizeof(xSignalHederRec)+sizeof(yPDef_go),0 ,0);}The following types, signal definitions and global variables are used in the example:
- xEnvPId: An SDL PId representing the environment, from scttypes.h
- xEnvPrs: A PrsNode representing the environment, from scttypes.h
- xSignalHeader: A datatype representing an SDL signal, from scttypes.h
- yPDef_go: A datatype representing the signal parameter types, from <system_name>.ifc
- go: An SDL signal, from <system_name>.ifc
The File pidlist.pr
An alternative way to get the PId for the Receiver is to use an ADT defined in the ADT library called pidlist.pr. This file defines an ADT called PidList and an operator called PId_Lit. With this ADT it is possible to directly address any static process instance in the system, both from internal SDL processes and from external OS-tasks. You can find more information about this feature in How to Obtain PId Literals.
If you need the pidlist.pr ADT in a Tight Integration then you must use the version in the .../RTOS/TightIntegrations/SDL/ directory.
The Standard Model
In the Standard Model of the Tight Integration each SDL process is implemented as an OS task. Preemption and the use of process priorities is only limited to what the OS supports.
Processes
Process Creation
An SDL process is created in the following way (in the VxWorks integration):
- A start-up signal is allocated.
- A message queue is created. Some operating systems create the message queue automatically when the task is created. This is explained for each operating system in the annexes to this chapter.
- The task is created with the message queue ID as a start-up parameter. In the case of VxWorks, the task will have a name starting with VXWORKSPAD_. This is a function which will first initialize some internal variables and then call the PAD function.
- A function (xAllocPrs) is called to create a representation of the new instance in the global symbol tree.
- The start-up signal is sent. When this signal is received in the task the start transition of the process is executed.
Process Termination
The following actions are carried out when a process terminates:
- The save queue and the message queue are emptied.
- The save queue is deleted.
- A message is sent to the xTimerTask with a request to remove all active timers of the process.
- xFreePrs is called to free the PrsNode.
- The message queue is deleted. In some operating systems this is done automatically when the task is deleted.
- The task is deleted.
PAD functions
Each PAD (Process Activity Definition) function will contain an eternal loop with an OS receive statement. When a process instance is created it is the PAD function that is called in the OS Create primitive.
The start-up and execution of a PAD function works like this:
- The support function xInputSignal is called. This function will wait for the start-up signal, that is always received first, and then return to the PAD function.
- The PAD function goes to the label Label_Execute_Transition. This label is the start of a code block containing a switch statement that evaluates the process variable RestartAddress. The code under each different case then represents a transition. At the end of this block the process variable State is updated and execution continues at Label_New_Transition.
- In Label_New_Transition a new call is made to xInputSignal and execution then continues at Label_Execute_Transition.
The structure of a PAD function is described below (with pseudo-code shown in italics):
void yPAD_z01_pr1 (void *VarP){Variable declarationsxInputSignal is called to receive the start-up signal...........goto Label_Execute_Transition;...........Label_New_Transition:xInputSignal is called to receive a signalLabel_Execute_Transition:Local declarationsswitch (yVarP->RestartAddress) {case 0:Execute the start transitionUpdate the process state variablegoto Label_New_Transition;case 1:Execute the transitionUpdate the process state variablegoto Label_New_Transition;...........}...........}Scheduling
Since each SDL process is implemented as an OS task, scheduling between processes will be handled completely by the OS.
Start-up
Start-up of a Standard Model Tight Integration can be described as follows (pseudocode is shown in italics):
MyMain() {/* initialization of semaphores etc */yInit();Give startup semaphorestaskSuspend(Mymain);}yInit() {Create the timer taskCreate an environment task or only an environment queuefor(i=1;i<=NoOfStaticProcessTypes;i++){for(j=1;j<=NoOfStaticInstancesOfEachProcesstype;j++){Allocate a startup signalCreate a message queueCreate a taskCall xAllocPrsSend the startup signal}}Assign SDL synonyms}The semaphore is used for synchronizing start-up of static processes. No static process is allowed to execute its start transition before all static processes are created, because a start transition can have signal sending to other static instances.
The MyMain function is placed among other support functions in the file sctsdl.c.
The yInit function is generated by the code generator and placed last in the generated file for the system.
The Instance Set Model
The Instance Set Model is based on the same principles as the Standard Model with the difference that the instance set is the basic unit rather than the process instance.
Processes
Both the instances and the instance sets are represented in the symbol table. In addition to the three parts that always make up an SDL process there is also an extra struct for the instance set, defining for example the input queue which is common to all the instances. Further, there is a PAD function for each instance, but also for the instance set.
Process Representation
An SDL_PId is represented by an xEPrsNode, pointing to an xEPrsStruct. An xEPrsNode also represents a process instance in the symbol table both in the Standard Model and the Instance Set Model.
typedef struct xEPrsStruct {xEPrsNode NextPrs;SDL_PId Self;xPrsIdNode NameNode;int BlockInstNumber;xPrsNode VarP;} xEPrsRec;Instance Set Data
The datatype xPrsInstanceSetVars is only used in the Instance Set Model. It defines common data for all instances of the set, like the save queue and the size of the instance data.
typedef struct {xSignalHeader SaveQ;xSignalHeader CurrentInSaveQ;xSignalHeader yInSignalPtr;char name[100];unsigned PrsDataSize;} xPrsInstanceSetVars.PAD functions
In the Instance Set Model there is a PAD function for each process instance but also for each instance set. The instance set PAD functions will be called at system start-up and contain an eternal loop in the same fashion as PAD functions in the Standard Model. Instance PAD functions are only called to execute transitions.
Process Creation
All instance sets, even for dynamic processes, are created at system start-up. Since the OS task and the signal queues are created with the instance set, the creation of an instance requires less labor than in the Standard Model. For the instance set creation the macro INIT_PROCESS_TYPE is used.
Process Termination
The instance set task is never terminated. Termination of a process instance will not remove the save queue, the input queue and the task. This is done at system termination. All queues, including the active timer queue, are emptied of messages to the terminated process though.
Signal queues
The message queue id of the receiver's instance set is accessed through NameNode in the receiver's xEPrsStruct and the variable PROCID.
Example from xSDLResetInTimerProcess:
Err=msgQSend ((MSG_Q_ID) (yInSignalPointer->Sender)->NameNode->PROCID, (char *) yInSignalPointer,sizeof (xTimerHeaderRec), 0, 0);In this case the receiver is the same as the original sender.
Signal sending
A support function xHandle_Sig is used when sending signals, instead of the macro RTOSSEND as in the Standard Model. This difference is shown in bold in the code below:
#ifdef X_ONE_TASK_PER_INSTANCE_SET#define SDL_2OUTPUT(PRIO, VIA, SIG_NAME, SIG_IDNODE,\RECEIVER, SIG_PAR_SIZE, SIG_NAME_STRING)\XOS_TRACE_OUTPUT(SIG_NAME_STRING) \XMSC_TRACE_OUTPUT(RECEIVER, yOutputSignalPtr, \SIG_NAME_STRING) \xHandle_Sig(yOutputSignalPtr,SDL_SELF,SIG_PAR_SIZE,\RECEIVER,(RTOSTASK_TYPE)RECEIVER-> \NameNode->PROCID RTOSHANDLESIG_PAR);#else#define SDL_2OUTPUT(PRIO, VIA, SIG_NAME, SIG_IDNODE, \RECEIVER, SIG_PAR_SIZE, SIG_NAME_STRING)\XOS_TRACE_OUTPUT(SIG_NAME_STRING) \XMSC_TRACE_OUTPUT(RECEIVER, yOutputSignalPtr,\SIG_NAME_STRING) \RTOSSEND(&yOutputSignalPtr, RECEIVER,SIG_PAR_SIZE)#endifScheduling
Scheduling between instance sets is handled by the operating system. Within the instance sets, however, scheduling is based on the signal queue. When the instance set PAD function is executing, it takes the first signal in the input queue and calls the PAD function of the addressed SDL process. The instance PAD function then executes one transition and returns control to the scheduling loop of the instance set PAD function.
Integrating with external code
You can easily integrate the SDL system with external code, for example written in C. Just use the hooks described below for inserting C statements in the main() function of the SDL system.
The hooks are in the form of #define macros located in a file called scthooks.h. A file called scthooks.h_template with empty macros can be found in the INCLUDE directory. Use this file as a template for your own application. You will find usage examples in the Examples directory.
This hook lets you declare function prototypes etc. at file scope.
This hook lets you declare variables for use in the main() function.
Any code inserted here will execute first in the main() function.
HOOK_MAIN_AFTER_PROCESS_RELEASE
Any code inserted here will execute as soon as all static processes have been created and are allowed to run.
HOOK_MAIN_AFTER_SIGNAL_RECEPTION
The main() function of the SDL system enters an infinite loop after having created all static processes. This loop is used to receive signals sent to the environment queue.
Use the HOOK_MAIN_AFTER_SIGNAL_RECEPTION to insert code for processing these signals.
1
http://www.ibm.com/rational |
![]() |
![]() |
![]() |
![]() |