QP/C  8.0.3
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
46void QF_poolInit(
47 void * const poolSto,
48 uint_fast32_t const poolSize,
49 uint_fast16_t const evtSize)
50{
51 uint_fast8_t const poolNum = QF_priv_.maxPool_;
52
53 // see precondition{qf_dyn,200} and precondition{qf_dyn,201}
56
57 Q_REQUIRE_INCRIT(100, poolNum < QF_MAX_EPOOL);
58 if (poolNum > 0U) {
60 QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[poolNum - 1U]) < evtSize);
61 }
62 QF_priv_.maxPool_ = poolNum + 1U; // one more pool
63
65
66 // perform the port-dependent initialization of the event-pool
67 QF_EPOOL_INIT_(QF_priv_.ePool_[poolNum], poolSto, poolSize, evtSize);
68
69#ifdef Q_SPY
70 // generate the object-dictionary entry for the initialized pool
71 {
72 uint8_t obj_name[9] = "EvtPool?";
73 obj_name[7] = (uint8_t)((uint8_t)'0' + poolNum + 1U);
74 QS_obj_dict_pre_(&QF_priv_.ePool_[poolNum], (char const *)obj_name);
75 }
76#endif // Q_SPY
77}
78
79//............................................................................
80//! @static @public @memberof QF
81uint_fast16_t QF_poolGetMaxBlockSize(void) {
84 uint_fast16_t const max_size =
85 QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[QF_priv_.maxPool_ - 1U]);
87
88 return max_size;
89}
90
91//............................................................................
92//! @static @public @memberof QF
93uint_fast16_t QF_getPoolMin(uint_fast8_t const poolNum) {
96
97 Q_REQUIRE_INCRIT(300, (poolNum <= QF_MAX_EPOOL)
98 && (0U < poolNum) && (poolNum <= QF_priv_.maxPool_));
99
100 uint_fast16_t const min = (uint_fast16_t)QF_priv_.ePool_[poolNum - 1U].nMin;
101
102 QF_CRIT_EXIT();
103
104 return min;
105}
106
107//............................................................................
108//! @static @private @memberof QF
110 uint_fast16_t const evtSize,
111 uint_fast16_t const margin,
112 enum_t const sig)
113{
114 // find the pool id that fits the requested event size...
115 uint8_t poolNum = 0U; // zero-based poolNum initially
116 for (; poolNum < QF_priv_.maxPool_; ++poolNum) {
117 if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[poolNum])) {
118 break;
119 }
120 }
121
124
125 // precondition:
126 // - cannot run out of registered pools
127 Q_REQUIRE_INCRIT(400, poolNum < QF_priv_.maxPool_);
128
129 ++poolNum; // convert to 1-based poolNum
130
131 QF_CRIT_EXIT();
132
133 // get event e (port-dependent)...
134 QEvt *e;
135#ifdef Q_SPY
136 QF_EPOOL_GET_(QF_priv_.ePool_[poolNum - 1U], e,
137 ((margin != QF_NO_MARGIN) ? margin : 0U),
138 (uint_fast8_t)QS_EP_ID + poolNum);
139#else
140 QF_EPOOL_GET_(QF_priv_.ePool_[poolNum - 1U], e,
141 ((margin != QF_NO_MARGIN) ? margin : 0U), 0U);
142#endif
143
144 if (e != (QEvt *)0) { // was e allocated correctly?
145 e->sig = (QSignal)sig; // set the signal
146 e->poolNum_ = poolNum;
147 e->refCtr_ = 0U;
148
150 QS_BEGIN_PRE(QS_QF_NEW, (uint_fast8_t)QS_EP_ID + poolNum)
151 QS_TIME_PRE(); // timestamp
152 QS_EVS_PRE(evtSize); // the size of the event
153 QS_SIG_PRE(sig); // the signal of the event
154 QS_END_PRE()
155 QS_CRIT_EXIT();
156 }
157 else { // event was not allocated
158
160 // This assertion means that the event allocation failed,
161 // and this failure cannot be tolerated. The most frequent
162 // reason is an event leak in the application.
163 Q_ASSERT_INCRIT(420, margin != QF_NO_MARGIN);
164
165 QS_BEGIN_PRE(QS_QF_NEW_ATTEMPT,
166 (uint_fast8_t)QS_EP_ID + poolNum)
167 QS_TIME_PRE(); // timestamp
168 QS_EVS_PRE(evtSize); // the size of the event
169 QS_SIG_PRE(sig); // the signal of the event
170 QS_END_PRE()
171
172 QF_CRIT_EXIT();
173 }
174
175 // the returned event e is guaranteed to be valid (not NULL)
176 // if we can't tolerate failed allocation
177 return e;
178}
179
180//............................................................................
181//! @static @public @memberof QF
182void QF_gc(QEvt const * const e) {
185
186 Q_REQUIRE_INCRIT(500, e != (QEvt *)0);
187
188 uint8_t const poolNum = e->poolNum_;
189
190 if (poolNum != 0U) { // is it a pool event (mutable)?
191
192 if (e->refCtr_ > 1U) { // isn't this the last reference?
193
194 QS_BEGIN_PRE(QS_QF_GC_ATTEMPT,
195 (uint_fast8_t)QS_EP_ID + poolNum)
196 QS_TIME_PRE(); // timestamp
197 QS_SIG_PRE(e->sig); // the signal of the event
198 QS_2U8_PRE(poolNum, e->refCtr_);
199 QS_END_PRE()
200
201 Q_ASSERT_INCRIT(505, e->refCtr_ > 0U);
202 QEvt_refCtr_dec_(e); // decrement the ref counter
203
204 QF_CRIT_EXIT();
205 }
206 else { // this is the last reference to this event, recycle it
207
208 QS_BEGIN_PRE(QS_QF_GC,
209 (uint_fast8_t)QS_EP_ID + poolNum)
210 QS_TIME_PRE(); // timestamp
211 QS_SIG_PRE(e->sig); // the signal of the event
212 QS_2U8_PRE(poolNum, e->refCtr_);
213 QS_END_PRE()
214
215 // pool number must be in range
216 Q_ASSERT_INCRIT(510, (poolNum <= QF_priv_.maxPool_)
217 && (poolNum <= QF_MAX_EPOOL));
218 QF_CRIT_EXIT();
219
220 // NOTE: casting 'const' away is legit because 'e' is a pool event
221#ifdef Q_SPY
222 QF_EPOOL_PUT_(QF_priv_.ePool_[poolNum - 1U], (QEvt *)e,
223 (uint_fast8_t)QS_EP_ID + poolNum);
224#else
225 QF_EPOOL_PUT_(QF_priv_.ePool_[poolNum - 1U], (QEvt *)e,
226 0U);
227#endif
228 }
229 }
230 else {
231 QF_CRIT_EXIT();
232 }
233}
234
235//............................................................................
236//! @static @private @memberof QF
238 QEvt const * const e,
239 void const * const evtRef)
240{
241#ifdef Q_UNSAFE
242 Q_UNUSED_PAR(evtRef);
243#endif
244
247
248 Q_REQUIRE_INCRIT(600, e != (QEvt *)0);
249
250 uint_fast8_t const poolNum = e->poolNum_;
251 Q_UNUSED_PAR(poolNum); // might be unused
252
253 Q_REQUIRE_INCRIT(610, (poolNum != 0U)
254 && (evtRef == (void *)0));
255
256 Q_ASSERT_INCRIT(605, e->refCtr_ < (2U * QF_MAX_ACTIVE));
257 QEvt_refCtr_inc_(e); // increments the ref counter
258
259 QS_BEGIN_PRE(QS_QF_NEW_REF,
260 (uint_fast8_t)QS_EP_ID + poolNum)
261 QS_TIME_PRE(); // timestamp
262 QS_SIG_PRE(e->sig); // the signal of the event
263 QS_2U8_PRE(poolNum, e->refCtr_);
264 QS_END_PRE()
265
266 QF_CRIT_EXIT();
267
268 return e;
269}
270
271//............................................................................
272//! @static @private @memberof QF
273void QF_deleteRef_(void const * const evtRef) {
276
277 QEvt const * const e = (QEvt const *)evtRef;
278 Q_REQUIRE_INCRIT(700, e != (QEvt *)0);
279
280#ifdef Q_SPY
281 uint_fast8_t const poolNum = e->poolNum_;
282 QS_BEGIN_PRE(QS_QF_DELETE_REF,
283 (uint_fast8_t)QS_EP_ID + poolNum)
284 QS_TIME_PRE(); // timestamp
285 QS_SIG_PRE(e->sig); // the signal of the event
286 QS_2U8_PRE(poolNum, e->refCtr_);
287 QS_END_PRE()
288#endif // def Q_SPY
289
290 QF_CRIT_EXIT();
291
292#if (QF_MAX_EPOOL > 0U)
293 QF_gc(e); // recycle the referenced event
294#endif
295}
296
297#endif // (QF_MAX_EPOOL > 0U) mutable events configured
QF_Attr QF_priv_
Definition qp_pkg.h:46
void QF_gc(QEvt const *const e)
Recycle a mutable (mutable) event.
Definition qf_dyn.c:182
uint_fast16_t QF_poolGetMaxBlockSize(void)
Obtain the block size of any registered event pools.
Definition qf_dyn.c:81
uint_fast16_t QF_getPoolMin(uint_fast8_t const poolNum)
Obtain the minimum of free entries of the given event pool.
Definition qf_dyn.c:93
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:109
void QF_deleteRef_(void const *const evtRef)
Internal QF implementation of deleting event reference.
Definition qf_dyn.c:273
QEvt const * QF_newRef_(QEvt const *const e, void const *const evtRef)
Internal QF implementation of creating new event reference.
Definition qf_dyn.c:237
QF_Attr QF_priv_
Definition qf_act.c:45
#define QF_EPOOL_EVENT_SIZE_(p_)
Definition qk.h:111
#define QF_EPOOL_PUT_(p_, e_, qsId_)
Definition qk.h:114
#define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_)
Definition qk.h:109
#define QF_EPOOL_GET_(p_, e_, m_, qsId_)
Definition qk.h:112
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:94
#define QF_NO_MARGIN
Special value of margin that causes asserting failure in case event allocation or event posting fails...
Definition qp.h:745
int enum_t
Definition qp.h:92
uint16_t QSignal
The signal of event QEvt.
Definition qp.h:105
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
Definition qp_config.h:123
#define QF_MAX_EPOOL
Maximum # event pools in the system (0..15)
Definition qp_config.h:133
Internal (package scope) QP/C interface.
Sample QP/C port.
QS/C dummy public interface.
#define QS_SIG_PRE(sig_)
Definition qs_dummy.h:147
#define QS_TIME_PRE()
Definition qs_dummy.h:146
#define QS_2U8_PRE(data1_, data2_)
Definition qs_dummy.h:143
#define QS_EVS_PRE(size_)
Definition qs_dummy.h:148
#define QS_CRIT_EXIT()
Definition qs_dummy.h:158
#define QS_END_PRE()
Definition qs_dummy.h:141
#define QS_CRIT_ENTRY()
Definition qs_dummy.h:157
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.h:140
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:39
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section)
Definition qsafe.h:49
#define QF_CRIT_EXIT()
Definition qsafe.h:43
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section)
Definition qsafe.h:86
#define QF_CRIT_STAT
Definition qsafe.h:35
Event class.
Definition qp.h:112
QSignal sig
Signal of the event (see Event Signal)
Definition qp.h:113
uint8_t volatile refCtr_
Event reference counter.
Definition qp.h:115
uint8_t poolNum_
Event pool number of this event.
Definition qp.h:114