QP/C++ 8.1.1
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_qeq.cpp
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.hpp" // QP port
31#include "qp_pkg.hpp" // 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.hpp" // QS port
35 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
36#else
37 #include "qs_dummy.hpp" // disable the QS software tracing
38#endif // Q_SPY
39
40// unnamed namespace for local definitions with internal linkage
41namespace {
42Q_DEFINE_THIS_MODULE("qf_qeq")
43} // unnamed namespace
44
45namespace QP {
46
47//............................................................................
49 : m_frontEvt(nullptr), // queue empty initially
50 m_ring(nullptr), // no queue buffer initially
51 m_end(0U), // end index 0 initially
52 m_head(0U), // head index 0 initially
53 m_tail(0U), // tail index 0 initially
54 m_nFree(0U), // no free events initially
55 m_nMin(0U) // all time minimum of free entries so far
56{}
57//............................................................................
59 QEvt const * * const qSto,
60 std::uint_fast16_t const qLen) noexcept
61{
64
65#if (QF_EQUEUE_CTR_SIZE == 1U)
66 // the qLen paramter must not exceed the dynamic range of uint8_t
67 Q_REQUIRE_INCRIT(10, qLen < 0xFFU);
68#endif
69
70 m_frontEvt = nullptr; // no events in the queue
71 m_ring = qSto; // the beginning of the ring buffer
72 m_end = static_cast<QEQueueCtr>(qLen); // index of the last element
73 if (qLen > 0U) { // queue buffer storage provided?
74 m_head = 0U; // head index: for removing events
75 m_tail = 0U; // tail index: for inserting events
76 }
77 m_nFree = static_cast<QEQueueCtr>(qLen + 1U); // +1 for frontEvt
78 m_nMin = m_nFree; // minimum so far
79
81}
82
83//............................................................................
85 QEvt const * const e,
86 std::uint_fast16_t const margin,
87 std::uint_fast8_t const qsId) noexcept
88{
89#ifndef Q_SPY
90 Q_UNUSED_PAR(qsId);
91#endif
92
95
96 // the posted event must be valid
97 Q_REQUIRE_INCRIT(100, e != nullptr);
98
99 QEQueueCtr nFree = m_nFree; // get member into temporary
100
101 bool status = (nFree > 0U);
102 if (margin == QF::NO_MARGIN) { // no margin requested?
103 // queue must not overflow
104 Q_ASSERT_INCRIT(130, status);
105 }
106 else {
107 status = (nFree > static_cast<QEQueueCtr>(margin));
108 }
109
110 if (status) { // can post the event?
111
112#if (QF_MAX_EPOOL > 0U)
113 if (e->poolNum_ != 0U) { // is it a mutable event?
114 QEvt_refCtr_inc_(e); // increment the reference counter
115 }
116#endif // (QF_MAX_EPOOL > 0U)
117
118 --nFree; // one free entry just used up
119 m_nFree = nFree; // update the original
120 if (m_nMin > nFree) { // is this the new minimum?
121 m_nMin = nFree; // update minimum so far
122 }
123
124#ifdef Q_SPY
126 QS_TIME_PRE(); // timestamp
127 QS_SIG_PRE(e->sig); // the signal of the event
128 QS_OBJ_PRE(this); // this queue object
129 QS_2U8_PRE(e->poolNum_, e->refCtr_);
130 QS_EQC_PRE(nFree); // # free entries
131 QS_EQC_PRE(m_nMin); // min # free entries
132 QS_END_PRE()
133#endif // def Q_SPY
134
135 if (m_frontEvt == nullptr) { // is the queue empty?
136 m_frontEvt = e; // deliver event directly
137 }
138 else { // queue was not empty, insert event into the ring-buffer
139 QEQueueCtr head = m_head; // get member into temporary
140 m_ring[head] = e; // insert e into buffer
141
142 if (head == 0U) { // need to wrap the head?
143 head = m_end;
144 }
145 --head; // advance head (counter-clockwise)
146 m_head = head; // update the member original
147 }
148 }
149 else { // event cannot be posted
150#ifdef Q_SPY
152 QS_TIME_PRE(); // timestamp
153 QS_SIG_PRE(e->sig); // the signal of this event
154 QS_OBJ_PRE(this); // this queue object
155 QS_2U8_PRE(e->poolNum_, e->refCtr_);
156 QS_EQC_PRE(nFree); // # free entries
157 QS_EQC_PRE(margin); // margin requested
158 QS_END_PRE()
159#endif // def Q_SPY
160 }
161
162 QF_CRIT_EXIT();
163
164 return status;
165}
166
167//............................................................................
169 QEvt const * const e,
170 std::uint_fast8_t const qsId) noexcept
171{
172#ifndef Q_SPY
173 Q_UNUSED_PAR(qsId);
174#endif
175
178
179 // event e to be posted must be valid
180 Q_REQUIRE_INCRIT(200, e != nullptr);
181
182 QEQueueCtr nFree = m_nFree; // get member into temporary
183
184 // must be able to LIFO-post the event
185 Q_REQUIRE_INCRIT(230, nFree != 0U);
186
187 if (e->poolNum_ != 0U) { // is it a mutable event?
188 QEvt_refCtr_inc_(e); // increment the reference counter
189 }
190
191 --nFree; // one free entry just used up
192 m_nFree = nFree; // update the member original
193 if (m_nMin > nFree) { // is this the new minimum?
194 m_nMin = nFree; // update minimum so far
195 }
196
198 QS_TIME_PRE(); // timestamp
199 QS_SIG_PRE(e->sig); // the signal of this event
200 QS_OBJ_PRE(this); // this queue object
201 QS_2U8_PRE(e->poolNum_, e->refCtr_);
202 QS_EQC_PRE(nFree); // # free entries
203 QS_EQC_PRE(m_nMin); // min # free entries
204 QS_END_PRE()
205
206 QEvt const * const frontEvt = m_frontEvt; // get member into temporary
207 m_frontEvt = e; // deliver the event directly to the front
208
209 if (frontEvt != nullptr) { // was the queue NOT empty?
210 QEQueueCtr tail = m_tail; // get member into temporary
211 ++tail;
212 if (tail == m_end) { // need to wrap the tail?
213 tail = 0U; // wrap around
214 }
215 m_tail = tail; // update the member original
216 m_ring[tail] = frontEvt;
217 }
218
219 QF_CRIT_EXIT();
220}
221
222//............................................................................
223QEvt const * QEQueue::get(std::uint_fast8_t const qsId) noexcept {
224#ifndef Q_SPY
225 Q_UNUSED_PAR(qsId);
226#endif
227
230
231 QEvt const * const e = m_frontEvt; // always remove evt from the front
232
233 if (e != nullptr) { // was the queue not empty?
234 QEQueueCtr nFree = m_nFree; // get member into temporary
235
236 ++nFree; // one more free event in the queue
237 m_nFree = nFree; // update the # free
238
239 if (nFree <= m_end) { // any events in the ring buffer?
240 // remove event from the tail
241 QEQueueCtr tail = m_tail; // get member into temporary
242
243 QEvt const * const frontEvt = m_ring[tail];
244
245 // the queue must have at least one event (at the front)
246 Q_ASSERT_INCRIT(350, frontEvt != nullptr);
247
249 QS_TIME_PRE(); // timestamp
250 QS_SIG_PRE(e->sig); // the signal of this event
251 QS_OBJ_PRE(this); // this queue object
253 QS_EQC_PRE(nFree); // # free entries
254 QS_END_PRE()
255
256 m_frontEvt = frontEvt; // update the member original
257
258 if (tail == 0U) { // need to wrap the tail?
259 tail = m_end; // wrap around
260 }
261 --tail; // advance the tail (counter-clockwise)
262 m_tail = tail; // update the member original
263 }
264 else {
265 m_frontEvt = nullptr; // queue becomes empty
266
267 // all entries in the queue must be free (+1 for frontEvt)
268 Q_INVARIANT_INCRIT(360, nFree == (m_end + 1U));
269
271 QS_TIME_PRE(); // timestamp
272 QS_SIG_PRE(e->sig); // the signal of this event
273 QS_OBJ_PRE(this); // this queue object
275 QS_END_PRE()
276 }
277 }
278
279 QF_CRIT_EXIT();
280
281 return e;
282}
283
284//............................................................................
285std::uint16_t QEQueue::getUse() const noexcept {
286 // NOTE: this function does NOT apply critical section, so it can
287 // be safely called from an already established critical section.
288 std::uint16_t nUse = 0U;
289 if (m_frontEvt != nullptr) { // queue not empty?
290 nUse = static_cast<std::uint16_t>(
291 static_cast<std::uint16_t>(m_end) + 1U
292 - static_cast<std::uint16_t>(m_nFree));
293 }
294 return nUse;
295}
296//............................................................................
297std::uint16_t QEQueue::getFree() const noexcept {
298 // NOTE: this function does NOT apply critical section, so it can
299 // be safely called from an already established critical section.
300 return m_nFree;
301}
302//............................................................................
303std::uint16_t QEQueue::getMin() const noexcept {
304 // NOTE: this function does NOT apply critical section, so it can
305 // be safely called from an already established critical section.
306 return m_nMin;
307}
308//............................................................................
309bool QEQueue::isEmpty() const noexcept {
310 // NOTE: this function does NOT apply critical section, so it can
311 // be safely called from an already established critical section.
312 return m_frontEvt == nullptr;
313}
314//............................................................................
315QEvt const *QEQueue::peekFront() const & {
316 // NOTE: this function does NOT apply critical section, so it can
317 // be safely called from an already established critical section.
318 return m_frontEvt;
319}
320
321} // namespace QP
std::uint16_t getUse() const noexcept
Obtain the number of entries in use in the queue.
Definition qf_qeq.cpp:285
QEQueueCtr m_nFree
Number of free events in the ring buffer.
Definition qequeue.hpp:82
QEQueue() noexcept
Default constructor of QP::QEQueue.
Definition qf_qeq.cpp:48
QEvt const * get(std::uint_fast8_t const qsId) noexcept
Obtain an event from the "raw" thread-safe queue.
Definition qf_qeq.cpp:223
QEvt const * peekFront() const &
Definition qf_qeq.cpp:315
bool isEmpty() const noexcept
Find out if the queue is empty.
Definition qf_qeq.cpp:309
QEvt const ** m_ring
Pointer to the start of the ring buffer.
Definition qequeue.hpp:78
void init(QEvt const **const qSto, std::uint_fast16_t const qLen) noexcept
Initialize the native QF event queue.
Definition qf_qeq.cpp:58
QEQueueCtr m_nMin
Minimum number of free events ever in the ring buffer.
Definition qequeue.hpp:83
std::uint16_t getMin() const noexcept
Obtain the minimum number of free entries ever in the queue (a.k.a. "low-watermark").
Definition qf_qeq.cpp:303
bool post(QEvt const *const e, std::uint_fast16_t const margin, std::uint_fast8_t const qsId) noexcept
Post an event to the "raw" thread-safe event queue (FIFO).
Definition qf_qeq.cpp:84
QEvt const * m_frontEvt
Pointer to event at the front of the queue.
Definition qequeue.hpp:77
QEQueueCtr m_head
Offset to where next event will be inserted into the buffer.
Definition qequeue.hpp:80
std::uint16_t getFree() const noexcept
Obtain the number of free entries still available in the queue.
Definition qf_qeq.cpp:297
QEQueueCtr m_end
Offset of the end of the ring buffer from the start of the buffer.
Definition qequeue.hpp:79
void postLIFO(QEvt const *const e, std::uint_fast8_t const qsId) noexcept
Post an event to the "raw" thread-safe event queue (LIFO).
Definition qf_qeq.cpp:168
QEQueueCtr m_tail
Offset of where next event will be extracted from the buffer.
Definition qequeue.hpp:81
Event class.
Definition qp.hpp:101
std::uint32_t poolNum_
Event pool number of this event.
Definition qp.hpp:104
std::uint32_t refCtr_
Event reference counter.
Definition qp.hpp:105
std::uint32_t sig
Signal of the event (see Event Signal).
Definition qp.hpp:103
constexpr std::uint_fast16_t NO_MARGIN
Special value of margin that causes asserting failure in case event allocation or event posting fails...
Definition qp.hpp:484
QP/C++ Framework namespace.
Definition qequeue.hpp:36
@ QS_QF_EQUEUE_POST_ATTEMPT
attempt to post evt to QEQueue failed
Definition qs.hpp:120
@ QS_QF_EQUEUE_GET_LAST
get the last event from the queue
Definition qs.hpp:82
@ QS_QF_EQUEUE_GET
get an event and queue still not empty
Definition qs.hpp:81
@ QS_QF_EQUEUE_POST_LIFO
an event was posted (LIFO) to a raw queue
Definition qs.hpp:80
@ QS_QF_EQUEUE_POST
an event was posted (FIFO) to a raw queue
Definition qs.hpp:79
void QEvt_refCtr_inc_(QEvt const *const me) noexcept
Internal function to increment the refCtr of a const event.
Definition qf_act.cpp:57
std::uint16_t QEQueueCtr
The data type to store the ring-buffer counters.
Definition qequeue.hpp:41
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:89
QP Framework in C++ internal (package-scope) interface
Sample QP/C++ port.
#define QS_TIME_PRE()
Definition qs.hpp:362
QS (QP/Spy software tracing) internal (package-scope) interface.
#define QS_OBJ_PRE(obj_)
Output pre-formatted object pointer element.
Definition qs_pkg.hpp:89
#define QS_EQC_PRE(ctr_)
Output pre-formatted event queue counter data element.
Definition qs_pkg.hpp:112
#define QS_SIG_PRE(sig_)
Output pre-formatted event signal data element.
Definition qs_pkg.hpp:90
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.hpp:81
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.hpp:77
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.hpp:71
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 Q_INVARIANT_INCRIT(id_, expr_)
Assertion for checking a postcondition (in critical section).
Definition qsafe.h:108
#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