QP/C  7.4.0-rc.2
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qk.c
Go to the documentation of this file.
1//$file${src::qk::qk.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qk::qk.c}
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) : qpc
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.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.h" // QP port
45#include "qp_pkg.h" // QP package-scope internal interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.h" // QS port
49 #include "qs_pkg.h" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.h" // disable the QS software tracing
52#endif // Q_SPY
53
54// protection against including this source file in a wrong project
55#ifndef QK_H_
56 #error "Source file included in a project NOT based on the QK kernel"
57#endif // QK_H_
58
59Q_DEFINE_THIS_MODULE("qk")
60
61//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
62// Check for the minimum required QP version
63#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
64#error qpc version 7.3.0 or higher required
65#endif
66//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67
68//$define${QK::QK-base} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
69
70//${QK::QK-base::priv_} ......................................................
71QK_Attr QK_priv_;
72
73//${QK::QK-base::schedLock} ..................................................
74//! @static @public @memberof QK
75QSchedStatus QK_schedLock(uint_fast8_t const ceiling) {
78 QF_MEM_SYS();
79
81 Q_INVARIANT_INCRIT(102, QK_priv_.lockCeil
82 == (uint_fast8_t)(~QK_priv_.lockCeil_dis));
83
84 // first store the previous lock prio
85 QSchedStatus stat;
86 if (ceiling > QK_priv_.lockCeil) { // raising the lock ceiling?
87 QS_BEGIN_PRE_(QS_SCHED_LOCK, QK_priv_.actPrio)
88 QS_TIME_PRE_(); // timestamp
89 // the previous lock ceiling & new lock ceiling
90 QS_2U8_PRE_((uint8_t)QK_priv_.lockCeil, (uint8_t)ceiling);
91 QS_END_PRE_()
92
93 // previous status of the lock
94 stat = (QSchedStatus)QK_priv_.lockCeil;
95
96 // new status of the lock
97 QK_priv_.lockCeil = ceiling;
98 #ifndef Q_UNSAFE
99 QK_priv_.lockCeil_dis = (uint_fast8_t)(~ceiling);
100 #endif
101 }
102 else {
103 stat = 0xFFU; // scheduler not locked
104 }
105
106 QF_MEM_APP();
107 QF_CRIT_EXIT();
108
109 return stat; // return the status to be saved in a stack variable
110}
111
112//${QK::QK-base::schedUnlock} ................................................
113//! @static @public @memberof QK
114void QK_schedUnlock(QSchedStatus const prevCeil) {
115 // has the scheduler been actually locked by the last QK_schedLock()?
116 if (prevCeil != 0xFFU) {
119 QF_MEM_SYS();
120
121 Q_INVARIANT_INCRIT(202, QK_priv_.lockCeil
122 == (uint_fast8_t)(~QK_priv_.lockCeil_dis));
124 && (QK_priv_.lockCeil > prevCeil));
125
126 QS_BEGIN_PRE_(QS_SCHED_UNLOCK, QK_priv_.actPrio)
127 QS_TIME_PRE_(); // timestamp
128 // current lock ceiling (old), previous lock ceiling (new)
129 QS_2U8_PRE_((uint8_t)QK_priv_.lockCeil, (uint8_t)prevCeil);
130 QS_END_PRE_()
131
132 // restore the previous lock ceiling
133 QK_priv_.lockCeil = prevCeil;
134 #ifndef Q_UNSAFE
135 QK_priv_.lockCeil_dis = (uint_fast8_t)(~prevCeil);
136 #endif
137
138 // find if any AOs should be run after unlocking the scheduler
139 if (QK_sched_() != 0U) { // preemption needed?
140 QK_activate_(); // activate any unlocked AOs
141 }
142
143 QF_MEM_APP();
144 QF_CRIT_EXIT();
145 }
146}
147
148//${QK::QK-base::sched_} .....................................................
149//! @static @private @memberof QK
150uint_fast8_t QK_sched_(void) {
151 // NOTE: this function is entered with interrupts DISABLED
152
153 Q_INVARIANT_INCRIT(402, QPSet_verify_(&QK_priv_.readySet,
154 &QK_priv_.readySet_dis));
155 uint_fast8_t p;
156 if (QPSet_isEmpty(&QK_priv_.readySet)) {
157 p = 0U; // no activation needed
158 }
159 else {
160 // find the highest-prio AO with non-empty event queue
161 p = QPSet_findMax(&QK_priv_.readySet);
162
164 QK_priv_.actThre == (uint_fast8_t)(~QK_priv_.actThre_dis));
165
166 // is the AO's prio. below the active preemption-threshold?
167 if (p <= QK_priv_.actThre) {
168 p = 0U; // no activation needed
169 }
170 else {
171 Q_INVARIANT_INCRIT(422, QK_priv_.lockCeil
172 == (uint_fast8_t)(~QK_priv_.lockCeil_dis));
173
174 // is the AO's prio. below the lock-ceiling?
175 if (p <= QK_priv_.lockCeil) {
176 p = 0U; // no activation needed
177 }
178 else {
179 Q_INVARIANT_INCRIT(432, QK_priv_.nextPrio
180 == (uint_fast8_t)(~QK_priv_.nextPrio_dis));
181 QK_priv_.nextPrio = p; // next AO to run
182 #ifndef Q_UNSAFE
183 QK_priv_.nextPrio_dis = (uint_fast8_t)(~QK_priv_.nextPrio);
184 #endif
185 }
186 }
187 }
188
189 return p;
190}
191
192//${QK::QK-base::activate_} ..................................................
193//! @static @private @memberof QK
194void QK_activate_(void) {
195 // NOTE: this function is entered with interrupts DISABLED
196
197 uint_fast8_t const prio_in = QK_priv_.actPrio; // save initial prio.
198 uint_fast8_t p = QK_priv_.nextPrio; // next prio to run
199
201 (prio_in == (uint_fast8_t)(~QK_priv_.actPrio_dis))
202 && (p == (uint_fast8_t)(~QK_priv_.nextPrio_dis)));
203 Q_REQUIRE_INCRIT(510, (prio_in <= QF_MAX_ACTIVE)
204 && (0U < p) && (p <= QF_MAX_ACTIVE));
205
206 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
207 uint_fast8_t pprev = prio_in;
208 #endif // QF_ON_CONTEXT_SW || Q_SPY
209
210 QK_priv_.nextPrio = 0U; // clear for the next time
211 #ifndef Q_UNSAFE
212 QK_priv_.nextPrio_dis = (uint_fast8_t)(~0U);
213 #endif
214
215 uint_fast8_t pthre_in;
216 QActive *a;
217 if (prio_in == 0U) { // preempting the idle thread?
218 pthre_in = 0U;
219 }
220 else {
221 a = QActive_registry_[prio_in];
222 Q_ASSERT_INCRIT(510, a != (QActive *)0);
223
224 pthre_in = (uint_fast8_t)a->pthre;
225 Q_INVARIANT_INCRIT(511, pthre_in ==
226 (uint_fast8_t)(~(uint_fast8_t)a->pthre_dis & 0xFFU));
227 }
228
229 // loop until no more ready-to-run AOs of higher pthre than the initial
230 do {
231 a = QActive_registry_[p]; // obtain the pointer to the AO
232 Q_ASSERT_INCRIT(520, a != (QActive *)0); // the AO must be registered
233 uint_fast8_t const pthre = (uint_fast8_t)a->pthre;
234 Q_INVARIANT_INCRIT(522, pthre ==
235 (uint_fast8_t)(~(uint_fast8_t)a->pthre_dis & 0xFFU));
236
237 // set new active prio. and preemption-threshold
238 QK_priv_.actPrio = p;
239 QK_priv_.actThre = pthre;
240 #ifndef Q_UNSAFE
241 QK_priv_.actPrio_dis = (uint_fast8_t)(~p);
242 QK_priv_.actThre_dis = (uint_fast8_t)(~pthre);
243 #endif
244
245 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
246 if (p != pprev) { // changing threads?
247
248 QS_BEGIN_PRE_(QS_SCHED_NEXT, p)
249 QS_TIME_PRE_(); // timestamp
250 QS_2U8_PRE_(p, // prio. of the scheduled AO
251 pprev); // previous prio.
252 QS_END_PRE_()
253
254 #ifdef QF_ON_CONTEXT_SW
255 QF_onContextSw(QActive_registry_[pprev], a);
256 #endif // QF_ON_CONTEXT_SW
257
258 pprev = p; // update previous prio.
259 }
260 #endif // QF_ON_CONTEXT_SW || Q_SPY
261
262 QF_MEM_APP();
263 QF_INT_ENABLE(); // unconditionally enable interrupts
264
265 QEvt const * const e = QActive_get_(a);
266 // NOTE QActive_get_() performs QF_MEM_APP() before return
267
268 // dispatch event (virtual call)
269 (*a->super.vptr->dispatch)(&a->super, e, p);
270 #if (QF_MAX_EPOOL > 0U)
271 QF_gc(e);
272 #endif
273
274 // determine the next highest-prio. AO ready to run...
275 QF_INT_DISABLE(); // unconditionally disable interrupts
276 QF_MEM_SYS();
277
278 // internal integrity check (duplicate inverse storage)
279 Q_INVARIANT_INCRIT(532, QPSet_verify_(&QK_priv_.readySet,
280 &QK_priv_.readySet_dis));
281
282 if (a->eQueue.frontEvt == (QEvt *)0) { // empty queue?
283 QPSet_remove(&QK_priv_.readySet, p);
284 #ifndef Q_UNSAFE
285 QPSet_update_(&QK_priv_.readySet, &QK_priv_.readySet_dis);
286 #endif
287 }
288
289 if (QPSet_isEmpty(&QK_priv_.readySet)) {
290 p = 0U; // no activation needed
291 }
292 else {
293 // find new highest-prio AO ready to run...
294 p = QPSet_findMax(&QK_priv_.readySet);
295
296 // is the new prio. below the initial preemption-threshold?
297 if (p <= pthre_in) {
298 p = 0U; // no activation needed
299 }
300 else {
301 Q_INVARIANT_INCRIT(542, QK_priv_.lockCeil
302 == (uint_fast8_t)(~QK_priv_.lockCeil_dis));
303
304 // is the AO's prio. below the lock preemption-threshold?
305 if (p <= QK_priv_.lockCeil) {
306 p = 0U; // no activation needed
307 }
308 else {
310 }
311 }
312 }
313 } while (p != 0U);
314
315 // restore the active prio. and preemption-threshold
316 QK_priv_.actPrio = prio_in;
317 QK_priv_.actThre = pthre_in;
318 #ifndef Q_UNSAFE
319 QK_priv_.actPrio_dis = (uint_fast8_t)(~QK_priv_.actPrio);
320 QK_priv_.actThre_dis = (uint_fast8_t)(~QK_priv_.actThre);
321 #endif
322
323 #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
324 if (prio_in != 0U) { // resuming an active object?
325 a = QActive_registry_[prio_in]; // pointer to preempted AO
326
327 QS_BEGIN_PRE_(QS_SCHED_NEXT, prio_in)
328 QS_TIME_PRE_(); // timestamp
329 // prio. of the resumed AO, previous prio.
330 QS_2U8_PRE_(prio_in, pprev);
331 QS_END_PRE_()
332 }
333 else { // resuming prio.==0 --> idle
334 a = (QActive *)0; // QK idle loop
335
336 QS_BEGIN_PRE_(QS_SCHED_IDLE, pprev)
337 QS_TIME_PRE_(); // timestamp
338 QS_U8_PRE_(pprev); // previous prio.
339 QS_END_PRE_()
340 }
341
342 #ifdef QF_ON_CONTEXT_SW
343 QF_onContextSw(QActive_registry_[pprev], a);
344 #endif // QF_ON_CONTEXT_SW
345
346 #endif // QF_ON_CONTEXT_SW || Q_SPY
347}
348//$enddef${QK::QK-base} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
349
350//$define${QK::QF-cust} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
351
352//${QK::QF-cust::init} .......................................................
353//! @static @public @memberof QF
354void QF_init(void) {
355 QF_bzero_(&QF_priv_, sizeof(QF_priv_));
356 QF_bzero_(&QK_priv_, sizeof(QK_priv_));
357 QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
358
359 // setup the QK scheduler as initially locked and not running
360 QK_priv_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
361
362 #ifndef Q_UNSAFE
363 QPSet_update_(&QK_priv_.readySet, &QK_priv_.readySet_dis);
364 QK_priv_.actPrio_dis = (uint_fast8_t)(~0U);
365 QK_priv_.nextPrio_dis = (uint_fast8_t)(~0U);
366 QK_priv_.actThre_dis = (uint_fast8_t)(~0U);
367 QK_priv_.lockCeil_dis = (uint_fast8_t)(~QK_priv_.lockCeil);
368 #endif
369
370 for (uint_fast8_t tickRate = 0U;
371 tickRate < Q_DIM(QTimeEvt_timeEvtHead_);
372 ++tickRate)
373 {
374 QTimeEvt_ctorX(&QTimeEvt_timeEvtHead_[tickRate],
375 (QActive *)0, (enum_t)Q_USER_SIG, tickRate);
376 }
377
378 #ifdef QK_INIT
379 QK_INIT(); // port-specific initialization of the QK kernel
380 #endif
381}
382
383//${QK::QF-cust::stop} .......................................................
384//! @static @public @memberof QF
385void QF_stop(void) {
386 QF_onCleanup(); // application-specific cleanup callback
387 // nothing else to do for the preemptive QK kernel
388}
389
390//${QK::QF-cust::run} ........................................................
391//! @static @public @memberof QF
392int_t QF_run(void) {
393 #ifdef Q_SPY
394 // produce the QS_QF_RUN trace record
396 QF_MEM_SYS();
397 QS_beginRec_((uint_fast8_t)QS_QF_RUN);
398 QS_endRec_();
399 QF_MEM_APP();
401 #endif // Q_SPY
402
403 QF_onStartup(); // application-specific startup callback
404
406 QF_MEM_SYS();
407
408 #ifdef QK_START
409 QK_START(); // port-specific startup of the QK kernel
410 #endif
411
412 QK_priv_.lockCeil = 0U; // unlock the QK scheduler
413 #ifndef Q_UNSAFE
414 QK_priv_.lockCeil_dis = (uint_fast8_t)(~0U);
415 #endif
416
417 // activate AOs to process events posted so far
418 if (QK_sched_() != 0U) {
419 QK_activate_();
420 }
421
422 QF_MEM_APP();
424
425 for (;;) { // QK idle loop...
426 QK_onIdle(); // application-specific QK on-idle callback
427 }
428
429 #ifdef __GNUC__
430 return 0;
431 #endif
432}
433//$enddef${QK::QF-cust} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
434
435//$define${QK::QActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
436
437//${QK::QActive} .............................................................
438
439//${QK::QActive::start_} .....................................................
440//! @public @memberof QActive
441void QActive_start_(QActive * const me,
442 QPrioSpec const prioSpec,
443 QEvt const * * const qSto,
444 uint_fast16_t const qLen,
445 void * const stkSto,
446 uint_fast16_t const stkSize,
447 void const * const par)
448{
449 Q_UNUSED_PAR(stkSto); // not needed in QK
450 Q_UNUSED_PAR(stkSize); // not needed in QK
451
454 QF_MEM_SYS();
455
457 && (stkSto == (void *)0));
458 QF_MEM_APP();
459 QF_CRIT_EXIT();
460
461 me->prio = (uint8_t)(prioSpec & 0xFFU); // QF-prio. of the AO
462 me->pthre = (uint8_t)(prioSpec >> 8U); // preemption-threshold
463 QActive_register_(me); // make QF aware of this active object
464
465 QEQueue_init(&me->eQueue, qSto, qLen); // init the built-in queue
466
467 // top-most initial tran. (virtual call)
468 (*me->super.vptr->init)(&me->super, par, me->prio);
469 QS_FLUSH(); // flush the trace buffer to the host
470
471 // See if this AO needs to be scheduled if QK is already running
473 QF_MEM_SYS();
474 if (QK_sched_() != 0U) { // activation needed?
475 QK_activate_();
476 }
477 QF_MEM_APP();
478 QF_CRIT_EXIT();
479}
480//$enddef${QK::QActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
QF_Attr QF_priv_
Definition qf_act.c:71
uint_fast8_t QSchedStatus
Definition qk.h:60
#define QF_MEM_APP()
Definition qp.h:1288
#define Q_UNUSED_PAR(par_)
Definition qp.h:536
@ Q_USER_SIG
offset for the user signals (QP Application)
Definition qp.h:263
#define QF_MEM_SYS()
Definition qp.h:1283
int int_t
Definition qp.h:104
int enum_t
Definition qp.h:107
#define Q_DIM(array_)
Definition qp.h:539
uint16_t QPrioSpec
Definition qp.h:623
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
Definition qp_config.h:113
Internal (package scope) QP/C interface.
Sample QP/C port.
#define QK_ISR_CONTEXT_()
Definition qp_port.h:105
#define QF_INT_DISABLE()
Disable interrupts.
Definition qp_port.h:37
#define QF_INT_ENABLE()
Enable interrupts.
Definition qp_port.h:40
@ QS_QF_RUN
QF_run() was entered.
Definition qs.h:179
#define QS_TIME_PRE_()
Definition qs.h:450
@ QS_SCHED_IDLE
scheduler restored the idle task
Definition qs.h:156
@ QS_SCHED_LOCK
scheduler was locked
Definition qs.h:153
@ QS_SCHED_UNLOCK
scheduler was unlocked
Definition qs.h:154
#define QS_FLUSH()
Definition qs.h:363
@ QS_SCHED_NEXT
scheduler started next task
Definition qs.h:155
QS/C package-scope interface.
Sample QS/C port.
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
int_t QF_run(void)
Definition qutest.c:191
void QF_init(void)
Definition qutest.c:172
void QF_stop(void)
Definition qutest.c:186
Active object class (based on the QHsm implementation strategy)
Definition qp.h:804
uint8_t pthre_dis
Definition qp.h:836
QACTIVE_EQUEUE_TYPE eQueue
Definition qp.h:826
QAsm super
Definition qp.h:806
uint8_t prio
Definition qp.h:809
uint8_t pthre
Definition qp.h:812
struct QAsmVtable const * vptr
Definition qp.h:284
void(* init)(QAsm *const me, void const *const e, uint_fast8_t const qsId)
Definition qp.h:302
void(* dispatch)(QAsm *const me, QEvt const *const e, uint_fast8_t const qsId)
Definition qp.h:304
Event class.
Definition qp.h:145
Private attributes of the QK kernel.
Definition qk.h:67