QP/C++ 8.1.4
Real-Time Event Framework
Loading...
Searching...
No Matches
qv.cpp
Go to the documentation of this file.
1//============================================================================
2// QP/C++ Real-Time Event Framework (RTEF)
3//
4// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
5//
6// Q u a n t u m L e a P s
7// ------------------------
8// Modern Embedded Software
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
11//
12// This software is dual-licensed under the terms of the open-source GNU
13// General Public License (GPL) or under the terms of one of the closed-
14// source Quantum Leaps commercial licenses.
15//
16// Redistributions in source code must retain this top-level comment block.
17// Plagiarizing this software to sidestep the license obligations is illegal.
18//
19// NOTE:
20// The GPL does NOT permit the incorporation of this code into proprietary
21// programs. Please contact Quantum Leaps for commercial licensing options,
22// which expressly supersede the GPL and are designed explicitly for
23// closed-source distribution.
24//
25// Quantum Leaps contact information:
26// <www.state-machine.com/licensing>
27// <info@state-machine.com>
28//============================================================================
29#define QP_IMPL // this is QP implementation
30#include "qp_port.hpp" // QP port
31#include "qp_pkg.hpp" // QP package-scope internal interface
32#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
33#ifdef Q_SPY // QS software tracing enabled?
34 #include "qs_port.hpp" // QS port
35 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
36#else
37 #include "qs_dummy.hpp" // disable the QS software tracing
38#endif // Q_SPY
39
40// protection against including this source file in a wrong project
41#ifndef QV_HPP_
42 #error Source file included in a project NOT based on the QV kernel
43#endif // QV_HPP_
44
45// unnamed namespace for local definitions with internal linkage
46namespace {
47Q_DEFINE_THIS_MODULE("qv")
48} // unnamed namespace
49
50//============================================================================
51namespace QP {
52
54
55//............................................................................
56QV::QV() noexcept
57 : readySet(),
58 schedCeil(0U)
59{}
60
61//............................................................................
62void QV::schedDisable(std::uint8_t const ceiling) noexcept {
65
66 if (ceiling > priv_.schedCeil) { // raising the scheduler ceiling?
67
69 QS_TIME_PRE(); // timestamp
70 // the previous sched ceiling & new sched ceiling
71 QS_2U8_PRE(priv_.schedCeil,
72 static_cast<std::uint8_t>(ceiling));
74
75 priv_.schedCeil = ceiling;
76 }
78}
79
80//............................................................................
81void QV::schedEnable() noexcept {
84
85 if (priv_.schedCeil != 0U) { // actually enabling the scheduler?
86
88 QS_TIME_PRE(); // timestamp
89 // current sched ceiling (old), previous sched ceiling (new)
90 QS_2U8_PRE(priv_.schedCeil, 0U);
92
93 priv_.schedCeil = 0U;
94 }
96}
97
98//----------------------------------------------------------------------------
99namespace QF {
100
101//............................................................................
102void init() {
103#ifdef QV_INIT
104 QV_INIT(); // port-specific initialization of the QV kernel
105#endif
106}
107
108//............................................................................
109void stop() {
110 onCleanup(); // cleanup callback
111 // nothing else to do for the QV kernel
112}
113
114//............................................................................
117#ifdef Q_SPY
118 // produce the QS_QF_RUN trace record
119 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_QF_RUN));
120 QS::endRec_();
121#endif // Q_SPY
122
123#ifdef QV_START
124 QV_START(); // port-specific startup of the QV kernel
125#endif
126
127#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
128 std::uint_fast8_t pprev = 0U; // previous prio.
129
130#ifdef QF_ON_CONTEXT_SW
131 // officially switch to the idle cotext
132 QF_onContextSw(nullptr, nullptr);
133#endif // def QF_ON_CONTEXT_SW
134
135#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
136
138
139 onStartup(); // app. callback: configure and enable interrupts
140
142 for (;;) { // QV event loop...
143 // find the maximum prio. AO ready to run
144 std::uint_fast8_t const p = (QV::priv_.readySet.notEmpty()
145 ? QV::priv_.readySet.findMax()
146 : 0U);
147
148 if (p > QV::priv_.schedCeil) { // is it above the sched ceiling?
149 QActive * const a = QActive_registry_[p];
150
151#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
152 if (p != pprev) { // changing threads?
153
155 QS_TIME_PRE(); // timestamp
156 QS_2U8_PRE(static_cast<std::uint8_t>(p),
157 static_cast<std::uint8_t>(pprev));
158 QS_END_PRE()
159
160#ifdef QF_ON_CONTEXT_SW
161 QF_onContextSw(((pprev != 0U)
162 ? QActive_registry_[pprev]
163 : nullptr), a);
164#endif // QF_ON_CONTEXT_SW
165
166 pprev = p; // update previous prio.
167 }
168#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
169
171
172 QEvt const * const e = a->get_(); // queue not empty
173
174 a->dispatch(e, p); // dispatch event (virtual call)
175#if (QF_MAX_EPOOL > 0U)
176 QF::gc(e); // check if the event is garbage, and collect it if so
177#endif
179
180 if (a->m_eQueue.isEmpty()) { // empty queue?
181 QV::priv_.readySet.remove(p);
182 }
183 }
184 else { // no AO ready to run --> idle
185#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
186 if (pprev != 0U) {
188 QS_TIME_PRE(); // timestamp
189 QS_U8_PRE(static_cast<std::uint8_t>(pprev));
190 QS_END_PRE()
191
192#ifdef QF_ON_CONTEXT_SW
193 QF_onContextSw(QActive_registry_[pprev], nullptr);
194#endif // QF_ON_CONTEXT_SW
195
196 pprev = 0U; // update previous prio.
197 }
198#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
199
200 // QV::onIdle() must be called with interrupts DISABLED because
201 // the determination of the idle condition can change at any time
202 // by an interrupt posting events to a queue.
203 //
204 // NOTE: QV::onIdle() MUST enable interrupts internally, ideally
205 // atomically with putting the CPU into a power-saving mode.
206 QV::onIdle();
207
208 QF_INT_DISABLE(); // disable interrupts before looping back
209 }
210 }
211}
212
213} // namespace QF
214
215//----------------------------------------------------------------------------
217 QPrioSpec const prioSpec,
218 QEvtPtr * const qSto,
219 std::uint_fast16_t const qLen,
220 void * const stkSto,
221 std::uint_fast16_t const stkSize,
222 void const * const par)
223{
224 Q_UNUSED_PAR(stkSto); // not needed in QV
225 Q_UNUSED_PAR(stkSize); // not needed in QV
226
229
230 // stack storage must NOT be provided for the AO (QV does not need it)
231 Q_REQUIRE_INCRIT(310, stkSto == nullptr);
232 QF_CRIT_EXIT();
233
234 m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio.
235 m_pthre = 0U; // not used
236 register_(); // make QF aware of this AO
237
238 m_eQueue.init(qSto, qLen);
239
240 // top-most initial tran. (virtual call)
241 this->init(par, m_prio);
242 QS_FLUSH(); // flush the trace buffer to the host
243}
244
245} // namespace QP
Active object class (based on the QP::QHsm implementation strategy).
Definition qp.hpp:501
void register_() noexcept
Register this active object to be managed by the framework.
Definition qf_qact.cpp:68
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Virtual function to dispatch an event to the state machine.
Definition qf_qact.cpp:142
friend void QF::init()
QACTIVE_EQUEUE_TYPE m_eQueue
Port-dependent event-queue type (often QP::QEQueue).
Definition qp.hpp:515
QEvt const * get_() noexcept
Get an event from the event queue of an active object.
Definition qf_actq.cpp:191
void start(QPrioSpec const prioSpec, QEvtPtr *const qSto, std::uint_fast16_t const qLen, void *const stkSto, std::uint_fast16_t const stkSize, void const *const par=nullptr)
Starts execution of an active object and registers the object with the framework.
Definition qv.cpp:216
std::uint8_t m_pthre
Preemption-threshold [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:504
std::uint8_t m_prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:503
Event class.
Definition qp.hpp:101
QV non-preemptive kernel.
Definition qv.hpp:36
std::uint8_t schedCeil
Definition qv.hpp:39
static QV priv_
Definition qv.hpp:47
QV() noexcept
Definition qv.cpp:56
QPSet readySet
Set of active-objects/threads that are ready to run in the QV kernel.
Definition qv.hpp:38
static void schedDisable(std::uint8_t const ceiling) noexcept
Definition qv.cpp:62
static void schedEnable() noexcept
Definition qv.cpp:81
static void onIdle()
QF Active Object Framework namespace.
Definition qp.hpp:489
void onCleanup()
Cleanup QF callback.
void gc(QEvt const *const e) noexcept
Recycle a mutable (mutable) event.
Definition qf_dyn.cpp:276
void init()
QF initialization.
Definition qv.cpp:102
int_t run()
Transfers control to QF to run the application.
Definition qv.cpp:115
void stop()
Invoked by the application layer to stop the QF framework and return control to the OS/Kernel (used i...
Definition qv.cpp:109
void onStartup()
Startup QF callback.
QP/C++ Framework namespace.
Definition qequeue.hpp:36
@ QS_SCHED_LOCK
scheduler was locked
Definition qs.hpp:128
@ QS_QF_RUN
QF_run() was entered.
Definition qs.hpp:154
@ QS_SCHED_NEXT
scheduler started next task
Definition qs.hpp:130
@ QS_SCHED_UNLOCK
scheduler was unlocked
Definition qs.hpp:129
@ QS_SCHED_IDLE
scheduler restored the idle task
Definition qs.hpp:131
std::array< QActive *, QF_MAX_ACTIVE+1U > QActive_registry_
Internal array of pointers to the registered Active Objects.
Definition qf_qact.cpp:47
std::uint16_t QPrioSpec
Priority specification for Active Objects in QP.
Definition qp.hpp:423
int int_t
Alias for assertion-ID numbers in QP assertions and return from QP::QF::run().
Definition qp.hpp:87
#define Q_UNUSED_PAR(par_)
Helper macro to mark unused parameters of functions.
Definition qp.hpp:89
void QF_onContextSw(QP::QActive *prev, QP::QActive *next)
QP/C++ Framework in C++ internal (package-scope) interface.
Sample QP/C++ port.
#define QF_INT_DISABLE()
Port-specific interrupt disable.
Definition qp_port.hpp:57
#define QF_INT_ENABLE()
Port-specific interrupt enable.
Definition qp_port.hpp:65
#define QS_TIME_PRE()
Definition qs.hpp:362
#define QS_FLUSH()
Definition qs.hpp:273
QS (QP/Spy software tracing) internal (package-scope) interface.
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.hpp:83
#define QS_U8_PRE(data_)
Output pre-formatted unsigned 8-bit integer data element.
Definition qs_pkg.hpp:81
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.hpp:79
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.hpp:73
Sample QS/C++ port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:40
#define QF_CRIT_EXIT()
Definition qsafe.h:44
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section).
Definition qsafe.h:98
#define QF_CRIT_STAT
Definition qsafe.h:36