The Active Object model of computation can work with a wide range of real-time kernels. Among others, event-driven Active Objects can be executed by a traditional, blocking RTOS kernel, where each Active Object runs in its own RTOS thread structured as an event-loop. However, using a traditional, blocking RTOS to execute non-blocking Active Objects is wasteful. As demonstrated in the QK Preemptive Non-Blocking Kernel, non-blocking Active Objects can be executed more efficiently as one-shot, run-to-completion steps.
QXK is a preemptive, fixed-priority, dual-mode (blocking / non-blocking) kernel that executes Active Objects like the QK kernel (basic tasks), but can also execute traditional blocking threads (extended tasks). In this respect, QXK behaves like a traditional RTOS.
QXK has been designed specifically for combining event-driven Active Objects with traditional code that requires blocking, such as commercial middleware (TCP/IP stacks, UDP stacks, embedded file systems, etc.) or legacy software. To this end, QXK is not only more efficient than running QP/C++ on top of a traditional 3rd-party RTOS (because non-blocking basic tasks take less stack space and CPU cycles for context switch than the much heavier extended tasks). But the biggest advantage of QXK is that it protects the application-level code from inadvertent mixing of blocking calls inside the event-driven Active Objects. Specifically, QXK "knows" the type of the task context (extended/basic) and asserts internally if a blocking call (e.g., semaphore-wait or a time-delay) is attempted in a basic task (Active Object).
Basic tasks are one-shot, non-blocking, run-to-completion activations. The basic-task can nest on the same stack. Also, context switching from a basic-task to another basic-task requires only activation of the basic-task, which is simpler and faster than full context-switch required for extended-tasks (that QXK also supports, see below).
Extended tasks are endless loops allowed to block. Extended tasks require private per-task stacks, as in conventional RTOS kernels. Any switching from basic-to-extended task or extended-to-extended task requires full context switch.
QXK provides most blocking mechanisms found in traditional blocking RTOS kernels:
As all preemptive kernels, QXK requires the QP/C++ Application to be very careful with any resource sharing among Active Objects. Ideally, the Active Objects should communicate exclusively via events and otherwise should not share any resources. However, at the cost of increased coupling among Active Objects, QP/C++ Application might choose to share selected resources. However, such QP/C++ Application takes the burden on itself to apply a mutual exclusion mechanism while accessing any shared resources.
QXK kernel provides selective scheduler locking as a powerful mutual exclusion mechanism. Specifically, before accessing a shared resource, an Active Objects can lock the QXK scheduler up to the specified priority ceiling. This prevents Active Object preemption up to the specified priority ceiling, while not affecting Active Objects (or interrupts) of priority higher than the priority ceiling. After accessing the shared resource the Active Object must unlock the QXK scheduler.
Selective scheduling locking is a non-blocking mechanism. If an Active Object that needs to protect a shared resource is running, it means that all Active Objects of higher priority have no events to process. Consequently, simply preventing activation of higher-priority AOs that might access the resource is sufficient to guarantee the mutually exclusive access to the resource. Of course, you don't need to worry about any lower-priority AOs that might be preempted because they never resume until the current AO runs to completion.
Selective scheduler lock requests made by the same Active Object can nest. The nested lock requests can only increase the priority ceiling. Also, the nested lock requests must unlock the scheduler by restoring the previous priority ceiling.
As a fully preemptive, fixed-priority kernel, QXK always executes the highest-priority task that is ready to run (is not blocked). The scheduling algorithm used in QXK meets all the requirement of the Rate Monotonic Scheduling (a.k.a. Rate Monotonic Analysis — RMA) and can be used in hard real-time systems.
SRS_QP_QXK_00 : QP/C++ Framework shall provide preemptive non-blocking QXK kernel as one of the built-in kernels. |
---|
Description QP/C++ Framework shall provide QXK kernel implementation and ports to the supported CPU/compiler combinations as one of the optional software components. QP/C++ Application can then choose the QXK kernel to execute Active Objects and extended tasks. Such a selection is exclusive, meaning that when QP/C++ Application selects the QXK kernel, other kernels are excluded and cannot be used. |
Description QP/C++ Framework can implement the QXK kernel component by re-using already existing mechanisms, such as event queues for Active Objects, event delivery mechanisms, event memory management, etc. |
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_10 : QXK kernel shall support basic tasks for execution of Active Objects and shall handle them like the QK kernel. |
---|
Description QXK kernel shall provide API for designating an Active Object, which will require a unique priority and event queue, but not a private stack. Subsequently, QXK kernel shall execute thus designated Active Object as a basic-task by dispatching events to its state machine. |
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_11 : QXK kernel shall support extended tasks for execution of blocking threads and shall execute them like a conventional RTOS kernel. |
---|
Description QXK kernel shall provide API for designating an extended task (distinct from designating an Active Object), which will require a unique priority, optional event queue, and a private stack. Subsequently, QXK kernel shall execute thus designated object as an extended task. If an extended task is configured with an event queue, such an extened task can block on that queue and receive events through that queue. |
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_12 : QXK kernel shall support mixing basic and extended tasks. |
---|
Description QXK shall allow combining basic tasks (Active Objects) and extended tasks (threads) in a single application. QXK shall allow interleaving the unique priorities of basic tasks and extended tasks and prioritize them according to the same uniform prioritization scheme described in SRS_QP_AO_10. |
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_13 : QXK kernel shall support interactions between basic and extended tasks. |
---|
Description QXK shall support the following integrated mechanisms for communication between extended and basic tasks:
|
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_20 : QXK kernel shall support counting semaphores with optional timeout. |
---|
Description QXK shall support counting semaphores as on of the standard blocking mechanisms. As a special case, counting semaphore with maximum 1 shall behave as a binary semaphore. The blocking semaphore-wait operation (with optional timeout) shall be allowed only inside the extended threads. However, signaling a semaphore is allowed both from Active Objects and ISRs. |
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_21 : QXK kernel shall support blocking event queues with optional timeout. |
---|
Description For extended tasks configured with an event queue, QXK shall support blocking on that event queue (with optional timeout) inside the endless loop of the extended task. |
Forward Traceability (truncated to 2 level(s)) |
SRS_QP_QXK_22 : QXK kernel shall support blocking recursive mutexes with optional timeout. |
---|
Description QXK shall support mutexes as on of the standard mutual exclusion mechanisms. The blocking mutex-lock operation (with optional timeout) shall be allowed only inside the extended threads. The mutex shall support the priority-ceiling protocol to prevent unbounded priority inversion. The mutex shall also allow recursive locking (by the same extended task). |
Forward Traceability (truncated to 2 level(s)) |