Data Flow Analysis - Task, Critical Region and Event Definitions

Tasks play an important part in the operation of embedded, real-time software systems. The Task Flow Reports are a series of reports that check the implementation and interrelationships of tasks in your software. Task interactions can be complex and potentially problematic. The results reported by these checks do not necessarily indicate a deficiency in the software. Instead, they identify areas of potential conflict among your tasks, serving to focus further review efforts.

Because tasks are not explicitly designated in C/C++ programs, these reports provide you the ability to define the tasks, through the Task Definitions dialog. For each task, you specify the root function; the task is then considered to consist of the root function and all functions called directly or transitively from that root function. If tasks are not defined through the Task Definitions dialog, a task will be automatically defined for each root function in the project.

The reports also consider critical regions, ranges of statements protected by interrupt disables or semaphores. Again, these are not explicitly designated in your source code. Through the Critical Region Definitions dialog you're able to specify the functions used to enter a critical region (disable interrupt / semaphore) and to exit a critical region (enable interrupt / semaphore). The Mismatched Critical Regions and Calls in Critical Regions reports require that critical regions be defined. For the other reports, critical region definitions are optional.

The use of events for synchronization in multi-tasking systems is analyzed in two specific task flow check reports, Event Calls in Tasks and Event Transition Between Tasks. Like tasks and critical regions, event mechanisms are not explicit in C/C++ programs and need to be identified before these reports can be run. This is done through the Event Definitions dialog. Here, you specify the operating system event functions. Called by tasks, these are used to handle wait for (pend), release (post) and clear activities. This is also where you specify the events, those source code level identifiers (macros, enumeration literals, and constant variables) for the operating system shared resources used in event communications.

Once you have run the Task Flow Check reports, you can apply the full functionality of Imagix 4D to examine your software and to understand the issues flagged in the reports.

Specifying Tasks

For the Task Flow Check reports, a task is defined by the root (or entry) function for a flow of control that can be executed in the program without being explicitly invoked from inside the program. Typically, tasks can run concurrently (i.e. they execute while another part of the program executes) or quasi-concurrently (i.e. they execute for an unknown number of steps and then control transfers to another task).

For embedded real-time system, consider the following cases as tasks:

  • Any function that can be invoked asynchronously when an interrupt occurs
  • Any function that gets started by the underlying scheduler and can be stopped before completing its control flow and have the underlying scheduler transfer control to another task
  • Any starting (or root) function that might run (quasi) concurrently with other parts of the program

The following could be defined as one single task or split in separate tasks:

  • A set of functions that get always executed in the same sequence by the scheduler and never get stopped or interrupted by any other part of the program
  • A function that initializes the system is always run at startup and before any task can start. The initializer function can be included with the functions that define the operating system then

As an alternative to manually specifying the tasks yourself, you can select Auto Task to have Imagix 4D automatically define the tasks based on the rule you select.

Non-class root functions using global variablesApplies to C++ programs. Selects only functions that are not class methods and that either directly or through their callees use global or static variables. For C programs, this is the same as the next option.
Any root function using global variablesSelects all functions that are not called by another function and that either directly or through their callees use global or static variables. For C++, class methods that satisfy the condition are included.
Non-class root functionsSelects all functions that are not called by another function. For C++, this excludes any class methods. For C, this is the same as the next option.
Any root functionsSelects all functions that are not called by another function. For C++, class methods that satisfy the condition are included. This option is recommended as the default.

If a program has only one task according to this definition, then several of the Task Flow Check reports will be less meaningful. However, some of the reports will still be valuable. In particular, Mismatched Critical Regions will report issues in critical regions in the task, and Out of Step (Z) Variables will show potential sequencing issues in recurring tasks.

Specifying Events

For the event-related Task Flow Checks, the event definition includes the specification of the operating system event functions used to handle wait for (pend), release (post) and clear activities. Normally, post and clear are handled by the same function. A macro or enum literal is passed to that function to cause a clear rather than a post action. The Event Definition dialog is set up to support this.

If you happen to be using an operating system which has separate functions for post and clear, the workaround is to define a modified clear function which takes a macro as an additional argument. You would declare a new clear function, and then define the actual clear function to the new function. For example, assume that your actual clear function is named ClearEvent, and that it has one parameter. You would add the following to the compiler configuration file you are using:

void IMAGIX_ClearEvent(int event, int mode);
#define IMAGIX_CLR 1
#define ClearEvent(E) IMAGIX_ClearEvent(E, IMAGIX_CLR)
The best place to do this is in a new stand-alone file. After creating this file, you would cause it to be virtually #included by all of your source files by using the -inc option (described in the Analyzer Syntax and Options section, above).

Note that adding these #defines could lead to syntax warning messages when the source analyzer processes the declaration of ClearEvent; however, these would not cause any problems in the resulting database.

Then, in the Event Definitions dialog, you would specify IMAGIX_ClearEvent as a post event, and IMAGIX_CLR as the clear event parameter. With these changes, the event-related Task Flow Checks could distinguish between post activities and clear activities.