QP/C 8.1.2
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_qeq.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_qeq")
41
42//............................................................................
43//! @public @memberof QEQueue
44void QEQueue_init(QEQueue * const me,
45 struct QEvt const * * const qSto,
46 uint_fast16_t const qLen)
47{
50
51#if (QF_EQUEUE_CTR_SIZE == 1U)
52 // the qLen paramter must not exceed the dynamic range of uint8_t
53 Q_REQUIRE_INCRIT(10, qLen < 0xFFU);
54#endif
55
56 me->frontEvt = (QEvt *)0; // no events in the queue
57 me->ring = qSto; // the beginning of the ring buffer
58 me->end = (QEQueueCtr)qLen; // index of the last element
59 if (qLen > 0U) { // queue buffer storage provided?
60 me->head = 0U; // head index: for removing events
61 me->tail = 0U; // tail index: for inserting events
62 }
63 me->nFree = (QEQueueCtr)(qLen + 1U); // +1 for frontEvt
64 me->nMin = me->nFree; // minimum so far
65
67}
68
69//............................................................................
70//! @public @memberof QEQueue
71bool QEQueue_post(QEQueue * const me,
72 struct QEvt const * const e,
73 uint_fast16_t const margin,
74 uint_fast8_t const qsId)
75{
76#ifndef Q_SPY
77 Q_UNUSED_PAR(qsId);
78#endif
79
82
83 // the posted event must be valid
84 Q_REQUIRE_INCRIT(100, e != (QEvt *)0);
85
86 QEQueueCtr nFree = me->nFree; // get member into temporary
87
88 bool status = (nFree > 0U);
89 if (margin == QF_NO_MARGIN) { // no margin requested?
90 // queue must not overflow
91 Q_ASSERT_INCRIT(130, status);
92 }
93 else {
94 status = (nFree > (QEQueueCtr)margin);
95 }
96
97 if (status) { // can post the event?
98
99#if (QF_MAX_EPOOL > 0U)
100 if (e->poolNum_ != 0U) { // is it a mutable event?
101 QEvt_refCtr_inc_(e); // increment the reference counter
102 }
103#endif // (QF_MAX_EPOOL > 0U)
104
105 --nFree; // one free entry just used up
106 me->nFree = nFree; // update the original
107 if (me->nMin > nFree) { // is this the new minimum?
108 me->nMin = nFree; // update minimum so far
109 }
110
111#ifdef Q_SPY
113 QS_TIME_PRE(); // timestamp
114 QS_SIG_PRE(e->sig); // the signal of the event
115 QS_OBJ_PRE(me); // this queue object
117 QS_EQC_PRE(nFree); // # free entries
118 QS_EQC_PRE(me->nMin); // min # free entries
119 QS_END_PRE()
120#endif // def Q_SPY
121
122 if (me->frontEvt == (QEvt *)0) { // is the queue empty?
123 me->frontEvt = e; // deliver event directly
124 }
125 else { // queue was not empty, insert event into the ring-buffer
126 QEQueueCtr head = me->head; // get member into temporary
127 me->ring[head] = e; // insert e into buffer
128
129 if (head == 0U) { // need to wrap the head?
130 head = me->end;
131 }
132 --head; // advance head (counter-clockwise)
133 me->head = head; // update the member original
134 }
135 }
136 else { // event cannot be posted
137#ifdef Q_SPY
139 QS_TIME_PRE(); // timestamp
140 QS_SIG_PRE(e->sig); // the signal of this event
141 QS_OBJ_PRE(me); // this queue object
143 QS_EQC_PRE(nFree); // # free entries
144 QS_EQC_PRE(margin); // margin requested
145 QS_END_PRE()
146#endif // def Q_SPY
147 }
148
149 QF_CRIT_EXIT();
150
151 return status;
152}
153
154//............................................................................
155//! @public @memberof QEQueue
156void QEQueue_postLIFO(QEQueue * const me,
157 struct QEvt const * const e,
158 uint_fast8_t const qsId)
159{
160#ifndef Q_SPY
161 Q_UNUSED_PAR(qsId);
162#endif
163
166
167 // event e to be posted must be valid
168 Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
169
170 QEQueueCtr nFree = me->nFree; // get member into temporary
171
172 // must be able to LIFO-post the event
173 Q_REQUIRE_INCRIT(230, nFree != 0U);
174
175 if (e->poolNum_ != 0U) { // is it a mutable event?
176 QEvt_refCtr_inc_(e); // increment the reference counter
177 }
178
179 --nFree; // one free entry just used up
180 me->nFree = nFree; // update the member original
181
182 if (me->nMin > nFree) { // is this the new minimum?
183 me->nMin = nFree; // update minimum so far
184 }
185
187 QS_TIME_PRE(); // timestamp
188 QS_SIG_PRE(e->sig); // the signal of this event
189 QS_OBJ_PRE(me); // this queue object
191 QS_EQC_PRE(nFree); // # free entries
192 QS_EQC_PRE(me->nMin); // min # free entries
193 QS_END_PRE()
194
195 QEvt const * const frontEvt = me->frontEvt; // get member into temporary
196 me->frontEvt = e; // deliver the event directly to the front
197
198 if (frontEvt != (QEvt *)0) { // was the queue NOT empty?
199 QEQueueCtr tail = me->tail; // get member into temporary
200
201 ++tail;
202 if (tail == me->end) { // need to wrap the tail?
203 tail = 0U; // wrap around
204 }
205 me->tail = tail; // update the member original
206 me->ring[tail] = frontEvt;
207 }
208
209 QF_CRIT_EXIT();
210}
211
212//............................................................................
213//! @public @memberof QEQueue
214struct QEvt const * QEQueue_get(QEQueue * const me,
215 uint_fast8_t const qsId)
216{
217#ifndef Q_SPY
218 Q_UNUSED_PAR(qsId);
219#endif
220
223
224 QEvt const * const e = me->frontEvt; // always remove evt from the front
225
226 if (e != (QEvt *)0) { // is the queue NOT empty?
227 QEQueueCtr nFree = me->nFree; // get member into temporary
228
229 ++nFree; // one more free event in the queue
230 me->nFree = nFree; // update the # free
231
232 if (nFree <= me->end) { // any events in the ring buffer?
233 // remove event from the tail
234 QEQueueCtr tail = me->tail; // get member into temporary
235
236 QEvt const * const frontEvt = me->ring[tail];
237
238 // the queue must have at least one event (at the front)
239 Q_ASSERT_INCRIT(350, frontEvt != (QEvt *)0);
240
242 QS_TIME_PRE(); // timestamp
243 QS_SIG_PRE(e->sig); // the signal of this event
244 QS_OBJ_PRE(me); // this queue object
246 QS_EQC_PRE(nFree); // # free entries
247 QS_END_PRE()
248
249 me->frontEvt = frontEvt; // update the member original
250
251 if (tail == 0U) { // need to wrap the tail?
252 tail = me->end; // wrap around
253 }
254 --tail; // advance the tail (counter-clockwise)
255 me->tail = tail; // update the member original
256 }
257 else {
258 me->frontEvt = (QEvt *)0; // queue becomes empty
259
260 // all entries in the queue must be free (+1 for frontEvt)
261 Q_ASSERT_INCRIT(360, nFree == (me->end + 1U));
262
264 QS_TIME_PRE(); // timestamp
265 QS_SIG_PRE(e->sig); // the signal of this event
266 QS_OBJ_PRE(me); // this queue object
268 QS_END_PRE()
269 }
270 }
271
272 QF_CRIT_EXIT();
273
274 return e;
275}
276
277//............................................................................
278//! @public @memberof QEQueue
279uint16_t QEQueue_getUse(QEQueue const * const me) {
280 // NOTE: this function does NOT apply critical section, so it can
281 // be safely called from an already established critical section.
282 uint16_t nUse = 0U;
283 if (me->frontEvt != (QEvt *)0) { // queue not empty?
284 nUse = (uint16_t)((uint16_t)me->end + 1U - (uint16_t)me->nFree);
285 }
286 return nUse;
287}
288//............................................................................
289//! @public @memberof QEQueue
290uint16_t QEQueue_getFree(QEQueue const * const me) {
291 // NOTE: this function does NOT apply critical section, so it can
292 // be safely called from an already established critical section.
293 return (uint16_t)me->nFree;
294}
295//............................................................................
296//! @public @memberof QEQueue
297uint16_t QEQueue_getMin(QEQueue const * const me) {
298 // NOTE: this function does NOT apply critical section, so it can
299 // be safely called from an already established critical section.
300 return (uint16_t)me->nMin;
301}
302//............................................................................
303//! @public @memberof QEQueue
304bool QEQueue_isEmpty(QEQueue const * const me) {
305 // NOTE: this function does NOT apply critical section, so it can
306 // be safely called from an already established critical section.
307 return me->frontEvt == (struct QEvt *)0;
308}
309
uint16_t QEQueueCtr
The data type to store the ring-buffer counters.
Definition qequeue.h:39
#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
QP/C Framework in C internal (package-scope) interface.
Sample QP/C port.
#define QS_TIME_PRE()
Definition qs.h:340
@ QS_QF_EQUEUE_GET_LAST
get the last event from the queue
Definition qs.h:80
@ QS_QF_EQUEUE_POST_ATTEMPT
attempt to post evt to QEQueue failed
Definition qs.h:118
@ QS_QF_EQUEUE_POST_LIFO
an event was posted (LIFO) to a raw queue
Definition qs.h:78
@ QS_QF_EQUEUE_GET
get an event and queue still not empty
Definition qs.h:79
@ QS_QF_EQUEUE_POST
an event was posted (FIFO) to a raw queue
Definition qs.h:77
QS (QP/Spy software tracing) internal (package-scope) interface.
#define QS_OBJ_PRE(obj_)
Output pre-formatted object pointer element.
Definition qs_pkg.h:46
#define QS_EQC_PRE(ctr_)
Output pre-formatted event queue counter data element.
Definition qs_pkg.h:63
#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_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
Native QF Event Queue.
Definition qequeue.h:48
uint16_t QEQueue_getFree(QEQueue const *const me)
Obtain the number of free entries still available in the queue.
Definition qf_qeq.c:290
QEQueueCtr nFree
Number of free events in the ring buffer.
Definition qequeue.h:54
QEQueueCtr end
Offset of the end of the ring buffer from the start of the buffer.
Definition qequeue.h:51
uint16_t QEQueue_getUse(QEQueue const *const me)
Obtain the number of entries in use in the queue.
Definition qf_qeq.c:279
struct QEvt const * frontEvt
Pointer to event at the front of the queue.
Definition qequeue.h:49
struct QEvt const * QEQueue_get(QEQueue *const me, uint_fast8_t const qsId)
Obtain an event from the "raw" thread-safe queue.
Definition qf_qeq.c:214
QEQueueCtr nMin
Minimum number of free events ever in the ring buffer.
Definition qequeue.h:55
QEQueueCtr tail
Offset of where next event will be extracted from the buffer.
Definition qequeue.h:53
bool QEQueue_isEmpty(QEQueue const *const me)
Find out if the queue is empty.
Definition qf_qeq.c:304
struct QEvt const ** ring
Pointer to the start of the ring buffer.
Definition qequeue.h:50
void QEQueue_init(QEQueue *const me, struct QEvt const **const qSto, uint_fast16_t const qLen)
Initialize the native QF event queue.
Definition qf_qeq.c:44
QEQueueCtr head
Offset to where next event will be inserted into the buffer.
Definition qequeue.h:52
void QEQueue_postLIFO(QEQueue *const me, struct QEvt const *const e, uint_fast8_t const qsId)
Post an event to the "raw" thread-safe event queue (LIFO).
Definition qf_qeq.c:156
uint16_t QEQueue_getMin(QEQueue const *const me)
Obtain the minimum number of free entries ever in the queue (a.k.a. "low-watermark").
Definition qf_qeq.c:297
bool QEQueue_post(QEQueue *const me, struct QEvt const *const e, uint_fast16_t const margin, uint_fast8_t const qsId)
Post an event to the "raw" thread-safe event queue (FIFO).
Definition qf_qeq.c:71
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