QP/C++  8.0.3
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 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
50namespace QP {
51namespace QV {
52
54
55//............................................................................
56void schedDisable(std::uint_fast8_t const ceiling) {
59
60 if (ceiling > priv_.schedCeil) { // raising the scheduler ceiling?
61
62 QS_BEGIN_PRE(QS_SCHED_LOCK, 0U)
63 QS_TIME_PRE(); // timestamp
64 // the previous sched ceiling & new sched ceiling
65 QS_2U8_PRE(static_cast<std::uint8_t>(priv_.schedCeil),
66 static_cast<std::uint8_t>(ceiling));
68
69 priv_.schedCeil = ceiling;
70 }
72}
73
74//............................................................................
78
79 if (priv_.schedCeil != 0U) { // actually enabling the scheduler?
80
81 QS_BEGIN_PRE(QS_SCHED_UNLOCK, 0U)
82 QS_TIME_PRE(); // timestamp
83 // current sched ceiling (old), previous sched ceiling (new)
84 QS_2U8_PRE(static_cast<std::uint8_t>(priv_.schedCeil), 0U);
86
87 priv_.schedCeil = 0U;
88 }
90}
91
92} // namespace QV
93
94namespace QF {
95
96//............................................................................
97void init() {
98 bzero_(&QF::priv_, sizeof(QF::priv_));
99 bzero_(&QV::priv_, sizeof(QV::priv_));
101
102#ifdef QV_INIT
103 QV_INIT(); // port-specific initialization of the QV kernel
104#endif
105}
106
107//............................................................................
108void stop() {
109 onCleanup(); // cleanup callback
110 // nothing else to do for the QV kernel
111}
112
113//${QV::QF-cust::run} ........................................................
116#ifdef Q_SPY
117 // produce the QS_QF_RUN trace record
118 QS::beginRec_(QS_REC_NUM_(QS_QF_RUN));
119 QS::endRec_();
120#endif // Q_SPY
121
122#ifdef QV_START
123 QV_START(); // port-specific startup of the QV kernel
124#endif
125
126#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
127 std::uint_fast8_t pprev = 0U; // previous prio.
128
129#ifdef QF_ON_CONTEXT_SW
130 // officially switch to the idle cotext
131 QF_onContextSw(nullptr, nullptr);
132#endif // def QF_ON_CONTEXT_SW
133
134#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
135
137
138 onStartup(); // app. callback: configure and enable interrupts
139
141 for (;;) { // QV event loop...
142 // find the maximum prio. AO ready to run
143 std::uint_fast8_t const p = (QV::priv_.readySet.notEmpty()
144 ? QV::priv_.readySet.findMax()
145 : 0U);
146
147 if (p > QV::priv_.schedCeil) { // is it above the sched ceiling?
148 QActive * const a = QActive::registry_[p];
149
150#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
151 QS_BEGIN_PRE(QS_SCHED_NEXT, p)
152 QS_TIME_PRE(); // timestamp
153 QS_2U8_PRE(static_cast<std::uint8_t>(p),
154 static_cast<std::uint8_t>(pprev));
155 QS_END_PRE()
156
157#ifdef QF_ON_CONTEXT_SW
158 QF_onContextSw(((pprev != 0U)
159 ? QActive::registry_[pprev]
160 : nullptr), a);
161#endif // QF_ON_CONTEXT_SW
162
163 pprev = p; // update previous prio.
164#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
165
167
168 QEvt const * const e = a->get_();
169
170 // dispatch event (virtual call)
171 a->dispatch(e, a->getPrio());
172#if (QF_MAX_EPOOL > 0U)
173 gc(e);
174#endif
176
177 if (a->getEQueue().isEmpty()) { // empty queue?
178 QV::priv_.readySet.remove(p);
179 }
180 }
181 else { // no AO ready to run --> idle
182#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
183 if (pprev != 0U) {
184 QS_BEGIN_PRE(QS_SCHED_IDLE, pprev)
185 QS_TIME_PRE(); // timestamp
186 QS_U8_PRE(static_cast<std::uint8_t>(pprev));
187 QS_END_PRE()
188
189#ifdef QF_ON_CONTEXT_SW
190 QF_onContextSw(QActive::registry_[pprev], nullptr);
191#endif // QF_ON_CONTEXT_SW
192
193 pprev = 0U; // update previous prio
194 }
195#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
196
197 // QV::onIdle() must be called with interrupts DISABLED because
198 // the determination of the idle condition can change at any time
199 // by an interrupt posting events to a queue.
200 //
201 // NOTE: QV::onIdle() MUST enable interrupts internally, ideally
202 // atomically with putting the CPU into a power-saving mode.
203 QV::onIdle();
204
206 }
207 }
208#ifdef __GNUC__ // GNU compiler?
209 return 0;
210#endif
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
230 stkSto == nullptr);
231 QF_CRIT_EXIT();
232
233 m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio.
234 m_pthre = 0U; // not used
235 register_(); // make QF aware of this AO
236
237 m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO
238
239 this->init(par, m_prio); // take the top-most initial tran. (virtual)
240 QS_FLUSH(); // flush the trace buffer to the host
241}
242
243} // namespace QP
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:563
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)
Definition qv.cpp:216
void init(void const *const e, std::uint_fast8_t const qsId) override
Virtual function to take the top-most initial transition in the state machine.
Definition qp.hpp:607
static QActive * registry_[QF_MAX_ACTIVE+1U]
Definition qp.hpp:581
void register_() noexcept
Definition qf_qact.cpp:48
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Virtual function to dispatch an event to the state machine.
Definition qp.hpp:616
QACTIVE_EQUEUE_TYPE m_eQueue
Definition qp.hpp:577
QEvt const * get_() noexcept
Definition qf_actq.cpp:208
std::uint8_t m_pthre
Definition qp.hpp:566
std::uint_fast8_t getPrio() const noexcept
Definition qp.hpp:677
QACTIVE_EQUEUE_TYPE const & getEQueue() const noexcept
Definition qp.hpp:689
std::uint8_t m_prio
Definition qp.hpp:565
Event class.
Definition qp.hpp:115
Private attributes of the QV kernel.
Definition qv.hpp:36
QF Active Object Framework namespace.
void onCleanup()
void gc(QEvt const *const e) noexcept
Recycle a mutable (mutable) event.
Definition qf_dyn.cpp:188
void bzero_(void *const start, std::uint_fast16_t const len) noexcept
Definition qf_act.cpp:56
QF::Attr priv_
Definition qf_act.cpp:54
void init()
Definition qv.cpp:97
int_t run()
Definition qv.cpp:114
void stop()
Definition qv.cpp:108
void onStartup()
non-preemptive kernel
Definition qv.hpp:33
QV::Attr priv_
Definition qv.cpp:53
void schedEnable()
Definition qv.cpp:75
void onIdle()
void schedDisable(std::uint_fast8_t const ceiling)
Definition qv.cpp:56
QP/C++ framework.
Definition qequeue.hpp:36
QEvt const * QEvtPtr
Pointer to const event instances passed around in QP Framework.
Definition qp.hpp:141
std::uint16_t QPrioSpec
Priority specification for Active Objects in QP.
Definition qp.hpp:456
int int_t
Alias for assertion-ID numbers in QP assertions and return from QP::QF::run()
Definition qp.hpp:91
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:94
void QF_onContextSw(QP::QActive *prev, QP::QActive *next)
Internal (package scope) QP/C++ interface.
Sample QP/C++ port.
#define QF_INT_DISABLE()
Disable interrupts.
Definition qp_port.hpp:36
#define QF_INT_ENABLE()
Enable interrupts.
Definition qp_port.hpp:39
QS/C++ dummy public interface.
#define QS_TIME_PRE()
Definition qs_dummy.hpp:154
#define QS_2U8_PRE(data1_, data2_)
Definition qs_dummy.hpp:151
#define QS_FLUSH()
Definition qs_dummy.hpp:75
#define QS_U8_PRE(data_)
Definition qs_dummy.hpp:150
#define QS_END_PRE()
Definition qs_dummy.hpp:149
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.hpp:148
Sample QS/C++ port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:39
#define QF_CRIT_EXIT()
Definition qsafe.h:43
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section)
Definition qsafe.h:86
#define QF_CRIT_STAT
Definition qsafe.h:35