QP/C++  7.4.0-rc.1
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_INVARIANT_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_INVARIANT_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_MEM_APP();
276 QF_INT_ENABLE(); // unconditionally enable interrupts
277
278 QP::QEvt const * const e = a->get_();
279 // NOTE QActive_get_() performs QF_MEM_APP() before return
280
281 // dispatch event (virtual call)
282 a->dispatch(e, a->getPrio());
283 #if (QF_MAX_EPOOL > 0U)
284 QP::QF::gc(e);
285 #endif
286
287 // determine the next highest-prio. AO ready to run...
288 QF_INT_DISABLE(); // unconditionally disable interrupts
289 QF_MEM_SYS();
290
291 // internal integrity check (duplicate inverse storage)
294
295 if (a->getEQueue().isEmpty()) { // empty queue?
297 #ifndef Q_UNSAFE
299 #endif
300 }
301
302 if (QK_priv_.readySet.isEmpty()) {
303 p = 0U; // no activation needed
304 }
305 else {
306 // find new highest-prio AO ready to run...
308
309 // is the new prio. below the initial preemption-threshold?
310 if (p <= pthre_in) {
311 p = 0U; // no activation needed
312 }
313 else {
316
317 // is the AO's prio. below the lock preemption-threshold?
318 if (p <= QK_priv_.lockCeil) {
319 p = 0U; // no activation needed
320 }
321 else {
323 }
324 }
325 }
326 } while (p != 0U);
327
328 // restore the active prio. and preemption-threshold
329 QK_priv_.actPrio = prio_in;
330 QK_priv_.actThre = pthre_in;
331 #ifndef Q_UNSAFE
332 QK_priv_.actPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actPrio);
333 QK_priv_.actThre_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actThre);
334 #endif
335
336 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
337 if (prio_in != 0U) { // resuming an active object?
338 a = QP::QActive::registry_[prio_in]; // pointer to preempted AO
339
340 QS_BEGIN_PRE_(QP::QS_SCHED_NEXT, prio_in)
341 QS_TIME_PRE_(); // timestamp
342 // prio. of the resumed AO, previous prio.
343 QS_2U8_PRE_(prio_in, pprev);
344 QS_END_PRE_()
345 }
346 else { // resuming prio.==0 --> idle
347 a = nullptr; // QK idle loop
348
349 QS_BEGIN_PRE_(QP::QS_SCHED_IDLE, pprev)
350 QS_TIME_PRE_(); // timestamp
351 QS_U8_PRE_(pprev); // previous prio.
352 QS_END_PRE_()
353 }
354
355 #ifdef QF_ON_CONTEXT_SW
357 #endif // QF_ON_CONTEXT_SW
358
359 #endif // QF_ON_CONTEXT_SW || Q_SPY
360}
361//$enddef${QK-extern-C} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
362} // extern "C"
363
364//$define${QK::QF-cust} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
365namespace QP {
366namespace QF {
367
368//${QK::QF-cust::init} .......................................................
369void init() {
370 bzero_(&QF::priv_, sizeof(QF::priv_));
371 bzero_(&QK_priv_, sizeof(QK_priv_));
373
374 // setup the QK scheduler as initially locked and not running
375 QK_priv_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
376
377 #ifndef Q_UNSAFE
379 QK_priv_.actPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actPrio);
380 QK_priv_.nextPrio_dis = static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio);
381 QK_priv_.actThre_dis = static_cast<std::uint_fast8_t>(~QK_priv_.actThre);
382 QK_priv_.lockCeil_dis = static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil);
383 #endif
384
385 #ifdef QK_INIT
386 QK_INIT(); // port-specific initialization of the QK kernel
387 #endif
388}
389
390//${QK::QF-cust::stop} .......................................................
391void stop() {
392 onCleanup(); // cleanup callback
393 // nothing else to do for the QK preemptive kernel
394}
395
396//${QK::QF-cust::run} ........................................................
398 #ifdef Q_SPY
399 // produce the QS_QF_RUN trace record
401 QF_MEM_SYS();
402 QS::beginRec_(QS_REC_NUM_(QS_QF_RUN));
403 QS::endRec_();
404 QF_MEM_APP();
406 #endif // Q_SPY
407
408 onStartup(); // application-specific startup callback
409
411 QF_MEM_SYS();
412
413 #ifdef QK_START
414 QK_START(); // port-specific startup of the QK kernel
415 #endif
416
417 QK_priv_.lockCeil = 0U; // unlock the QK scheduler
418 #ifndef Q_UNSAFE
419 QK_priv_.lockCeil_dis = static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil);
420 #endif
421
422 // activate AOs to process events posted so far
423 if (QK_sched_() != 0U) {
424 QK_activate_();
425 }
426
427 QF_MEM_APP();
429
430 for (;;) { // QK idle loop...
431 QK::onIdle(); // application-specific QK on-idle callback
432 }
433
434 #ifdef __GNUC__ // GNU compiler?
435 return 0;
436 #endif
437}
438
439} // namespace QF
440} // namespace QP
441//$enddef${QK::QF-cust} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
442
443//$define${QK::QActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
444namespace QP {
445
446//${QK::QActive} .............................................................
447
448//${QK::QActive::start} ......................................................
450 QPrioSpec const prioSpec,
451 QEvt const * * const qSto,
452 std::uint_fast16_t const qLen,
453 void * const stkSto,
454 std::uint_fast16_t const stkSize,
455 void const * const par)
456{
457 Q_UNUSED_PAR(stkSto); // not needed in QK
458 Q_UNUSED_PAR(stkSize); // not needed in QK
459
462 QF_MEM_SYS();
463
465 && (stkSto == nullptr));
466 QF_MEM_APP();
467 QF_CRIT_EXIT();
468
469 m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio.
470 m_pthre = static_cast<std::uint8_t>(prioSpec >> 8U); // preemption-thre.
471 register_(); // make QF aware of this AO
472
473 m_eQueue.init(qSto, qLen); // init the built-in queue
474
475 // top-most initial tran. (virtual call)
476 this->init(par, m_prio);
477 QS_FLUSH(); // flush the trace buffer to the host
478
479 // See if this AO needs to be scheduled if QK is already running
481 QF_MEM_SYS();
482 if (QK_sched_() != 0U) { // activation needed?
483 QK_activate_();
484 }
485 QF_MEM_APP();
486 QF_CRIT_EXIT();
487}
488
489} // namespace QP
490//$enddef${QK::QActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Private attributes of the QK kernel.
Definition qk.hpp:76
std::uint_fast8_t actPrio_dis
Definition qk.hpp:90
std::uint_fast8_t actThre
Definition qk.hpp:81
QP::QPSet readySet
Definition qk.hpp:78
std::uint_fast8_t lockCeil_dis
Definition qk.hpp:102
QP::QPSet readySet_dis
Definition qk.hpp:86
std::uint_fast8_t nextPrio
Definition qk.hpp:80
std::uint_fast8_t actPrio
Definition qk.hpp:79
std::uint_fast8_t nextPrio_dis
Definition qk.hpp:94
std::uint_fast8_t actThre_dis
Definition qk.hpp:98
std::uint_fast8_t lockCeil
Definition qk.hpp:82
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:722
void init(void const *const e, std::uint_fast8_t const qsId) override
Definition qp.hpp:779
static QActive * registry_[QF_MAX_ACTIVE+1U]
Definition qp.hpp:748
std::uint8_t m_pthre_dis
Definition qp.hpp:746
void register_() noexcept
Definition qf_qact.cpp:76
std::uint_fast8_t getPThre() const noexcept
Definition qp.hpp:856
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Definition qp.hpp:788
QACTIVE_EQUEUE_TYPE m_eQueue
Definition qp.hpp:736
QEvt const * get_() noexcept
Definition qf_actq.cpp:330
std::uint8_t m_pthre
Definition qp.hpp:725
std::uint_fast8_t getPrio() const noexcept
Definition qp.hpp:849
QACTIVE_EQUEUE_TYPE const & getEQueue() const noexcept
Definition qp.hpp:861
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:449
std::uint8_t m_prio
Definition qp.hpp:724
Event class.
Definition qp.hpp:137
std::uint_fast8_t findMax() const noexcept
Definition qp.hpp:668
void remove(std::uint_fast8_t const n) noexcept
Definition qp.hpp:656
bool verify_(QPSet const *const dis) const noexcept
Definition qp.hpp:688
void update_(QPSet *const dis) const noexcept
Definition qp.hpp:679
bool isEmpty() const noexcept
Definition qp.hpp:621
void onCleanup()
void gc(QEvt const *const e) noexcept
Definition qf_dyn.cpp:222
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:369
int_t run()
Definition qk.cpp:397
void stop()
Definition qk.cpp:391
void onStartup()
QSchedStatus schedLock(std::uint_fast8_t const ceiling) noexcept
Definition qk.cpp:76
void schedUnlock(QSchedStatus const prevCeil) noexcept
Definition qk.cpp:115
void onIdle()
QP/C++ framework.
Definition qequeue.hpp:50
std::uint_fast8_t QSchedStatus
Definition qk.hpp:50
std::uint16_t QPrioSpec
Definition qp.hpp:572
@ 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
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
int int_t
Definition qp.hpp:103
#define QF_MEM_APP()
Definition qp.hpp:1331
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:539
void QF_onContextSw(QP::QActive *prev, QP::QActive *next)
#define QF_MEM_SYS()
Definition qp.hpp:1326
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
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 Q_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:154
#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