QP/C++  8.0.0
Real-Time Embedded Framework
Loading...
Searching...
No Matches
Interface Viewpoint

Time ViewpointSafety Viewpoint

The Interface Viewpoint focuses on defining and describing the interfaces between QP/C++ Framework and the outside layers, such as the underlying operating system (OS Abstraction Layer) and the QP/C++ Application.

The OS Abstraction Layer (OSAL) shown in Figure SDS-OSAL, insulates QP/C++ Framework from the underlying Operating System (OS), such as one of the built-in real-time kernels, 3rd-party RTOS, or a General-Purpose OS. The OSAL provides both the abstract Operating System API (OSAL API), see Figure SDS-OSAL [2A], and the implementation of this API for the specific OS (Figure SDS-OSAL [2B]). The main idea of an OSAL is that the OSAL API is fixed and is used used inside the QP/C++ Framework source code, while the OSAL implementation (called the "QP port") depends on the specific underlying OS. In other words, there is a separate "QP port" for every supported real-time kernel, 3rd-party RTOS or GPOS. The main focus of this section is to describe the design of the OSAL API, with the specific examples are taken from various "QP ports" implementing the OSAL API.

Remarks
The OSAL is an example of the "Facade" design pattern [GoF:94].

Figure SDS-OSAL: QP/C++ Port implementing OS Abstraction Layer.

Critical Section

Critical section is a non-blocking mutual exclusion mechanism that protects a sequence of instructions from preemptions. QP/C++ Framework, just like any other system-level software, must internally use critical sections to guarantee concurrency-safe operation. The critical section implementation depends on the underlying OS, so the QP/C++ OSAL must provide an efficient critical section abstraction to insulate QP/C++ Framework from the specifics of teh underlying OS.

For example, in single-core embedded systems, critical sections are typically implemented by disabling interrupts upon the entry to the section and re-enabling them upon the exit. This is effective because in such systems interrupts are the only way preemption can be initiated (both interrupt preemption but also thread preemption in a real-time kernel). However, other systems (e.g., multicore) might use a different critical section mechanism (e.g. spin-lock). Some other systems (e.g., general purpose OS) might implement user-space critical sections with the traditional mutual-exclusion mechanism, such as a mutex. The critical section abstraction in QP/C++ OSAL must accomodate all such critical section implementations.

Note
The maximum time spent in a critical section directly affects the system's responsiveness to external events (interrupt latency and task-level response). Therefore, all critical sections inside QP/C++ Framework source code are carefully designed to be as short as possible and are of the same order as critical sections in any commercial RTOS. Of course, the length of critical sections depends on the actual critical section mechanism and the quality of the code generated by the compiler.

SDS_QP_CRIT

SDS_QP_CRIT : Critical Section API

Description
The critical section abstraction in QP/C++ OSAL consists of three parameterless macros: critical-section status, critical-section-entry and critical-section-exit.

#define QF_CRIT_STAT ...
#define QF_CRIT_ENTRY() ...
#define QF_CRIT_EXIT() ...

These macros support two main types of critical section implementations:

  1. Simple critical section entry/exit (empty definition of the macro QF_CRIT_STAT);
  2. Save-and-restore critical section status (not-empty definition of the macro QF_CRIT_STAT).

Internally, QP/C++ Framework uses the critical section macros in the following generic way:

. . . // outside critical section
. . . // outside critical section
[3] . . . // inside critical section
. . . // outside critical section
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define QF_CRIT_STAT
Definition qsafe.h:54

[1] If the macro QF_CRIT_STAT is not-empty, it allocates a local critical-section-status variable. Otherwise, if the macro is empty, the line does nothing.

[2] the macro QF_CRIT_ENTRY() enters critical section, which saves the critical section status into the status-variable (if it was defined at step [1])

[3] this code executes inside the critical section protection

[4] the macro QF_CRIT_EXIT() exits critical section, which restores the critical section status from the status variable (if it was defined at step [1])

Examples
Example simple critical section macros without critical section status (ARM Cortex-M CPU):

#define QF_CRIT_STAT // empty
#define QF_CRIT_ENTRY() (asm volatile ("cpsid i"))
#define QF_CRIT_EXIT() (asm volatile ("cpsie i"))

Example save-and-restore critical section status macros (MSP430 CPU):

#define QF_CRIT_STAT unsigned short int_state_;
#define QF_CRIT_ENTRY() do { \
int_state_ = __get_interrupt_state(); \
__disable_interrupt(); \
} while (false)
#define QF_CRIT_EXIT() __set_interrupt_state(int_state_)

Nesting Critical Sections
Some CPUs or operating systems require nesting of one critical section in another critical section. The "save-and-restore critical section status" method enables such critical section nesting in an explicit manner. But even the "simple critical section" method can be implemented in way that allows critical section nesting. For example, the critical section can use an internal up-down nesting counter, which will guarantee that only the last nesting level truly exits the critical section.
Forward Traceability

Active Object OSAL

TBD...

Time ViewpointSafety Viewpoint