QP/C++ 8.1.1
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_dyn.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#if (QF_MAX_EPOOL > 0U) // mutable events configured?
41
42// unnamed namespace for local definitions with internal linkage
43namespace {
44Q_DEFINE_THIS_MODULE("qf_dyn")
45} // unnamed namespace
46
47namespace QP {
48namespace QF {
49
50//............................................................................
52 void * const poolSto,
53 std::uint_fast32_t const poolSize,
54 std::uint_fast16_t const evtSize) noexcept
55{
56 std::uint_fast8_t const poolNum = priv_.maxPool_;
57
60
61 // the maximum of initialized pools so far must be in the configured range
62 Q_REQUIRE_INCRIT(100, poolNum < QF_MAX_EPOOL);
63
64 if (poolNum > 0U) { // any event pools already initialized?
65 // the last initialized event pool must have event size smaller
66 // than the one just being initialized
67 // NOTE: QF event pools must be initialized in the increasing order
68 // of their event sizes
70 QF_EPOOL_EVENT_SIZE_(priv_.ePool_[poolNum - 1U]) < evtSize);
71 }
72
73 priv_.maxPool_ = static_cast<std::uint8_t>(poolNum + 1U); // one more pool
74
76
77 // perform the port-dependent initialization of the event-pool
78 QF_EPOOL_INIT_(priv_.ePool_[poolNum], poolSto, poolSize, evtSize);
79
80#ifdef Q_SPY
81 // generate the QS object-dictionary entry for the initialized pool
82 {
83 std::array<std::uint8_t, 9> obj_name = // initial event pool name
84 { 'E', 'v', 't', 'P', 'o', 'o', 'l', '?', '\0' };
85 // replace the "?" with the one-digit pool number (1-based)
86 obj_name[7] = static_cast<std::uint8_t>(
87 static_cast<std::uint8_t>('0') + priv_.maxPool_);
88 QS::obj_dict_pre_(&priv_.ePool_[poolNum],
89 reinterpret_cast<char *>(&obj_name[0]));
90 }
91#endif // Q_SPY
92}
93
94//............................................................................
95std::uint16_t poolGetMaxBlockSize() noexcept {
98
99 std::uint8_t const maxPool = priv_.maxPool_;
100
101 // the maximum number of initialized pools must be in configured range
102 Q_REQUIRE_INCRIT(210, (0U < maxPool) && (maxPool <= QF_MAX_EPOOL));
103
104 // set event size from the port-dependent operation
105 std::uint16_t const maxSize =
106 QF_EPOOL_EVENT_SIZE_(priv_.ePool_[maxPool - 1U]);
107 QF_CRIT_EXIT();
108
109 return maxSize;
110}
111
112//............................................................................
113#ifdef QF_EPOOL_USE_
114
115std::uint16_t getPoolUse(std::uint_fast8_t const poolNum) noexcept {
118
119#ifndef Q_UNSAFE
120 std::uint8_t const maxPool = priv_.maxPool_;
121
122 // the maximum number of initialized pools must be in configured range
123 Q_REQUIRE_INCRIT(310, maxPool <= QF_MAX_EPOOL);
124
125 // the queried poolNum must be one of the initialized pools or 0
126 Q_REQUIRE_INCRIT(320, poolNum <= maxPool);
127#endif
128 std::uint16_t nUse = 0U;
129 if (poolNum > 0U) { // event pool number provided?
130 // set event pool use from the port-dependent operation
131 nUse = QF_EPOOL_USE_(&priv_.ePool_[poolNum - 1U]);
132 }
133 else { // special case of poolNum==0
134 // calculate the sum of used entries in all event pools
135 for (std::uint_fast8_t pool = priv_.maxPool_; pool > 0U; --pool) {
136 // add the event pool use from the port-dependent operation
137 nUse += QF_EPOOL_USE_(&priv_.ePool_[pool - 1U]);
138 }
139 }
140
141 QF_CRIT_EXIT();
142
143 return nUse;
144}
145#endif // QF_EPOOL_USE_
146
147//............................................................................
148#ifdef QF_EPOOL_FREE_
149
150std::uint16_t getPoolFree(std::uint_fast8_t const poolNum) noexcept {
153
154#ifndef Q_UNSAFE
155 std::uint8_t const maxPool = priv_.maxPool_;
156
157 // the maximum count of initialized pools must be in configured range
158 Q_REQUIRE_INCRIT(410, maxPool <= QF_MAX_EPOOL);
159
160 // the poolNum paramter must be in range
161 Q_REQUIRE_INCRIT(420, (0U < poolNum) && (poolNum <= maxPool));
162#endif
163 std::uint16_t const nFree = QF_EPOOL_FREE_(&priv_.ePool_[poolNum - 1U]);
164
165 QF_CRIT_EXIT();
166
167 return nFree;
168}
169#endif // QF_EPOOL_FREE_
170
171//............................................................................
172#ifdef QF_EPOOL_MIN_
173
174std::uint16_t getPoolMin(std::uint_fast8_t const poolNum) noexcept {
177
178#ifndef Q_UNSAFE
179 std::uint8_t const maxPool = priv_.maxPool_;
180
181 // the maximum count of initialized pools must be in configured range
182 Q_REQUIRE_INCRIT(510, maxPool <= QF_MAX_EPOOL);
183
184 // the poolNum paramter must be in range
185 Q_REQUIRE_INCRIT(520, (0U < poolNum) && (poolNum <= maxPool));
186#endif
187 // call port-specific operation for the minimum of free blocks so far
188 std::uint16_t const nMin = QF_EPOOL_MIN_(&priv_.ePool_[poolNum - 1U]);
189
190 QF_CRIT_EXIT();
191
192 return nMin;
193}
194#endif // QF_EPOOL_MIN_
195
196//............................................................................
198 std::uint_fast16_t const evtSize,
199 std::uint_fast16_t const margin,
200 QSignal const sig) noexcept
201{
204
205 std::uint8_t const maxPool = priv_.maxPool_;
206
207 // the maximum count of initialized pools must be in configured range
208 Q_REQUIRE_INCRIT(610, maxPool <= QF_MAX_EPOOL);
209
210 // find the pool that fits the requested event size...
211 std::uint8_t poolNum = 0U; // zero-based poolNum initially
212 for (; poolNum < maxPool; ++poolNum) {
213 // call port-specific operation for the event-size in a given pool
214 if (evtSize <= QF_EPOOL_EVENT_SIZE_(priv_.ePool_[poolNum])) {
215 break; // event pool found
216 }
217 }
218
219 // event pool must be found, which means that the reqeusted event size
220 // fits in one of the initialized pools
221 Q_ASSERT_INCRIT(620, poolNum < maxPool);
222
223 ++poolNum; // convert to 1-based poolNum
224
225 QF_CRIT_EXIT();
226
227 // get event e (port-dependent)...
228 QEvt *e;
229#ifdef Q_SPY
230 QF_EPOOL_GET_(priv_.ePool_[poolNum - 1U], e,
231 ((margin != NO_MARGIN) ? margin : 0U),
232 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum);
233#else
234 QF_EPOOL_GET_(priv_.ePool_[poolNum - 1U], e,
235 ((margin != NO_MARGIN) ? margin : 0U), 0U);
236#endif
237
238 if (e != nullptr) { // was e allocated correctly?
239 e->sig = static_cast<QSignal>(sig); // set the signal
240 e->poolNum_ = poolNum;
241 e->refCtr_ = 0U; // reference count starts at 0
242
245 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum)
246 QS_TIME_PRE(); // timestamp
247 QS_EVS_PRE(evtSize); // the size of the event
248 QS_SIG_PRE(sig); // the signal of the event
249 QS_END_PRE()
250 QS_CRIT_EXIT();
251 }
252 else { // event was not allocated
253
255 // This assertion means that the event allocation failed,
256 // and this failure cannot be tolerated. The most frequent
257 // reason is an event leak in the application.
258 Q_ASSERT_INCRIT(630, margin != NO_MARGIN);
259
261 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum)
262 QS_TIME_PRE(); // timestamp
263 QS_EVS_PRE(evtSize); // the size of the event
264 QS_SIG_PRE(sig); // the signal of the event
265 QS_END_PRE()
266
267 QF_CRIT_EXIT();
268 }
269
270 // if the caller can't tolerate failed allocation (margin != QF_NO_MARGIN),
271 // the returned event e is guaranteed to be valid (not NULL).
272 return e;
273}
274
275//............................................................................
276void gc(QEvt const * const e) noexcept {
279
280 // the collected event must be valid
281 Q_REQUIRE_INCRIT(700, e != nullptr);
282
283 std::uint8_t const poolNum = static_cast<std::uint8_t>(e->poolNum_);
284 if (poolNum != 0U) { // is it a pool event (mutable)?
285
286 if (e->refCtr_ > 1U) { // isn't this the last reference?
287
289 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum)
290 QS_TIME_PRE(); // timestamp
291 QS_SIG_PRE(e->sig); // the signal of the event
292 QS_2U8_PRE(poolNum, e->refCtr_);
293 QS_END_PRE()
294
295 QEvt_refCtr_dec_(e); // decrement the ref counter
296
297 QF_CRIT_EXIT();
298 }
299 else { // this is the last reference to this event, recycle it
300#ifndef Q_UNSAFE
301 std::uint8_t const maxPool = priv_.maxPool_;
302
303 // the maximum count of initialized pools must be in configured range
304 Q_ASSERT_INCRIT(740, maxPool <= QF_MAX_EPOOL);
305
306 // the event poolNum must be one one the initialized event pools
307 Q_ASSERT_INCRIT(750, poolNum <= maxPool);
308#endif
310 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum)
311 QS_TIME_PRE(); // timestamp
312 QS_SIG_PRE(e->sig); // the signal of the event
313 QS_2U8_PRE(poolNum, e->refCtr_);
314 QS_END_PRE()
315
316 QF_CRIT_EXIT();
317
318 // call port-specific operation to put the event to a given pool
319 // NOTE: casting 'const' away is legit because 'e' is a pool event
320#ifdef Q_SPY
321 QF_EPOOL_PUT_(priv_.ePool_[poolNum - 1U],
322 const_cast<QEvt*>(e),
323 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum);
324#else
325 QF_EPOOL_PUT_(priv_.ePool_[poolNum - 1U],
326 const_cast<QEvt*>(e), 0U);
327#endif
328 }
329 }
330 else {
331 QF_CRIT_EXIT();
332 }
333}
334
335//............................................................................
336QEvt const * newRef_(
337 QEvt const * const e,
338 QEvt const * const evtRef) noexcept
339{
340#ifdef Q_UNSAFE
341 Q_UNUSED_PAR(evtRef);
342#endif
343
346
347 // the referenced event must be valid
348 Q_REQUIRE_INCRIT(800, e != nullptr);
349
350 // the event reference count must not exceed the number of AOs
351 // in the system plus each AO possibly holding one event reference
352 Q_REQUIRE_INCRIT(820, e->refCtr_ < (2U * QF_MAX_ACTIVE));
353
354 // the event ref must be valid
355 Q_REQUIRE_INCRIT(830, evtRef == nullptr);
356
357 std::uint_fast8_t const poolNum = e->poolNum_;
358
359 // the referenced event must be a pool event (not an immutable event)
360 Q_ASSERT_INCRIT(840, poolNum != 0U);
361
362 QEvt_refCtr_inc_(e); // increments the ref counter
363
365 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum)
366 QS_TIME_PRE(); // timestamp
367 QS_SIG_PRE(e->sig); // the signal of the event
368 QS_2U8_PRE(poolNum, e->refCtr_);
369 QS_END_PRE()
370
371 QF_CRIT_EXIT();
372 Q_UNUSED_PAR(poolNum); // might be unused
373
374 return e;
375}
376
377//............................................................................
378void deleteRef_(QEvt const * const evtRef) noexcept {
381
382 QEvt const * const e = evtRef;
383
384 // the referenced event must be valid
385 Q_REQUIRE_INCRIT(900, e != nullptr);
386
387#ifdef Q_SPY
388 std::uint8_t const poolNum = e->poolNum_;
389
391 static_cast<std::uint_fast8_t>(QS_ID_EP) + poolNum)
392 QS_TIME_PRE(); // timestamp
393 QS_SIG_PRE(e->sig); // the signal of the event
394 QS_2U8_PRE(poolNum, e->refCtr_);
395 QS_END_PRE()
396#endif // def Q_SPY
397
398 QF_CRIT_EXIT();
399
400#if (QF_MAX_EPOOL > 0U)
401 gc(e); // recycle the referenced event
402#endif
403}
404
405} // namespace QF
406} // namespace QP
407
408#endif // (QF_MAX_EPOOL > 0U) mutable events configured
Event class.
Definition qp.hpp:101
std::uint32_t poolNum_
Event pool number of this event.
Definition qp.hpp:104
std::uint32_t refCtr_
Event reference counter.
Definition qp.hpp:105
std::uint32_t sig
Signal of the event (see Event Signal).
Definition qp.hpp:103
std::array< QF_EPOOL_TYPE_, QF_MAX_EPOOL > ePool_
Array of event pools sized for the maximum allowed number of pools.
Definition qp_pkg.hpp:83
std::uint8_t maxPool_
Number of event pools managed by the QF Framework.
Definition qp_pkg.hpp:84
QF Active Object Framework namespace.
Definition qp.hpp:476
void deleteRef_(QEvt const *const evtRef) noexcept
Definition qf_dyn.cpp:378
std::uint16_t poolGetMaxBlockSize() noexcept
Obtain the block size of any registered event pools.
Definition qf_dyn.cpp:95
QEvt const * newRef_(QEvt const *const e, QEvt const *const evtRef) noexcept
Definition qf_dyn.cpp:336
void gc(QEvt const *const e) noexcept
Recycle a mutable (mutable) event.
Definition qf_dyn.cpp:276
QEvt * newX_(std::uint_fast16_t const evtSize, std::uint_fast16_t const margin, QSignal const sig) noexcept
Definition qf_dyn.cpp:197
QF::Attr priv_
Definition qf_qact.cpp:51
void poolInit(void *const poolSto, std::uint_fast32_t const poolSize, std::uint_fast16_t const evtSize) noexcept
Event pool initialization for dynamic allocation of events.
Definition qf_dyn.cpp:51
std::uint16_t getPoolUse(std::uint_fast8_t const poolNum) noexcept
constexpr std::uint_fast16_t NO_MARGIN
Special value of margin that causes asserting failure in case event allocation or event posting fails...
Definition qp.hpp:484
std::uint16_t getPoolMin(std::uint_fast8_t const poolNum) noexcept
Obtain the minimum of free entries of the given event pool.
std::uint16_t getPoolFree(std::uint_fast8_t const poolNum) noexcept
QP/C++ Framework namespace.
Definition qequeue.hpp:36
constexpr std::int_fast16_t QS_ID_EP
Definition qs.hpp:205
@ QS_QF_NEW
new event was created
Definition qs.hpp:94
@ QS_QF_GC
garbage collection
Definition qs.hpp:96
@ QS_QF_DELETE_REF
an event reference is about to be deleted
Definition qs.hpp:108
@ QS_QF_NEW_ATTEMPT
an attempt to allocate an event failed
Definition qs.hpp:85
@ QS_QF_GC_ATTEMPT
garbage collection attempt
Definition qs.hpp:95
@ QS_QF_NEW_REF
new event reference was created
Definition qs.hpp:93
void QEvt_refCtr_inc_(QEvt const *const me) noexcept
Internal function to increment the refCtr of a const event.
Definition qf_act.cpp:57
void QEvt_refCtr_dec_(QEvt const *const me) noexcept
Internal function to decrement the refCtr of a const event.
Definition qf_act.cpp:68
std::uint16_t QSignal
The signal of event QP::QEvt.
Definition qp.hpp:98
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:89
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64).
Definition qp_config.hpp:98
#define QF_MAX_EPOOL
Maximum # event pools in the system (0..15).
QP Framework in C++ internal (package-scope) interface
Sample QP/C++ port.
#define QF_EPOOL_FREE_(ePool_)
Definition qp_port.hpp:195
#define QF_EPOOL_MIN_(ePool_)
Definition qp_port.hpp:196
#define QF_EPOOL_EVENT_SIZE_(p_)
Definition qp_port.hpp:190
#define QF_EPOOL_PUT_(p_, e_, qsId_)
Definition qp_port.hpp:193
#define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_)
Definition qp_port.hpp:188
#define QF_EPOOL_USE_(ePool_)
Definition qp_port.hpp:194
#define QF_EPOOL_GET_(p_, e_, m_, qsId_)
Definition qp_port.hpp:191
#define QS_TIME_PRE()
Definition qs.hpp:362
#define QS_CRIT_EXIT()
Internal macro for exiting a critical section.
Definition qs.hpp:438
#define QS_CRIT_ENTRY()
Internal macro for entering a critical section.
Definition qs.hpp:434
QS (QP/Spy software tracing) internal (package-scope) interface.
#define QS_SIG_PRE(sig_)
Output pre-formatted event signal data element.
Definition qs_pkg.hpp:90
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.hpp:81
#define QS_EVS_PRE(size_)
Output pre-formatted event queue size data element.
Definition qs_pkg.hpp:123
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.hpp:77
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.hpp:71
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