Reference Manual For QP/C 8.1.5
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 QEvtPtr * 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.e = (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 const status = ((margin == QF_NO_MARGIN)
89 || (nFree > (QEQueueCtr)margin));
90 if (status) { // can post the event?
91
92 // the queue must have a free slot
93 Q_ASSERT_INCRIT(130, nFree != 0U);
94
95#if (QF_MAX_EPOOL > 0U)
96 if (e->poolNum_ != 0U) { // is it a mutable event?
97 QEvt_refCtr_inc_(e); // increment the reference counter
98 }
99#endif // (QF_MAX_EPOOL > 0U)
100
101 --nFree; // one free entry just used up
102 me->nFree = nFree; // update the original
103 if (me->nMin > nFree) { // is this the new minimum?
104 me->nMin = nFree; // update minimum so far
105 }
106
107#ifdef Q_SPY
109 QS_TIME_PRE(); // timestamp
110 QS_SIG_PRE(e->sig); // the signal of the event
111 QS_OBJ_PRE(me); // this queue object
113 QS_EQC_PRE(nFree); // # free entries
114 QS_EQC_PRE(me->nMin); // min # free entries
115 QS_END_PRE()
116#endif // def Q_SPY
117
118 if (me->frontEvt.e == (QEvt *)0) { // is the queue empty?
119 me->frontEvt.e = e; // deliver event directly
120 }
121 else { // queue was not empty, insert event into the ring-buffer
122 QEQueueCtr head = me->head; // get member into temporary
123 me->ring[head].e = e; // insert e into buffer
124
125 if (head == 0U) { // need to wrap the head?
126 head = me->end;
127 }
128 --head; // advance head (counter-clockwise)
129 me->head = head; // update the member original
130 }
131 }
132 else { // event cannot be posted
133#ifdef Q_SPY
135 QS_TIME_PRE(); // timestamp
136 QS_SIG_PRE(e->sig); // the signal of this event
137 QS_OBJ_PRE(me); // this queue object
139 QS_EQC_PRE(nFree); // # free entries
140 QS_EQC_PRE(margin); // margin requested
141 QS_END_PRE()
142#endif // def Q_SPY
143 }
144
145 QF_CRIT_EXIT();
146
147 return status;
148}
149
150//............................................................................
151//! @public @memberof QEQueue
152void QEQueue_postLIFO(QEQueue * const me,
153 struct QEvt const * const e,
154 uint_fast8_t const qsId)
155{
156#ifndef Q_SPY
157 Q_UNUSED_PAR(qsId);
158#endif
159
162
163 // event e to be posted must be valid
164 Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
165
166 QEQueueCtr nFree = me->nFree; // get member into temporary
167
168 // must be able to LIFO-post the event
169 Q_REQUIRE_INCRIT(230, nFree != 0U);
170
171 if (e->poolNum_ != 0U) { // is it a mutable event?
172 QEvt_refCtr_inc_(e); // increment the reference counter
173 }
174
175 --nFree; // one free entry just used up
176 me->nFree = nFree; // update the member original
177
178 if (me->nMin > nFree) { // is this the new minimum?
179 me->nMin = nFree; // update minimum so far
180 }
181
183 QS_TIME_PRE(); // timestamp
184 QS_SIG_PRE(e->sig); // the signal of this event
185 QS_OBJ_PRE(me); // this queue object
187 QS_EQC_PRE(nFree); // # free entries
188 QS_EQC_PRE(me->nMin); // min # free entries
189 QS_END_PRE()
190
191 QEvt const * const frontEvt = me->frontEvt.e; // get member into temporary
192 me->frontEvt.e = e; // deliver the event directly to the front
193
194 if (frontEvt != (QEvt *)0) { // was the queue NOT empty?
195 QEQueueCtr tail = me->tail; // get member into temporary
196 ++tail;
197 if (tail == me->end) { // need to wrap the tail?
198 tail = 0U; // wrap around
199 }
200 me->tail = tail; // update the member original
201 me->ring[tail].e = frontEvt;
202 }
203
204 QF_CRIT_EXIT();
205}
206
207//............................................................................
208//! @public @memberof QEQueue
209struct QEvt const * QEQueue_get(QEQueue * const me,
210 uint_fast8_t const qsId)
211{
212#ifndef Q_SPY
213 Q_UNUSED_PAR(qsId);
214#endif
215
218
219 QEvt const * const e = me->frontEvt.e; // always remove evt from the front
220
221 if (e != (QEvt *)0) { // is the queue NOT empty?
222 QEQueueCtr nFree = me->nFree; // get member into temporary
223
224 ++nFree; // one more free event in the queue
225 me->nFree = nFree; // update the # free
226
227 if (nFree <= me->end) { // any events in the ring buffer?
228 // remove event from the tail
229 QEQueueCtr tail = me->tail; // get member into temporary
230
231 QEvt const * const frontEvt = me->ring[tail].e;
232
233 // the queue must have at least one event (at the front)
234 Q_ASSERT_INCRIT(350, frontEvt != (QEvt *)0);
235
237 QS_TIME_PRE(); // timestamp
238 QS_SIG_PRE(e->sig); // the signal of this event
239 QS_OBJ_PRE(me); // this queue object
241 QS_EQC_PRE(nFree); // # free entries
242 QS_END_PRE()
243
244 me->frontEvt.e = frontEvt; // update the member original
245
246 if (tail == 0U) { // need to wrap the tail?
247 tail = me->end; // wrap around
248 }
249 --tail; // advance the tail (counter-clockwise)
250 me->tail = tail; // update the member original
251 }
252 else {
253 me->frontEvt.e = (QEvt *)0; // queue becomes empty
254
255 // all entries in the queue must be free (+1 for frontEvt)
256 Q_ASSERT_INCRIT(370, nFree == (me->end + 1U));
257
259 QS_TIME_PRE(); // timestamp
260 QS_SIG_PRE(e->sig); // the signal of this event
261 QS_OBJ_PRE(me); // this queue object
263 QS_END_PRE()
264 }
265 }
266
267 QF_CRIT_EXIT();
268
269 return e;
270}
271
272//............................................................................
273//! @public @memberof QEQueue
274uint16_t QEQueue_getUse(QEQueue const * const me) {
275 // NOTE: this function does NOT apply critical section, so it can
276 // be safely called from an already established critical section.
277 uint16_t nUse = 0U;
278 if (me->frontEvt.e != (QEvt *)0) { // queue not empty?
279 nUse = (uint16_t)((uint16_t)me->end + 1U - (uint16_t)me->nFree);
280 }
281 return nUse;
282}
283//............................................................................
284//! @public @memberof QEQueue
285uint16_t QEQueue_getFree(QEQueue const * const me) {
286 // NOTE: this function does NOT apply critical section, so it can
287 // be safely called from an already established critical section.
288 return (uint16_t)me->nFree;
289}
290//............................................................................
291//! @public @memberof QEQueue
292uint16_t QEQueue_getMin(QEQueue const * const me) {
293 // NOTE: this function does NOT apply critical section, so it can
294 // be safely called from an already established critical section.
295 return (uint16_t)me->nMin;
296}
297//............................................................................
298//! @public @memberof QEQueue
299bool QEQueue_isEmpty(QEQueue const * const me) {
300 // NOTE: this function does NOT apply critical section, so it can
301 // be safely called from an already established critical section.
302 return me->frontEvt.e == (struct QEvt *)0;
303}
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:694
QP/C Framework in C internal (package-scope) interface.
Sample QP/C port.
#define QF_CRIT_ENTRY()
Port-specific critical section entry.
Definition qp_port.h:65
#define QF_CRIT_EXIT()
Port-specific critical section exit.
Definition qp_port.h:66
#define QF_CRIT_STAT
Define the critical section status that was present before entering the critical section.
Definition qp_port.h:64
@ 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. \clearpage .
#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 (fault detection).
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section).
Definition qsafe.h:54
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section).
Definition qsafe.h:98
Native QF Event Queue.
Definition qequeue.h:52
uint16_t QEQueue_getFree(QEQueue const *const me)
Obtain the number of free entries still available in the queue.
Definition qf_qeq.c:285
void QEQueue_init(QEQueue *const me, QEvtPtr *const qSto, uint_fast16_t const qLen)
Initialize the native QF event queue.
Definition qf_qeq.c:44
QEQueueCtr nFree
Number of free events in the ring buffer \clearpage .
Definition qequeue.h:58
QEQueueCtr end
Offset of the end of the ring buffer from the start of the buffer \clearpage .
Definition qequeue.h:55
uint16_t QEQueue_getUse(QEQueue const *const me)
Obtain the number of entries in use in the queue.
Definition qf_qeq.c:274
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:209
QEQueueCtr nMin
Minimum number of free events ever in the ring buffer.
Definition qequeue.h:59
QEQueueCtr tail
Offset of where next event will be extracted from the buffer \clearpage .
Definition qequeue.h:57
bool QEQueue_isEmpty(QEQueue const *const me)
Find out if the queue is empty.
Definition qf_qeq.c:299
QEvtPtr * ring
Pointer to the start of the ring buffer \clearpage .
Definition qequeue.h:54
QEQueueCtr head
Offset to where next event will be inserted into the buffer \clearpage .
Definition qequeue.h:56
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:152
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:292
QEvtPtr frontEvt
Pointer to event at the front of the queue.
Definition qequeue.h:53
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
The data type to store in the event queue ring-buffer.
Definition qequeue.h:46