QP/C++  7.3.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qk.cpp
Go to the documentation of this file.
1//$file${src::qk::qk.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qk::qk.cpp}
5//
6// This code has been generated by QM 6.1.1 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// This code is covered by the following QP license:
10// License # : LicenseRef-QL-dual
11// Issued to : Any user of the QP/C++ real-time embedded framework
12// Framework(s) : qpcpp
13// Support ends : 2024-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// Q u a n t u m L e a P s
19// ------------------------
20// Modern Embedded Software
21//
22// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
23//
24// This software is dual-licensed under the terms of the open source GNU
25// General Public License version 3 (or any later version), or alternatively,
26// under the terms of one of the closed source Quantum Leaps commercial
27// licenses.
28//
29// The terms of the open source GNU General Public License version 3
30// can be found at: <www.gnu.org/licenses/gpl-3.0>
31//
32// The terms of the closed source Quantum Leaps commercial licenses
33// can be found at: <www.state-machine.com/licensing>
34//
35// Redistributions in source code must retain this top-level comment block.
36// Plagiarizing this software to sidestep the license obligations is illegal.
37//
38// Contact information:
39// <www.state-machine.com/licensing>
40// <info@state-machine.com>
41//
42//$endhead${src::qk::qk.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.hpp" // QP port
45#include "qp_pkg.hpp" // QP package-scope interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.hpp" // QS port
49 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.hpp" // disable the QS software tracing
52#endif // Q_SPY
53
54// protection against including this source file in a wrong project
55#ifndef QK_HPP_
56 #error "Source file included in a project NOT based on the QK kernel"
57#endif // QK_HPP_
58
59// unnamed namespace for local definitions with internal linkage
60namespace {
61Q_DEFINE_THIS_MODULE("qk")
62} // unnamed namespace
63
64//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
65// Check for the minimum required QP version
66#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
67#error qpcpp version 7.3.0 or higher required
68#endif
69//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70
71//$define${QK::QK-base} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
72namespace QP {
73namespace QK {
74
75//${QK::QK-base::schedLock} ..................................................
76QSchedStatus schedLock(std::uint_fast8_t const ceiling) noexcept {
79 QF_MEM_SYS();
80
83 == static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil_dis));
84
85 // first store the previous lock prio
86 QSchedStatus stat;
87 if (ceiling > QK_priv_.lockCeil) { // raising the lock ceiling?
88 QS_BEGIN_PRE_(QS_SCHED_LOCK, QK_priv_.actPrio)
89 QS_TIME_PRE_(); // timestamp
90 // the previous lock ceiling & new lock ceiling
91 QS_2U8_PRE_(static_cast<std::uint8_t>(QK_priv_.lockCeil),
92 static_cast<std::uint8_t>(ceiling));
93 QS_END_PRE_()
94
95 // previous status of the lock
96 stat = static_cast<QSchedStatus>(QK_priv_.lockCeil);
97
98 // new status of the lock
99 QK_priv_.lockCeil = ceiling;
100 #ifndef Q_UNSAFE
101 QK_priv_.lockCeil_dis = static_cast<std::uint_fast8_t>(~ceiling);
102 #endif
103 }
104 else {
105 stat = 0xFFU; // scheduler not locked
106 }
107
108 QF_MEM_APP();
109 QF_CRIT_EXIT();
110
111 return stat; // return the status to be saved in a stack variable
112}
113
114//${QK::QK-base::schedUnlock} ................................................
115void schedUnlock(QSchedStatus const prevCeil) noexcept {
116 // has the scheduler been actually locked by the last QK::schedLock()?
117 if (prevCeil != 0xFFU) {
120 QF_MEM_SYS();
121
123 == static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil_dis));
125 && (QK_priv_.lockCeil > prevCeil));
126
127 QS_BEGIN_PRE_(QS_SCHED_UNLOCK, QK_priv_.actPrio)
128 QS_TIME_PRE_(); // timestamp
129 // current lock ceiling (old), previous lock ceiling (new)
130 QS_2U8_PRE_(static_cast<std::uint8_t>(QK_priv_.lockCeil),
131 static_cast<std::uint8_t>(prevCeil));
132 QS_END_PRE_()
133
134 // restore the previous lock ceiling
135 QK_priv_.lockCeil = prevCeil;
136 #ifndef Q_UNSAFE
137 QK_priv_.lockCeil_dis = static_cast<std::uint_fast8_t>(~prevCeil);
138 #endif
139
140 // find if any AOs should be run after unlocking the scheduler
141 if (QK_sched_() != 0U) { // preemption needed?
142 QK_activate_(); // activate any unlocked AOs
143 }
144
145 QF_MEM_APP();
146 QF_CRIT_EXIT();
147 }
148}
149
150} // namespace QK
151} // namespace QP
152//$enddef${QK::QK-base} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
153
154extern "C" {
155//$define${QK-extern-C} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
156
157//${QK-extern-C::QK_priv_} ...................................................
159
160//${QK-extern-C::QK_sched_} ..................................................
161std::uint_fast8_t QK_sched_() noexcept {
162 // NOTE: this function is entered with interrupts DISABLED
163
166
167 std::uint_fast8_t p;
168 if (QK_priv_.readySet.isEmpty()) {
169 p = 0U; // no activation needed
170 }
171 else {
172 // find the highest-prio AO with non-empty event queue
174
176 == static_cast<std::uint_fast8_t>(~QK_priv_.actThre_dis));
177
178 // is the AO's prio. below the active preemption-threshold?
179 if (p <= QK_priv_.actThre) {
180 p = 0U; // no activation needed
181 }
182 else {
184 == static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil_dis));
185
186 // is the AO's prio. below the lock-ceiling?
187 if (p <= QK_priv_.lockCeil) {
188 p = 0U; // no activation needed
189 }
190 else {
192 == static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio_dis));
193 QK_priv_.nextPrio = p; // next AO to run
194 #ifndef Q_UNSAFE
196 = static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio);
197 #endif
198 }
199 }
200 }
201
202 return p;
203}
204
205//${QK-extern-C::QK_activate_} ...............................................
206void QK_activate_() noexcept {
207 // NOTE: this function is entered with interrupts DISABLED
208
209 std::uint_fast8_t const prio_in = QK_priv_.actPrio; // save initial prio.
210 std::uint_fast8_t p = QK_priv_.nextPrio; // next prio to run
211
213 (prio_in == static_cast<std::uint_fast8_t>(~QK_priv_.actPrio_dis))
214 && (p == static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio_dis)));
215 Q_REQUIRE_INCRIT(510, (prio_in <= QF_MAX_ACTIVE)
216 && (0U < p) && (p <= QF_MAX_ACTIVE));
217
218 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
219 std::uint_fast8_t pprev = prio_in;
220 #endif // QF_ON_CONTEXT_SW || Q_SPY
221
222 QK_priv_.nextPrio = 0U; // clear for the next time
223 #ifndef Q_UNSAFE
224 QK_priv_.nextPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio);
225 #endif
226
227 std::uint_fast8_t pthre_in;
228 QP::QActive *a;
229 if (prio_in == 0U) { // preempting the idle thread?
230 pthre_in = 0U;
231 }
232 else {
233 a = QP::QActive::registry_[prio_in];
234 Q_ASSERT_INCRIT(510, a != nullptr);
235
236 pthre_in = static_cast<std::uint_fast8_t>(a->getPThre());
237 Q_ASSERT_INCRIT(511, pthre_in == static_cast<std::uint_fast8_t>(
238 ~static_cast<std::uint_fast8_t>(a->m_pthre_dis) & 0xFFU));
239 }
240
241 // loop until no more ready-to-run AOs of higher pthre than the initial
242 do {
243 a = QP::QActive::registry_[p]; // obtain the pointer to the AO
244 Q_ASSERT_INCRIT(520, a != nullptr); // the AO must be registered
245 std::uint_fast8_t const pthre
246 = static_cast<std::uint_fast8_t>(a->getPThre());
247 Q_ASSERT_INCRIT(522, pthre == static_cast<std::uint_fast8_t>(
248 ~static_cast<std::uint_fast8_t>(a->m_pthre_dis) & 0xFFU));
249
250 // set new active prio. and preemption-threshold
251 QK_priv_.actPrio = p;
252 QK_priv_.actThre = pthre;
253 #ifndef Q_UNSAFE
254 QK_priv_.actPrio_dis = static_cast<std::uint_fast8_t>(~p);
255 QK_priv_.actThre_dis = static_cast<std::uint_fast8_t>(~pthre);
256 #endif
257
258 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
259 if (p != pprev) { // changing threads?
260
261 QS_BEGIN_PRE_(QP::QS_SCHED_NEXT, p)
262 QS_TIME_PRE_(); // timestamp
263 QS_2U8_PRE_(p, // prio. of the scheduled AO
264 pprev); // previous prio.
265 QS_END_PRE_()
266
267 #ifdef QF_ON_CONTEXT_SW
269 #endif // QF_ON_CONTEXT_SW
270
271 pprev = p; // update previous prio.
272 }
273 #endif // QF_ON_CONTEXT_SW || Q_SPY
274
275 QF_INT_ENABLE(); // unconditionally enable interrupts
276
277 QP::QEvt const * const e = a->get_();
278 // NOTE QActive_get_() performs QF_MEM_APP() before return
279
280 // dispatch event (virtual call)
281 a->dispatch(e, a->getPrio());
282 #if (QF_MAX_EPOOL > 0U)
283 QP::QF::gc(e);
284 #endif
285
286 // determine the next highest-prio. AO ready to run...
287 QF_INT_DISABLE(); // unconditionally disable interrupts
288 QF_MEM_SYS();
289
290 // internal integrity check (duplicate inverse storage)
291 Q_ASSERT_INCRIT(532,
293
294 if (a->getEQueue().isEmpty()) { // empty queue?
296 #ifndef Q_UNSAFE
298 #endif
299 }
300
301 if (QK_priv_.readySet.isEmpty()) {
302 p = 0U; // no activation needed
303 }
304 else {
305 // find new highest-prio AO ready to run...
307
308 // is the new prio. below the initial preemption-threshold?
309 if (p <= pthre_in) {
310 p = 0U; // no activation needed
311 }
312 else {
313 Q_ASSERT_INCRIT(542,
315
316 // is the AO's prio. below the lock preemption-threshold?
317 if (p <= QK_priv_.lockCeil) {
318 p = 0U; // no activation needed
319 }
320 else {
322 }
323 }
324 }
325 } while (p != 0U);
326
327 // restore the active prio. and preemption-threshold
328 QK_priv_.actPrio = prio_in;
329 QK_priv_.actThre = pthre_in;
330 #ifndef Q_UNSAFE
331 QK_priv_.actPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actPrio);
332 QK_priv_.actThre_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actThre);
333 #endif
334
335 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
336 if (prio_in != 0U) { // resuming an active object?
337 a = QP::QActive::registry_[prio_in]; // pointer to preempted AO
338
339 QS_BEGIN_PRE_(QP::QS_SCHED_NEXT, prio_in)
340 QS_TIME_PRE_(); // timestamp
341 // prio. of the resumed AO, previous prio.
342 QS_2U8_PRE_(prio_in, pprev);
343 QS_END_PRE_()
344 }
345 else { // resuming prio.==0 --> idle
346 a = nullptr; // QK idle loop
347
348 QS_BEGIN_PRE_(QP::QS_SCHED_IDLE, pprev)
349 QS_TIME_PRE_(); // timestamp
350 QS_U8_PRE_(pprev); // previous prio.
351 QS_END_PRE_()
352 }
353
354 #ifdef QF_ON_CONTEXT_SW
356 #endif // QF_ON_CONTEXT_SW
357
358 #endif // QF_ON_CONTEXT_SW || Q_SPY
359}
360//$enddef${QK-extern-C} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
361} // extern "C"
362
363//$define${QK::QF-cust} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
364namespace QP {
365namespace QF {
366
367//${QK::QF-cust::init} .......................................................
368void init() {
369 bzero_(&QF::priv_, sizeof(QF::priv_));
370 bzero_(&QK_priv_, sizeof(QK_priv_));
372
373 // setup the QK scheduler as initially locked and not running
374 QK_priv_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
375
376 #ifndef Q_UNSAFE
378 QK_priv_.actPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actPrio);
379 QK_priv_.nextPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio);
380 QK_priv_.actThre_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actThre);
381 QK_priv_.lockCeil_dis = static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil);
382 #endif
383
384 #ifdef QK_INIT
385 QK_INIT(); // port-specific initialization of the QK kernel
386 #endif
387}
388
389//${QK::QF-cust::stop} .......................................................
390void stop() {
391 onCleanup(); // cleanup callback
392 // nothing else to do for the QK preemptive kernel
393}
394
395//${QK::QF-cust::run} ........................................................
397 #ifdef Q_SPY
398 // produce the QS_QF_RUN trace record
400 QF_MEM_SYS();
401 QS::beginRec_(QS_REC_NUM_(QS_QF_RUN));
402 QS::endRec_();
403 QF_MEM_APP();
405 #endif // Q_SPY
406
407 onStartup(); // application-specific startup callback
408
410 QF_MEM_SYS();
411
412 #ifdef QK_START
413 QK_START(); // port-specific startup of the QK kernel
414 #endif
415
416 QK_priv_.lockCeil = 0U; // unlock the QK scheduler
417 #ifndef Q_UNSAFE
418 QK_priv_.lockCeil_dis = static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil);
419 #endif
420
421 // activate AOs to process events posted so far
422 if (QK_sched_() != 0U) {
423 QK_activate_();
424 }
425
426 QF_MEM_APP();
428
429 for (;;) { // QK idle loop...
430 QK::onIdle(); // application-specific QK on-idle callback
431 }
432
433 #ifdef __GNUC__ // GNU compiler?
434 return 0;
435 #endif
436}
437
438} // namespace QF
439} // namespace QP
440//$enddef${QK::QF-cust} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
441
442//$define${QK::QActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
443namespace QP {
444
445//${QK::QActive} .............................................................
446
447//${QK::QActive::start} ......................................................
449 QPrioSpec const prioSpec,
450 QEvt const * * const qSto,
451 std::uint_fast16_t const qLen,
452 void * const stkSto,
453 std::uint_fast16_t const stkSize,
454 void const * const par)
455{
456 Q_UNUSED_PAR(stkSto); // not needed in QK
457 Q_UNUSED_PAR(stkSize); // not needed in QK
458
461 QF_MEM_SYS();
462
464 && (stkSto == nullptr));
465 QF_MEM_APP();
466 QF_CRIT_EXIT();
467
468 m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio.
469 m_pthre = static_cast<std::uint8_t>(prioSpec >> 8U); // preemption-thre.
470 register_(); // make QF aware of this AO
471
472 m_eQueue.init(qSto, qLen); // init the built-in queue
473
474 // top-most initial tran. (virtual call)
475 this->init(par, m_prio);
476 QS_FLUSH(); // flush the trace buffer to the host
477
478 // See if this AO needs to be scheduled if QK is already running
480 QF_MEM_SYS();
481 if (QK_sched_() != 0U) { // activation needed?
482 QK_activate_();
483 }
484 QF_MEM_APP();
485 QF_CRIT_EXIT();
486}
487
488} // namespace QP
489//$enddef${QK::QActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Private attributes of the QK kernel.
Definition qk.hpp:76
std::uint_fast8_t actThre
Definition qk.hpp:81
std::uint_fast8_t actPrio_dis
Definition qk.hpp:90
std::uint_fast8_t lockCeil
Definition qk.hpp:82
QP::QPSet readySet_dis
Definition qk.hpp:86
QP::QPSet readySet
Definition qk.hpp:78
std::uint_fast8_t lockCeil_dis
Definition qk.hpp:102
std::uint_fast8_t nextPrio
Definition qk.hpp:80
std::uint_fast8_t nextPrio_dis
Definition qk.hpp:94
std::uint_fast8_t actThre_dis
Definition qk.hpp:98
std::uint_fast8_t actPrio
Definition qk.hpp:79
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:724
void init(void const *const e, std::uint_fast8_t const qsId) override
Definition qp.hpp:781
std::uint8_t m_pthre_dis
Definition qp.hpp:748
QEvt const * get_() noexcept
Definition qf_actq.cpp:308
std::uint_fast8_t getPThre() const noexcept
Definition qp.hpp:858
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Definition qp.hpp:790
QACTIVE_EQUEUE_TYPE m_eQueue
Definition qp.hpp:738
std::uint8_t m_pthre
Definition qp.hpp:727
void start(QPrioSpec const prioSpec, QEvt const **const qSto, std::uint_fast16_t const qLen, void *const stkSto, std::uint_fast16_t const stkSize, void const *const par)
Definition qk.cpp:448
std::uint_fast8_t getPrio() const noexcept
Definition qp.hpp:851
static QActive * registry_[QF_MAX_ACTIVE+1U]
Definition qp.hpp:750
QACTIVE_EQUEUE_TYPE const & getEQueue() const noexcept
Definition qp.hpp:863
std::uint8_t m_prio
Definition qp.hpp:726
void register_() noexcept
Definition qf_qact.cpp:76
Event class.
Definition qp.hpp:139
bool isEmpty() const noexcept
Definition qp.hpp:623
void update_(QPSet *const dis) const noexcept
Definition qp.hpp:681
bool verify_(QPSet const *const dis) const noexcept
Definition qp.hpp:690
void remove(std::uint_fast8_t const n) noexcept
Definition qp.hpp:658
std::uint_fast8_t findMax() const noexcept
Definition qp.hpp:670
void onStartup()
int_t run()
Definition qk.cpp:396
void onCleanup()
void stop()
Definition qk.cpp:390
void bzero_(void *const start, std::uint_fast16_t const len) noexcept
Definition qf_act.cpp:81
QF::Attr priv_
Definition qf_act.cpp:78
void init()
Definition qk.cpp:368
void gc(QEvt const *const e) noexcept
Definition qf_dyn.cpp:236
void onIdle()
QSchedStatus schedLock(std::uint_fast8_t const ceiling) noexcept
Definition qk.cpp:76
void schedUnlock(QSchedStatus const prevCeil) noexcept
Definition qk.cpp:115
QP/C++ framework.
Definition qequeue.hpp:50
std::uint_fast8_t QSchedStatus
Definition qk.hpp:50
std::uint16_t QPrioSpec
Definition qp.hpp:574
@ QS_SCHED_LOCK
scheduler was locked
Definition qs.hpp:145
@ QS_QF_RUN
QF_run() was entered.
Definition qs.hpp:171
@ QS_SCHED_NEXT
scheduler started next task
Definition qs.hpp:147
@ QS_SCHED_UNLOCK
scheduler was unlocked
Definition qs.hpp:146
@ QS_SCHED_IDLE
scheduler restored the idle task
Definition qs.hpp:148
void QK_activate_() noexcept
Definition qk.cpp:206
QK_Attr QK_priv_
Definition qk.cpp:158
std::uint_fast8_t QK_sched_() noexcept
Definition qk.cpp:161
QK_Attr QK_priv_
Definition qk.cpp:158
std::uint_fast8_t QK_sched_() noexcept
Definition qk.cpp:161
void QK_activate_() noexcept
Definition qk.cpp:206
int int_t
Definition qp.hpp:105
#define QF_MEM_APP()
Definition qp.hpp:1276
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:541
void QF_onContextSw(QP::QActive *prev, QP::QActive *next)
#define QF_MEM_SYS()
Definition qp.hpp:1271
#define QF_MAX_ACTIVE
Internal (package scope) QP/C++ interface.
Sample QP/C++ port.
#define QK_ISR_CONTEXT_()
Definition qp_port.hpp:111
#define QF_INT_DISABLE()
Disable interrupts.
Definition qp_port.hpp:36
#define QF_INT_ENABLE()
Enable interrupts.
Definition qp_port.hpp:39
#define QS_TIME_PRE_()
Definition qs.hpp:473
#define QS_FLUSH()
Definition qs.hpp:363
QS/C++ package-scope interface.
QS/C++ port to a 32-bit CPU, generic C++ compiler.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:72
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define QF_CRIT_STAT
Definition qsafe.h:54