QP/C  7.0.0
Real-Time Embedded Framework
qf_actq.c
Go to the documentation of this file.
1/*============================================================================
2* QP/C Real-Time Embedded Framework (RTEF)
3* Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
4*
5* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
6*
7* This software is dual-licensed under the terms of the open source GNU
8* General Public License version 3 (or any later version), or alternatively,
9* under the terms of one of the closed source Quantum Leaps commercial
10* licenses.
11*
12* The terms of the open source GNU General Public License version 3
13* can be found at: <www.gnu.org/licenses/gpl-3.0>
14*
15* The terms of the closed source Quantum Leaps commercial licenses
16* can be found at: <www.state-machine.com/licensing>
17*
18* Redistributions in source code must retain this top-level comment block.
19* Plagiarizing this software to sidestep the license obligations is illegal.
20*
21* Contact information:
22* <www.state-machine.com>
23* <info@state-machine.com>
24============================================================================*/
36#define QP_IMPL /* this is QP implementation */
37#include "qf_port.h" /* QF port */
38#include "qf_pkg.h" /* QF package-scope interface */
39#include "qassert.h" /* QP embedded systems-friendly assertions */
40#ifdef Q_SPY /* QS software tracing enabled? */
41 #include "qs_port.h" /* QS port */
42 #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
43#else
44 #include "qs_dummy.h" /* disable the QS software tracing */
45#endif /* Q_SPY */
46
47Q_DEFINE_THIS_MODULE("qf_actq")
48
49/*==========================================================================*/
50#ifdef Q_SPY
83bool QActive_post_(QActive * const me, QEvt const * const e,
84 uint_fast16_t const margin, void const * const sender)
85#else
86bool QActive_post_(QActive * const me, QEvt const * const e,
87 uint_fast16_t const margin)
88#endif
89{
91 Q_REQUIRE_ID(100, e != (QEvt *)0);
92
94 QF_CRIT_E_();
95 QEQueueCtr nFree = me->eQueue.nFree; /* get volatile into the temporary */
96
97 /* test-probe#1 for faking queue overflow */
100 nFree = 0U;
101 )
102
103 bool status;
104 if (margin == QF_NO_MARGIN) {
105 if (nFree > 0U) {
106 status = true; /* can post */
107 }
108 else {
109 status = false; /* cannot post */
110 Q_ERROR_CRIT_(110); /* must be able to post the event */
111 }
112 }
113 else if (nFree > (QEQueueCtr)margin) {
114 status = true; /* can post */
115 }
116 else {
117 status = false; /* cannot post, but don't assert */
118 }
119
120 /* is it a dynamic event? */
121 if (e->poolId_ != 0U) {
122 QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
123 }
124
125 if (status) { /* can post the event? */
126
127 --nFree; /* one free entry just used up */
128 me->eQueue.nFree = nFree; /* update the volatile */
129 if (me->eQueue.nMin > nFree) {
130 me->eQueue.nMin = nFree; /* increase minimum so far */
131 }
132
134 QS_TIME_PRE_(); /* timestamp */
135 QS_OBJ_PRE_(sender); /* the sender object */
136 QS_SIG_PRE_(e->sig); /* the signal of the event */
137 QS_OBJ_PRE_(me); /* this active object (recipient) */
138 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
139 QS_EQC_PRE_(nFree); /* number of free entries */
140 QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
142
143#ifdef Q_UTEST
144 /* callback to examine the posted event under the same conditions
145 * as producing the #QS_QF_ACTIVE_POST trace record, which are:
146 * the local filter for this AO ('me->prio') is set
147 */
148 if (QS_LOC_CHECK_(me->prio)) {
149 /* callback to examine the posted event */
150 QS_onTestPost(sender, me, e, status);
151 }
152#endif
153
154 /* empty queue? */
155 if (me->eQueue.frontEvt == (QEvt *)0) {
156 me->eQueue.frontEvt = e; /* deliver event directly */
157 QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
158 }
159 /* queue is not empty, insert event into the ring-buffer */
160 else {
161 /* insert event into the ring buffer (FIFO) */
162 QF_PTR_AT_(me->eQueue.ring, me->eQueue.head) = e;
163
164 if (me->eQueue.head == 0U) { /* need to wrap head? */
165 me->eQueue.head = me->eQueue.end; /* wrap around */
166 }
167 --me->eQueue.head; /* advance the head (counter clockwise) */
168 }
169
170 QF_CRIT_X_();
171 }
172 else { /* cannot post the event */
173
175 QS_TIME_PRE_(); /* timestamp */
176 QS_OBJ_PRE_(sender); /* the sender object */
177 QS_SIG_PRE_(e->sig); /* the signal of the event */
178 QS_OBJ_PRE_(me); /* this active object (recipient) */
179 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
180 QS_EQC_PRE_(nFree); /* number of free entries */
181 QS_EQC_PRE_(margin); /* margin requested */
183
184#ifdef Q_UTEST
185 /* callback to examine the posted event under the same conditions
186 * as producing the #QS_QF_ACTIVE_POST trace record, which are:
187 * the local filter for this AO ('me->prio') is set
188 */
189 if (QS_LOC_CHECK_(me->prio)) {
190 QS_onTestPost(sender, me, e, status);
191 }
192#endif
193
194 QF_CRIT_X_();
195
196 QF_gc(e); /* recycle the event to avoid a leak */
197 }
198
199 return status;
200}
201
202/*==========================================================================*/
221void QActive_postLIFO_(QActive * const me, QEvt const * const e) {
222
224 QF_CRIT_E_();
225 QEQueueCtr nFree = me->eQueue.nFree; /* get volatile into the temporary */
226
227 /* test-probe#1 for faking queue overflow */
230 nFree = 0U;
231 )
232
233 /* the queue must be able to accept the event (cannot overflow) */
234 Q_ASSERT_CRIT_(210, nFree != 0U);
235
236 /* is it a dynamic event? */
237 if (e->poolId_ != 0U) {
238 QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
239 }
240
241 --nFree; /* one free entry just used up */
242 me->eQueue.nFree = nFree; /* update the volatile */
243 if (me->eQueue.nMin > nFree) {
244 me->eQueue.nMin = nFree; /* update minimum so far */
245 }
246
248 QS_TIME_PRE_(); /* timestamp */
249 QS_SIG_PRE_(e->sig); /* the signal of this event */
250 QS_OBJ_PRE_(me); /* this active object */
251 QS_2U8_PRE_(e->poolId_, e->refCtr_);/* pool Id & ref Count */
252 QS_EQC_PRE_(nFree); /* # free entries */
253 QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
255
256#ifdef Q_UTEST
257 /* callback to examine the posted event under the same conditions
258 * as producing the #QS_QF_ACTIVE_POST trace record, which are:
259 * the local filter for this AO ('me->prio') is set
260 */
261 if (QS_LOC_CHECK_(me->prio)) {
262 QS_onTestPost((QActive *)0, me, e, true);
263 }
264#endif
265
266 /* temporary to avoid UB for volatile access */
267 QEvt const * const frontEvt = me->eQueue.frontEvt;
268 me->eQueue.frontEvt = e; /* deliver the event directly to the front */
269
270 /* was the queue empty? */
271 if (frontEvt == (QEvt *)0) {
272 QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
273 }
274 /* queue was not empty, leave the event in the ring-buffer */
275 else {
276 ++me->eQueue.tail;
277 /* need to wrap the tail? */
278 if (me->eQueue.tail == me->eQueue.end) {
279 me->eQueue.tail = 0U; /* wrap around */
280 }
281
282 QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail) = frontEvt;
283 }
284 QF_CRIT_X_();
285}
286
287/*==========================================================================*/
310QEvt const *QActive_get_(QActive * const me) {
311
313 QF_CRIT_E_();
314 QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly */
315
316 /* always remove event from the front */
317 QEvt const * const e = me->eQueue.frontEvt;
318 QEQueueCtr const nFree = me->eQueue.nFree + 1U; /* volatile into tmp */
319 me->eQueue.nFree = nFree; /* update the number of free */
320
321 /* any events in the ring buffer? */
322 if (nFree <= me->eQueue.end) {
323
324 /* remove event from the tail */
325 me->eQueue.frontEvt = QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail);
326 if (me->eQueue.tail == 0U) { /* need to wrap the tail? */
327 me->eQueue.tail = me->eQueue.end; /* wrap around */
328 }
329 --me->eQueue.tail;
330
332 QS_TIME_PRE_(); /* timestamp */
333 QS_SIG_PRE_(e->sig); /* the signal of this event */
334 QS_OBJ_PRE_(me); /* this active object */
335 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
336 QS_EQC_PRE_(nFree); /* # free entries */
338 }
339 else {
340 me->eQueue.frontEvt = (QEvt *)0; /* queue becomes empty */
341
342 /* all entries in the queue must be free (+1 for fronEvt) */
343 Q_ASSERT_CRIT_(310, nFree == (me->eQueue.end + 1U));
344
346 QS_TIME_PRE_(); /* timestamp */
347 QS_SIG_PRE_(e->sig); /* the signal of this event */
348 QS_OBJ_PRE_(me); /* this active object */
349 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
351 }
352 QF_CRIT_X_();
353 return e;
354}
355
356/*==========================================================================*/
376uint_fast16_t QF_getQueueMin(uint_fast8_t const prio) {
377
378 Q_REQUIRE_ID(400, (prio <= QF_MAX_ACTIVE)
379 && (QF_active_[prio] != (QActive *)0));
380
382 QF_CRIT_E_();
383 uint_fast16_t const min = (uint_fast16_t)QF_active_[prio]->eQueue.nMin;
384 QF_CRIT_X_();
385
386 return min;
387}
388
389/*==========================================================================*/
390#ifdef Q_SPY
391 static void QTicker_init_(QHsm * const me, void const *par,
392 uint_fast8_t const qs_id);
393 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e,
394 uint_fast8_t const qs_id);
396 static bool QTicker_post_(QActive * const me, QEvt const * const e,
397 uint_fast16_t const margin, void const * const sender);
398#else
399 static void QTicker_init_(QHsm * const me, void const *par);
400 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e);
401 static bool QTicker_post_(QActive * const me, QEvt const * const e,
402 uint_fast16_t const margin);
403#endif
404
405static void QTicker_postLIFO_(QActive * const me, QEvt const * const e);
406
415#define QTICKER_CAST_(me_) ((QActive *)(me_))
416
417/*..........................................................................*/
419void QTicker_ctor(QTicker * const me, uint_fast8_t tickRate) {
420 static QActiveVtable const vtable = { /* QActive virtual table */
421 { &QTicker_init_,
423#ifdef Q_SPY
425#endif
426 },
430 };
431 QActive_ctor(&me->super, Q_STATE_CAST(0)); /* superclass' ctor */
432 me->super.super.vptr = &vtable.super; /* hook the vptr */
433
434 /* reuse eQueue.head for tick-rate */
435 me->super.eQueue.head = (QEQueueCtr)tickRate;
436}
437/*..........................................................................*/
438#ifdef Q_SPY
440static void QTicker_init_(QHsm * const me, void const *par,
441 uint_fast8_t const qs_id)
442#else
443static void QTicker_init_(QHsm * const me, void const *par)
444#endif
445{
446 (void)me;
447 (void)par;
448#ifdef Q_SPY
449 (void)qs_id; /* unused parameter */
450#endif
451 QTICKER_CAST_(me)->eQueue.tail = 0U;
452}
453/*..........................................................................*/
454#ifdef Q_SPY
456static void QTicker_dispatch_(QHsm * const me, QEvt const * const e,
457 uint_fast8_t const qs_id)
458#else
459static void QTicker_dispatch_(QHsm * const me, QEvt const * const e)
460#endif
461{
462 QEQueueCtr nTicks; /* # ticks since the last call */
464
465 (void)e; /* unused parameter */
466#ifdef Q_SPY
467 (void)qs_id; /* unused parameter */
468#endif
469
470 QF_CRIT_E_();
471 nTicks = QTICKER_CAST_(me)->eQueue.tail; /* save the # of ticks */
472 QTICKER_CAST_(me)->eQueue.tail = 0U; /* clear the # ticks */
473 QF_CRIT_X_();
474
475 for (; nTicks > 0U; --nTicks) {
476 QF_TICK_X((uint_fast8_t)QTICKER_CAST_(me)->eQueue.head, me);
477 }
478}
479/*..........................................................................*/
480#ifndef Q_SPY
482static bool QTicker_post_(QActive * const me, QEvt const * const e,
483 uint_fast16_t const margin)
484#else
485static bool QTicker_post_(QActive * const me, QEvt const * const e,
486 uint_fast16_t const margin,
487 void const * const sender)
488#endif
489{
490 (void)e; /* unused parameter */
491 (void)margin; /* unused parameter */
492
494 QF_CRIT_E_();
495 if (me->eQueue.frontEvt == (QEvt *)0) {
496
497 static QEvt const tickEvt = { 0U, 0U, 0U };
498 me->eQueue.frontEvt = &tickEvt; /* deliver event directly */
499 --me->eQueue.nFree; /* one less free event */
500
501 QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
502 }
503
504 ++me->eQueue.tail; /* account for one more tick event */
505
507 QS_TIME_PRE_(); /* timestamp */
508 QS_OBJ_PRE_(sender); /* the sender object */
509 QS_SIG_PRE_(0U); /* the signal of the event */
510 QS_OBJ_PRE_(me); /* this active object */
511 QS_2U8_PRE_(0U, 0U); /* pool Id & refCtr of the evt */
512 QS_EQC_PRE_(0U); /* number of free entries */
513 QS_EQC_PRE_(0U); /* min number of free entries */
515
516 QF_CRIT_X_();
517
518 return true; /* the event is always posted correctly */
519}
520/*..........................................................................*/
522static void QTicker_postLIFO_(QActive * const me, QEvt const * const e) {
523 (void)me; /* unused parameter */
524 (void)e; /* unused parameter */
525 Q_ERROR_ID(900);
526}
#define QACTIVE_EQUEUE_SIGNAL_(me_)
Definition: macros.h:75
#define QACTIVE_EQUEUE_WAIT_(me_)
Definition: macros.h:71
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:102
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:252
#define Q_ERROR_ID(id_)
Definition: qassert.h:187
#define Q_STATE_CAST(handler_)
Definition: qep.h:196
uint8_t QEQueueCtr
Definition: qequeue.h:63
#define QF_TICK_X(tickRate_, sender_)
Definition: qf.h:675
#define QF_NO_MARGIN
Definition: qf.h:687
#define QTICKER_CAST_(me_)
Definition: qf_actq.c:415
static bool QTicker_post_(QActive *const me, QEvt const *const e, uint_fast16_t const margin, void const *const sender)
Definition: qf_actq.c:485
Internal (package scope) QF/C interface.
#define QF_CRIT_STAT_
Definition: qf_pkg.h:54
#define QF_PTR_AT_(base_, i_)
Definition: qf_pkg.h:183
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.h:97
#define QF_CRIT_X_()
Definition: qf_pkg.h:78
#define QF_EVT_REF_CTR_INC_(e_)
Definition: qf_pkg.h:177
#define QF_CRIT_E_()
Definition: qf_pkg.h:66
#define Q_ERROR_CRIT_(id_)
Definition: qf_pkg.h:106
#define QS_TIME_PRE_()
Definition: qs.h:220
#define QS_TEST_PROBE_DEF(fun_)
Definition: qs.h:1024
#define QS_LOC_CHECK_(qs_id_)
Definition: qs.h:568
@ QS_QF_ACTIVE_POST_LIFO
Definition: qs.h:74
@ QS_QF_ACTIVE_GET
Definition: qs.h:75
@ QS_QF_ACTIVE_POST_ATTEMPT
Definition: qs.h:118
@ QS_QF_ACTIVE_POST
Definition: qs.h:73
@ QS_QF_ACTIVE_GET_LAST
Definition: qs.h:76
#define QS_TEST_PROBE_ID(id_, code_)
Definition: qs.h:1032
Internal (package scope) QS/C interface.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Definition: qs_pkg.h:138
#define QS_OBJ_PRE_(obj_)
Definition: qs_pkg.h:179
#define QS_END_NOCRIT_PRE_()
Definition: qs_pkg.h:148
#define QS_2U8_PRE_(data1_, data2_)
Definition: qs_pkg.h:154
#define QS_SIG_PRE_(sig_)
Definition: qs_pkg.h:172
#define QS_EQC_PRE_(ctr_)
Definition: qs_pkg.h:205
#define QF_MAX_ACTIVE
Definition: qf.h:107
void QActive_ctor(QActive *const me, QStateHandler initial)
Definition: qf_qact.c:58
bool QActive_post_(QActive *const me, QEvt const *const e, uint_fast16_t const margin, void const *const sender)
Definition: qf_actq.c:83
QEvt const * QActive_get_(QActive *const me)
Definition: qf_actq.c:310
QHsm super
Definition: qf.h:108
void QActive_postLIFO_(QActive *const me, QEvt const *const e)
Definition: qf_actq.c:221
void QActive_start_(QActive *const me, uint_fast8_t prio, QEvt const **const qSto, uint_fast16_t const qLen, void *const stkSto, uint_fast16_t const stkSize, void const *const par)
Definition: qutest.c:87
uint8_t prio
Definition: qf.h:152
struct QHsmVtable super
Definition: qf.h:158
Definition: qep.h:119
QSignal sig
Definition: qep.h:123
uint8_t poolId_
Definition: qep.h:128
uint8_t volatile refCtr_
Definition: qep.h:133
uint_fast16_t QF_getQueueMin(uint_fast8_t const prio)
Definition: qf_actq.c:376
QActive * QF_active_[QF_MAX_ACTIVE+1U]
Definition: qf_act.c:48
void QF_gc(QEvt const *const e)
Definition: qf_dyn.c:241
Definition: qep.h:253
struct QHsmVtable const * vptr
Definition: qep.h:254
QStateHandler QHsm_getStateHandler_(QHsm *const me)
Definition: qep_hsm.c:605
void QS_onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status)
Definition: qf.h:894
QActive super
Definition: qf.h:895
static void QTicker_postLIFO_(QActive *const me, QEvt const *const e)
Definition: qf_actq.c:522
void QTicker_ctor(QTicker *const me, uint_fast8_t tickRate)
Definition: qf_actq.c:419
static void QTicker_dispatch_(QHsm *const me, QEvt const *const e, uint_fast8_t const qs_id)
Definition: qf_actq.c:456
static void QTicker_init_(QHsm *const me, void const *par, uint_fast8_t const qs_id)
Definition: qf_actq.c:440