QP/C  8.0.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 Q_REQUIRE_INCRIT(100, qLen < 0xFFU);
53#endif
54
55 me->frontEvt = (QEvt *)0; // no events in the queue
56 me->ring = qSto; // the beginning of the ring buffer
57 me->end = (QEQueueCtr)qLen;
58 if (qLen > 0U) {
59 me->head = 0U;
60 me->tail = 0U;
61 }
62 me->nFree = (QEQueueCtr)(qLen + 1U); // +1 for frontEvt
63 me->nMin = me->nFree;
64
66}
67
68//............................................................................
69//! @public @memberof QEQueue
70bool QEQueue_post(QEQueue * const me,
71 struct QEvt const * const e,
72 uint_fast16_t const margin,
73 uint_fast8_t const qsId)
74{
75#ifndef Q_SPY
76 Q_UNUSED_PAR(qsId);
77#endif
78
81
82 Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
83
84 QEQueueCtr tmp = me->nFree; // get volatile into temporary
85
86 // can the queue accept the event?
87 bool const status = ((margin == QF_NO_MARGIN) && (tmp > 0U))
88 || (tmp > (QEQueueCtr)margin);
89 if (status) {
90 // is it a mutable event?
91 if (e->poolNum_ != 0U) {
92 Q_ASSERT_INCRIT(205, e->refCtr_ < (2U * QF_MAX_ACTIVE));
93 QEvt_refCtr_inc_(e); // increment the reference counter
94 }
95
96 --tmp; // one free entry just used up
97
98 me->nFree = tmp; // update the original
99 if (me->nMin > tmp) { // is this the new minimum?
100 me->nMin = tmp; // update minimum so far
101 }
102
103#ifdef Q_SPY
104 QS_BEGIN_PRE(QS_QF_EQUEUE_POST, qsId)
105 QS_TIME_PRE(); // timestamp
106 QS_SIG_PRE(e->sig); // the signal of the event
107 QS_OBJ_PRE(me); // this queue object
109 QS_EQC_PRE(tmp); // # free entries
110 QS_EQC_PRE(me->nMin); // min # free entries
111 QS_END_PRE()
112#endif // def Q_SPY
113
114 if (me->frontEvt == (QEvt *)0) { // is the queue empty?
115 me->frontEvt = e; // deliver event directly
116 }
117 else { // queue was not empty, insert event into the ring-buffer
118 tmp = me->head; // get volatile into temporary
119 me->ring[tmp] = e; // insert e into buffer
120
121 if (tmp == 0U) { // need to wrap the head?
122 tmp = me->end;
123 }
124 --tmp; // advance head (counter-clockwise)
125
126 me->head = tmp; // update the original
127 }
128 }
129 else { // event cannot be posted
130 // dropping events must be acceptable
131 Q_ASSERT_INCRIT(230, margin != QF_NO_MARGIN);
132
133#ifdef Q_SPY
134 QS_BEGIN_PRE(QS_QF_EQUEUE_POST_ATTEMPT, qsId)
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(tmp); // # 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 Q_REQUIRE_INCRIT(300, e != (QEvt *)0);
164
165 QEQueueCtr tmp = me->nFree; // get volatile into temporary
166
167 // must be able to LIFO-post the event
168 Q_REQUIRE_INCRIT(310, tmp != 0U);
169
170 if (e->poolNum_ != 0U) { // is it a mutable event?
171 Q_ASSERT_INCRIT(305, e->refCtr_ < (2U * QF_MAX_ACTIVE));
172 QEvt_refCtr_inc_(e); // increment the reference counter
173 }
174
175 --tmp; // one free entry just used up
176
177 me->nFree = tmp; // update the original
178 if (me->nMin > tmp) { // is this the new minimum?
179 me->nMin = tmp; // update minimum so far
180 }
181
182 QS_BEGIN_PRE(QS_QF_EQUEUE_POST_LIFO, qsId)
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(tmp); // # free entries
188 QS_EQC_PRE(me->nMin); // min # free entries
189 QS_END_PRE()
190
191 QEvt const * const frontEvt = me->frontEvt;
192 me->frontEvt = e; // deliver the event directly to the front
193
194 if (frontEvt != (QEvt *)0) { // was the queue NOT empty?
195 tmp = me->tail; // get volatile into temporary;
196 ++tmp;
197 if (tmp == me->end) { // need to wrap the tail?
198 tmp = 0U; // wrap around
199 }
200 me->tail = tmp;
201 me->ring[tmp] = 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; // always remove evt from the front
220
221 if (e != (QEvt *)0) { // was the queue not empty?
222 QEQueueCtr tmp = me->nFree; // get volatile into temporary
223
224 ++tmp; // one more free event in the queue
225
226 me->nFree = tmp; // update the # free
227
228 // any events in the ring buffer?
229 if (tmp <= me->end) {
230
231 QS_BEGIN_PRE(QS_QF_EQUEUE_GET, qsId)
232 QS_TIME_PRE(); // timestamp
233 QS_SIG_PRE(e->sig); // the signal of this event
234 QS_OBJ_PRE(me); // this queue object
236 QS_EQC_PRE(tmp); // # free entries
237 QS_END_PRE()
238
239 tmp = me->tail; // get volatile into temporary
240 QEvt const * const frontEvt = me->ring[tmp];
241
242 Q_ASSERT_INCRIT(420, frontEvt != (QEvt *)0);
243
244 me->frontEvt = frontEvt; // update the original
245
246 if (tmp == 0U) { // need to wrap the tail?
247 tmp = me->end;
248 }
249 --tmp; // advance the tail (counter-clockwise)
250 me->tail = tmp; // update the original
251 }
252 else {
253 me->frontEvt = (QEvt *)0; // queue becomes empty
254
255 // all entries in the queue must be free (+1 for frontEvt)
256 Q_ASSERT_INCRIT(440, tmp == (me->end + 1U));
257
258 QS_BEGIN_PRE(QS_QF_EQUEUE_GET_LAST, qsId)
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}
uint16_t QEQueueCtr
Definition qequeue.h:39
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:96
#define QF_NO_MARGIN
Special value of margin that causes asserting failure in case event allocation or event posting fails...
Definition qp.h:747
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
Definition qp_config.h:123
Internal (package scope) QP/C interface.
Sample QP/C port.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.h:149
#define QS_EQC_PRE(ctr_)
Definition qs_dummy.h:151
#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_END_PRE()
Definition qs_dummy.h:141
#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
Native QF Event Queue.
Definition qequeue.h:48
QEQueueCtr volatile tail
Offset of where next event will be extracted from the buffer.
Definition qequeue.h:53
QEQueueCtr volatile head
Offset to where next event will be inserted into the buffer.
Definition qequeue.h:52
QEQueueCtr end
Offset of the end of the ring buffer from the start of the buffer.
Definition qequeue.h:51
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:55
QEQueueCtr volatile nFree
Number of free events in the ring buffer.
Definition qequeue.h:54
struct QEvt const ** ring
Pointer to the start of the ring buffer.
Definition qequeue.h:50
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
struct QEvt const *volatile frontEvt
Pointer to event at the front of the queue.
Definition qequeue.h:49
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:70
Event class.
Definition qp.h:114
QSignal sig
Signal of the event (see Event Signal)
Definition qp.h:115
uint8_t volatile refCtr_
Event reference counter.
Definition qp.h:117
uint8_t poolNum_
Event pool number of this event.
Definition qp.h:116