QP/C 8.1.2
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_qact.c
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.h" // QP port
31#include "qp_pkg.h" // 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.h" // QS port
35 #include "qs_pkg.h" // QS facilities for pre-defined trace records
36#else
37 #include "qs_dummy.h" // disable the QS software tracing
38#endif // Q_SPY
39
40Q_DEFINE_THIS_MODULE("qf_qact")
41
42//! @static @private @memberof QActive
43QActive * QActive_registry_[QF_MAX_ACTIVE + 1U];
44
45//! @static @private @memberof QF
46QF_Attr QF_priv_;
47
48//----------------------------------------------------------------------------
49//! @protected @memberof QActive
50void QActive_ctor(QActive * const me,
51 QStateHandler const initial)
52{
53 // NOTE: QActive indirectly inherits the abstract QAsm base class,
54 // but it will delegate the state machine behavior to the QHsm class,
55 // so the following initiaization is identical as in QHsm ctor:
56 QHsm_ctor((QHsm *)(me), initial);
57
58 // NOTE: this vtable is identical as QHsm, but is provided
59 // for the QActive subclass to ensure a UNIQUE vptr to distinguish
60 // subclasses of QActive (e.g., in the debugger).
61 static struct QAsmVtable const vtable = { // QActive virtual table
62 &QHsm_init_,
63 &QHsm_dispatch_,
64 &QHsm_isIn_,
65 &QHsm_getStateHandler_
66 };
67 me->super.vptr = &vtable; // hook vptr to QActive vtable
68}
69
70//............................................................................
71//! @private @memberof QActive
72void QActive_register_(QActive * const me) {
75
76 if (me->pthre == 0U) { // preemption-threshold not defined?
77 me->pthre = me->prio; // apply the default
78 }
79
80 // AO's prio. must be in range
81 Q_REQUIRE_INCRIT(100, (0U < me->prio) && (me->prio <= QF_MAX_ACTIVE));
82
83 // the AO must NOT be registered already
85
86 // the AO's prio. must not exceed the preemption threshold
87 Q_REQUIRE_INCRIT(130, me->prio <= me->pthre);
88
89#ifndef Q_UNSAFE
90 uint8_t prev_thre = me->pthre;
91 uint8_t next_thre = me->pthre;
92
93 for (uint8_t p = me->prio - 1U; p > 0U; --p) {
94 if (QActive_registry_[p] != (QActive *)0) {
95 prev_thre = QActive_registry_[p]->pthre;
96 break;
97 }
98 }
99 for (uint8_t p = me->prio + 1U; p <= QF_MAX_ACTIVE; ++p) {
100 if (QActive_registry_[p] != (QActive *)0) {
101 next_thre = QActive_registry_[p]->pthre;
102 break;
103 }
104 }
105
106 // the preemption threshold of this AO must be between
107 // preemption threshold of the previous AO and next AO
108 Q_ASSERT_INCRIT(160,
109 (prev_thre <= me->pthre) && (me->pthre <= next_thre));
110
111#endif // Q_UNSAFE
112
113 // register the AO at the QF-prio.
114 QActive_registry_[me->prio] = me;
115
116 QF_CRIT_EXIT();
117}
118
119//............................................................................
120//! @private @memberof QActive
121void QActive_unregister_(QActive * const me) {
124
125 uint8_t const p = me->prio; // put AO's prio. in a temporary
126
127 // AO's prio. must be in range
128 Q_REQUIRE_INCRIT(210, (0U < p) && (p <= QF_MAX_ACTIVE));
129
130 // this AO must be registered at prio. p
131 Q_REQUIRE_INCRIT(230, me == QActive_registry_[p]);
132
133 me->super.state.fun = Q_STATE_CAST(0); // invalidate the state
134 QActive_registry_[p] = (QActive *)0; // free-up the prio. level
135
136 QF_CRIT_EXIT();
137}
138
139//----------------------------------------------------------------------------
140#ifndef QF_LOG2
141uint_fast8_t QF_LOG2(QPSetBits const bitmask) {
142 // look-up table for log2(0..15)
143 static uint8_t const log2LUT[16] = {
144 0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U,
145 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
146 };
147 uint_fast8_t n = 0U;
148 QPSetBits x = bitmask;
149 QPSetBits tmp; // temporary for modified bitmask parameter
150
151#if (QF_MAX_ACTIVE > 16U)
152 tmp = (x >> 16U);
153 if (tmp != 0U) { // x > 2^16?
154 n += 16U;
155 x = tmp;
156 }
157#endif
158#if (QF_MAX_ACTIVE > 8U)
159 tmp = (x >> 8U);
160 if (tmp != 0U) { // x > 2^8?
161 n += 8U;
162 x = tmp;
163 }
164#endif
165 tmp = (x >> 4U);
166 if (tmp != 0U) { // x > 2^4?
167 n += 4U;
168 x = tmp;
169 }
170 // x is guaranteed to be in the 0..15 range for the look-up
171 return (uint_fast8_t)(n + log2LUT[x]);
172}
173#endif // ndef QF_LOG2
174
175//----------------------------------------------------------------------------
176//! @public @memberof QPSet
177void QPSet_setEmpty(QPSet * const me) {
178 me->bits0 = 0U; // clear bitmask for elements 1..32
179#if (QF_MAX_ACTIVE > 32)
180 me->bits1 = 0U; // clear bitmask for elements 33..64
181#endif
182}
183//............................................................................
184//! @public @memberof QPSet
185bool QPSet_isEmpty(QPSet const * const me) {
186#if (QF_MAX_ACTIVE <= 32U)
187 return (me->bits0 == 0U); // check only bitmask for elements 1..32
188#else
189 return (me->bits0 == 0U) // bitmask for elements 1..32 empty?
190 ? (me->bits1 == 0U) // check bitmask for for elements 33..64
191 : false; // the set is NOT empty
192#endif
193}
194//............................................................................
195//! @public @memberof QPSet
196bool QPSet_notEmpty(QPSet const * const me) {
197#if (QF_MAX_ACTIVE <= 32U)
198 return (me->bits0 != 0U); // check only bitmask for elements 1..32
199#else
200 return (me->bits0 != 0U) // bitmask for elements 1..32 empty?
201 ? true // the set is NOT empty
202 : (me->bits1 != 0U); // check bitmask for for elements 33..64
203#endif
204}
205//............................................................................
206//! @public @memberof QPSet
207bool QPSet_hasElement(QPSet const * const me, uint_fast8_t const n) {
208#if (QF_MAX_ACTIVE <= 32U)
209 // check the bit only in bitmask for elements 1..32
210 return (me->bits0 & ((QPSetBits)1U << (n - 1U))) != 0U;
211#else
212 return (n <= 32U) // which group of elements (1..32 or 33..64)?
213 ? ((me->bits0 & ((QPSetBits)1U << (n - 1U))) != 0U)
214 : ((me->bits1 & ((QPSetBits)1U << (n - 33U))) != 0U);
215#endif
216}
217//............................................................................
218//! @public @memberof QPSet
219void QPSet_insert(QPSet * const me, uint_fast8_t const n) {
220#if (QF_MAX_ACTIVE <= 32U)
221 // set the bit only in bitmask for elements 1..32
222 me->bits0 = (me->bits0 | ((QPSetBits)1U << (n - 1U)));
223#else
224 if (n <= 32U) { // set the bit in the bitmask for elements 1..32?
225 me->bits0 = (me->bits0 | ((QPSetBits)1U << (n - 1U)));
226 }
227 else { // set the bit in the bitmask for for elements 33..64
228 me->bits1 = (me->bits1 | ((QPSetBits)1U << (n - 33U)));
229 }
230#endif
231}
232//............................................................................
233//! @public @memberof QPSet
234void QPSet_remove(QPSet * const me, uint_fast8_t const n) {
235#if (QF_MAX_ACTIVE <= 32U)
236 // clear the bit only in bitmask for elements 1..32
237 me->bits0 = (me->bits0 & (QPSetBits)(~((QPSetBits)1U << (n - 1U))));
238#else
239 if (n <= 32U) { // clear the bit in the bitmask for elements 1..32?
240 (me->bits0 = (me->bits0 & ~((QPSetBits)1U << (n - 1U))));
241 }
242 else { // clear the bit in the bitmask for for elements 33..64
243 (me->bits1 = (me->bits1 & ~((QPSetBits)1U << (n - 33U))));
244 }
245#endif
246}
247//............................................................................
248//! @public @memberof QPSet
249uint_fast8_t QPSet_findMax(QPSet const * const me) {
250#if (QF_MAX_ACTIVE <= 32U)
251 // check only the bitmask for elements 1..32
252 return QF_LOG2(me->bits0);
253#else
254 return (me->bits1 != 0U) // bitmask for elements 32..64 not empty?
255 ? (32U + QF_LOG2(me->bits1)) // 32 + log2(bits 33..64)
256 : (QF_LOG2(me->bits0)); // log2(bits 1..32)
257#endif
258}
#define Q_STATE_CAST(handler_)
Perform cast to QStateHandler.
Definition qp.h:172
uint32_t QPSetBits
Bitmask for the internal representation of QPSet elements.
Definition qp.h:398
QState(* QStateHandler)(void *const me, QEvt const *const e)
Pointer to a state-handler function.
Definition qp.h:142
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64).
Definition qp_config.h:100
QP/C Framework in C internal (package-scope) interface.
Sample QP/C port.
#define QF_LOG2(bitmask_)
Port-specific integer log-base-2 of a 32-bit bitmask.
Definition qp_port.h:140
QS (QP/Spy software tracing) internal (package-scope) interface.
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:40
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section).
Definition qsafe.h:54
#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
Active object class (based on the QHsm implementation strategy).
Definition qp.h:447
QAsm super
Definition qp.h:448
void QActive_unregister_(QActive *const me)
Un-register the active object from the framework.
Definition qf_qact.c:121
void QActive_ctor(QActive *const me, QStateHandler const initial)
QActive constructor (abstract base class).
Definition qf_qact.c:50
void QActive_register_(QActive *const me)
Register this active object to be managed by the framework.
Definition qf_qact.c:72
QActive * QActive_registry_[QF_MAX_ACTIVE+1U]
Static (one per-class) array of registered active objects.
Definition qp_pkg.h:38
uint8_t prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.h:449
uint8_t pthre
Preemption-threshold [1..QF_MAX_ACTIVE] of this AO.
Definition qp.h:450
union QAsmAttr state
Current state (pointer to the current state-handler function).
Definition qp.h:180
Virtual table for the QAsm class.
Definition qp.h:208
Private attributes of the QF framework.
Definition qp_pkg.h:58
Hierarchical State Machine class (QHsm-style state machine implementation strategy).
Definition qp.h:239
Set of Active Objects of up to QF_MAX_ACTIVE elements.
Definition qp.h:407
void QPSet_remove(QPSet *const me, uint_fast8_t const n)
Remove element n from the priority-set (n = 1..QF_MAX_ACTIVE).
Definition qf_qact.c:234
bool QPSet_isEmpty(QPSet const *const me)
Find out whether the priority-set is empty.
Definition qf_qact.c:185
bool QPSet_notEmpty(QPSet const *const me)
Find out whether the priority-set is NOT empty.
Definition qf_qact.c:196
void QPSet_insert(QPSet *const me, uint_fast8_t const n)
Insert element n into the priority-set (n = 1..QF_MAX_ACTIVE).
Definition qf_qact.c:219
void QPSet_setEmpty(QPSet *const me)
Make the priority set empty.
Definition qf_qact.c:177
bool QPSet_hasElement(QPSet const *const me, uint_fast8_t const n)
Find out whether the priority-set has element n.
Definition qf_qact.c:207
QPSetBits bits0
Bitmask for elements 1..32.
Definition qp.h:409
QPSetBits bits1
Bitmask for elements 33..64.
Definition qp.h:412
uint_fast8_t QPSet_findMax(QPSet const *const me)
Find the maximum element in the set–returns zero if the set is empty.
Definition qf_qact.c:249
QStateHandler fun
Definition qp.h:162