QP/C  7.3.4
Real-Time Embedded Framework
Loading...
Searching...
No Matches
Non-Preemptive Kernel

Software TracingPreemptive Non-Blocking Kernel

Concepts & Definitions

The Active Object model of computation can work with a wide range of real-time kernels. Specifically for the kernel discussed in this section, an Active Object requires an execution context only during the RTC (Run-to-Completion) processing and an Active Object that is merely waiting for events does not need an execution context at all. This opens up possibility of executing multiple Active Objects in a single thread (e.g., the main() function in C or C++).

QV Non-Preemptive Kernel

QV is a simple non-preemptive, cooperative, fixed-priority, event-driven kernel integrated with the QP Framework. QV is non-preemptive because it executes all Active Objects in the system in a single loop (similar to the traditional "superloop", a.k.a. "main+ISRs" architecture), so Active Objects cannot preempt each other. The QV kernel is based on a fixed-priority based scheduler that always selects the highest-priority Active Object ready to run (with some event(s) in its queue). When such Active Object is found, QV executes the RTC step in this Active Object and then loops back. That way, Active Objects cooperate to share a single "superloop" and implicitly yield to each other after every RTC step.

Figure 10_01: QV non-preemptive kernel operation. ISRs can preempt the "superloop" at any time when interrupts are not explicitly disabled.
Note
The QV kernel enables partitioning the application into separate Active Objects, while preserving the simplicity and portability of the "superloop" architecture. Due to the simplicity and restrictions on preemption (which is only allowed for ISRs), the QV kernel is a recommended choice for safety-critical applications.

Sharing Resources in QV

As described in the Shared-Nothing Principle for Active Objects, QP Applications should generally strive to avoid any sharing of resources among Active Objects. However, the simplistic and non-preemptive nature of the QV kernel allows applications to relax the "shared-nothing" principle and safely share some resources among Active Objects.

Note
As soon as any resource sharing among Active Objects is introduced, the application becomes locked to a non-preemptive kernel and stops being portable to a preemptive kernel. Conversely, an application that heeds the Shared-Nothing Principle remains widely portable to any real-time kernel, including preemptive kernels.

Idle Processing in QV

The situation when QV scheduler finds no events for processing in a given pass through the "superloop" (see Figure 10_01) is called the idle condition. In that case, the QV kernel executes idle processing to let the application, among others, put the CPU and peripherals in a low-power sleep mode. Existence of such a single point to apply low-power modes is a hallmark of a power-friendly architecture.

However, as in the traditional "superloop" (a.k.a., "foreground/background" architecture) QV kernel must detect the idle condition inside a critical section (with interrupts disabled) and must be careful to enter the low-power mode safely without re-enabling interrupts too soon (see [Samek:07]). Otherwise any interrupt allowed after determining the idle condition but before calling the idle processing could post events to Active Objects, thus invalidating the idle condition. However, due to the simplistic, non-preemptive nature of the QV kernel, the idle processing would still be called and would enter the sleep mode while some events might be available and waiting (indefinitely) for processing.

Figure 10_02: QV non-preemptive kernel idle processing
Note
The need to enter the low-power sleep mode with interrupts still disabled (or atomically with re-enabling interrupts) is a unique requirement of a non-preemptive kernel, such as QV. This requirement does not apply to preemptive kernels.

Task-Level Response in QV

The maximum time an event for the highest-priority Active Object can be delayed is called the task-level response. The task-level response in the QV kernel is equal to the longest RTC step of all Active Objects in the system. Note that this task-level response is still a lot better than the traditional "superloop" (a.k.a. main+ISRs) architecture, where the task-level response is typically the sum of the worst-case execution times of all tasks in the "superloop".

Due to the non-blocking nature of event processing inside Active Objects, the RTC steps tend to be short (typically microseconds), which can deliver adequate real-time performance to surprisingly wide range of applications. Also, the task-level response can be often improved by breaking up the longest RTC steps into shorter pieces (multi-stage processing). For example, an Active Object can perform only a fraction of the overall event processing and post event to self to trigger continuation next time ("Reminder" state pattern).

