QP/C++ 8.1.2
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//............................................................................
56void QV::schedDisable(std::uint8_t const ceiling) noexcept {
59
60 if (ceiling > priv_.schedCeil) { // raising the scheduler ceiling?
61
63 QS_TIME_PRE(); // timestamp
64 // the previous sched ceiling & new sched ceiling
65 QS_2U8_PRE(priv_.schedCeil,
66 static_cast<std::uint8_t>(ceiling));
68
69 priv_.schedCeil = ceiling;
70 }
72}
73
74//............................................................................
75void QV::schedEnable() noexcept {
78
79 if (priv_.schedCeil != 0U) { // actually enabling the scheduler?
80
82 QS_TIME_PRE(); // timestamp
83 // current sched ceiling (old), previous sched ceiling (new)
84 QS_2U8_PRE(priv_.schedCeil, 0U);
86
87 priv_.schedCeil = 0U;
88 }
90}
91
92//----------------------------------------------------------------------------
93namespace QF {
94
95//............................................................................
96void init() {
97#ifdef QV_INIT
98 QV_INIT(); // port-specific initialization of the QV kernel
99#endif
100}
101
102//............................................................................
103void stop() {
104 onCleanup(); // cleanup callback
105 // nothing else to do for the QV kernel
106}
107
108//............................................................................
111#ifdef Q_SPY
112 // produce the QS_QF_RUN trace record
113 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_QF_RUN));
114 QS::endRec_();
115#endif // Q_SPY
116
117#ifdef QV_START
118 QV_START(); // port-specific startup of the QV kernel
119#endif
120
121#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
122 std::uint_fast8_t pprev = 0U; // previous prio.
123
124#ifdef QF_ON_CONTEXT_SW
125 // officially switch to the idle cotext
126 QF_onContextSw(nullptr, nullptr);
127#endif // def QF_ON_CONTEXT_SW
128
129#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
130
132
133 onStartup(); // app. callback: configure and enable interrupts
134
136 for (;;) { // QV event loop...
137 // find the maximum prio. AO ready to run
138 std::uint_fast8_t const p = (QV::priv_.readySet.notEmpty()
139 ? QV::priv_.readySet.findMax()
140 : 0U);
141
142 if (p > QV::priv_.schedCeil) { // is it above the sched ceiling?
143 QActive * const a = QActive_registry_[p];
144
145#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
146 if (p != pprev) { // changing threads?
147
149 QS_TIME_PRE(); // timestamp
150 QS_2U8_PRE(static_cast<std::uint8_t>(p),
151 static_cast<std::uint8_t>(pprev));
152 QS_END_PRE()
153
154#ifdef QF_ON_CONTEXT_SW
155 QF_onContextSw(((pprev != 0U)
156 ? QActive_registry_[pprev]
157 : nullptr), a);
158#endif // QF_ON_CONTEXT_SW
159
160 pprev = p; // update previous prio.
161 }
162#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
163
165
166 QEvt const * const e = a->get_();
167 // NOTE QActive::get_() performs QF_MEM_APP() before return
168
169 // dispatch event (virtual call)
170 a->dispatch(e, p);
171#if (QF_MAX_EPOOL > 0U)
172 gc(e);
173#endif
175
176 if (a->m_eQueue.isEmpty()) { // empty queue?
177 QV::priv_.readySet.remove(p);
178 }
179 }
180 else { // no AO ready to run --> idle
181#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
182 if (pprev != 0U) {
184 QS_TIME_PRE(); // timestamp
185 QS_U8_PRE(static_cast<std::uint8_t>(pprev));
186 QS_END_PRE()
187
188#ifdef QF_ON_CONTEXT_SW
189 QF_onContextSw(QActive_registry_[pprev], nullptr);
190#endif // QF_ON_CONTEXT_SW
191
192 pprev = 0U; // update previous prio.
193 }
194#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
195
196 // QV::onIdle() must be called with interrupts DISABLED because
197 // the determination of the idle condition can change at any time
198 // by an interrupt posting events to a queue.
199 //
200 // NOTE: QV::onIdle() MUST enable interrupts internally, ideally
201 // atomically with putting the CPU into a power-saving mode.
202 QV::onIdle();
203
204 QF_INT_DISABLE(); // disable interrupts before looping back
205 }
206 }
207}
208
209} // namespace QF
210
211//----------------------------------------------------------------------------
213 QPrioSpec const prioSpec,
214 QEvtPtr * const qSto,
215 std::uint_fast16_t const qLen,
216 void * const stkSto,
217 std::uint_fast16_t const stkSize,
218 void const * const par)
219{
220 Q_UNUSED_PAR(stkSto); // not needed in QV
221 Q_UNUSED_PAR(stkSize); // not needed in QV
222
225
226 // stack storage must NOT be provided for the AO (QV does not need it)
227 Q_REQUIRE_INCRIT(310, stkSto == nullptr);
228 QF_CRIT_EXIT();
229
230 m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio.
231 m_pthre = 0U; // not used
232 register_(); // make QF aware of this AO
233
234 m_eQueue.init(qSto, qLen);
235
236 // top-most initial tran. (virtual call)
237 this->init(par, m_prio);
238 QS_FLUSH(); // flush the trace buffer to the host
239}
240
241} // namespace QP
Active object class (based on the QP::QHsm implementation strategy).
Definition qp.hpp:492
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:506
QEvt const * get_() noexcept
Get an event from the event queue of an active object.
Definition qf_actq.cpp:197
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:212
std::uint8_t m_pthre
Preemption-threshold [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:495
std::uint8_t m_prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:494
Event class.
Definition qp.hpp:101
QV non-preemptive kernel.
Definition qv.hpp:36
static QV priv_
Definition qv.hpp:46
static void schedDisable(std::uint8_t const ceiling) noexcept
Definition qv.cpp:56
static void schedEnable() noexcept
Definition qv.cpp:75
static void onIdle()
QF Active Object Framework namespace.
Definition qp.hpp:480
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:96
int_t run()
Transfers control to QF to run the application.
Definition qv.cpp:109
void stop()
Invoked by the application layer to stop the QF framework and return control to the OS/Kernel (used i...
Definition qv.cpp:103
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
QEvt const * QEvtPtr
Pointer to const event instances passed around in QP/C++ Framework.
Definition qp.hpp:129
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:421
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