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