Remarks
Sometimes the task-level response of the simple QV kernel might be too slow and it is impractical to break up all the long RTC steps into shorter pieces. In such cases a preemptive kernel (such as QK, QXK, or a traditional RTOS) can provide a more robust solution. The big advantage of a preemptive kernel is that it effectively decouples high-priority Active Objects from low-priority Active Objects in the time domain. The timeliness of execution of high-priority Active Object is almost independent on the low-priority Active Objects. However, preemptive kernels open the whole new class of problems, collectively known as concurrency hazards.

Requirements

SRS-QP-10_00

SRS-QP-10_00
QP Framework shall provide non-preemptive QV kernel as one of the built-in kernels.
Description
QP Framework shall provide QV kernel implementation and ports to the supported CPU/compiler combinations as one of the optional software components. QP Application can then choose the QV kernel to execute Active Objects. Such a selection is exclusive, meaning that when QP Application selects the QV kernel, other kernels are excluded and cannot be used.
Description
QP Framework can implement the QV kernel component by re-using already existing mechanisms, such as event queues for Active Objects, event delivery mechanisms, event memory management, etc. That way, the QV kernel implementation can be quite small and consist only of the missing pieces, such as the "superloop" with the QV scheduler.

SRS-QP-10_10

SRS-QP-10_10
QV kernel shall provide an idle-callback defined in QP Application.

Description
When no events are available in a given pass through the "superloop" (see Figure 10_01), the QV kernel executes idle processing. This idle processing shall invoke an idle-callback (a function) defined in QP Application. The idle-callback can perform any processing, including putting the CPU and peripherals in a low-power sleep mode.

Note
The idle-processing of the QV kernel can be viewed as the lowest-priority task that can't be preempted by other Active Objects. Consequently the idle-processing time also counts as another RTC step, which must be considered for the task-level response of the QV kernel.
Use Case
The idle-callback can perform Software Tracing data transfer to the host, or other processing.

SRS-QP-10_11

SRS-QP-10_11
The idle-callback shall be invoked with interrupts disabled to allow a safe transition to a low-power sleep mode.
Description
As described in Section Idle Processing in QV, a safe transition to low-power sleep mode requires the QV idle-callback to be invoked with interrupts disabled (inside the same critical section as the detection of the idle condition).

SRS-QP-10_12

SRS-QP-10_12
The idle-callback shall always return with interrupts enabled.
Description
Regardless whether the idle-callback switches to a low-power mode, QP Application must define the idle-callback such that it re-enables interrupts in every path through the code. The QV kernel assumes that this will be the case, and will not work correctly if the idle-callback fails to enable interrupts.

SRS-QP-10_20

SRS-QP-10_20
QV kernel may provide API to selectively disable scheduling Active Objects below the specified scheduler-disable ceiling priority.
Description
The selective scheduler disabling API shall prevent scheduling any Active Object whose unique priority is below the specified scheduler-disable ceiling priority.
Use Case
The main use case for selective scheduler disabling is in time-triggered designs and Active Objects with multi-stage processing. An Active Object that breaks up its long RTC steps into shorter pieces (multi-stage processing) would self-post a special "Reminder" event to trigger subsequent stages of processing. However, to prevent such processing from overrunning the next clock period, the Active Object can explicitly disable the QV scheduler up to its own priority level.

SRS-QP-10_21

SRS-QP-10_21
If QV kernel provides API to disable the scheduler it shall provide the API to enable the scheduler.
Description
The scheduler enabling API shall complement the scheduler disabling API (see SRS-QP-10_20). The scheduler enabling API shall restore the scheduler-disable ceiling established in the most recent call to the scheduler disabling API.
Use Case
The main use case for scheduler enabling (matching the use case in SRS-QP-10_20) is enabling the QV scheduler in the system clock tick.

Software TracingPreemptive Non-Blocking Kernel