QP/C++ 8.1.2
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 = ((margin == QF::NO_MARGIN)
102 || (nFree > static_cast<QEQueueCtr>(margin)));
103 if (status) { // can post the event?
104
105 // the queue must have a free slot
106 Q_ASSERT_INCRIT(130, nFree != 0U);
107
108#if (QF_MAX_EPOOL > 0U)
109 if (e->poolNum_ != 0U) { // is it a mutable event?
110 QEvt_refCtr_inc_(e); // increment the reference counter
111 }
112#endif // (QF_MAX_EPOOL > 0U)
113
114 --nFree; // one free entry just used up
115 m_nFree = nFree; // update the original
116 if (m_nMin > nFree) { // is this the new minimum?
117 m_nMin = nFree; // update minimum so far
118 }
119
120#ifdef Q_SPY
122 QS_TIME_PRE(); // timestamp
123 QS_SIG_PRE(e->sig); // the signal of the event
124 QS_OBJ_PRE(this); // this queue object
125 QS_2U8_PRE(e->poolNum_, e->refCtr_);
126 QS_EQC_PRE(nFree); // # free entries
127 QS_EQC_PRE(m_nMin); // min # free entries
128 QS_END_PRE()
129#endif // def Q_SPY
130
131 if (m_frontEvt == nullptr) { // is the queue empty?
132 m_frontEvt = e; // deliver event directly
133 }
134 else { // queue was not empty, insert event into the ring-buffer
135 QEQueueCtr head = m_head; // get member into temporary
136 m_ring[head] = e; // insert e into buffer
137
138 if (head == 0U) { // need to wrap the head?
139 head = m_end;
140 }
141 --head; // advance head (counter-clockwise)
142 m_head = head; // update the member original
143 }
144 }
145 else { // event cannot be posted
146#ifdef Q_SPY
148 QS_TIME_PRE(); // timestamp
149 QS_SIG_PRE(e->sig); // the signal of this event
150 QS_OBJ_PRE(this); // this queue object
151 QS_2U8_PRE(e->poolNum_, e->refCtr_);
152 QS_EQC_PRE(nFree); // # free entries
153 QS_EQC_PRE(margin); // margin requested
154 QS_END_PRE()
155#endif // def Q_SPY
156 }
157
158 QF_CRIT_EXIT();
159
160 return status;
161}
162
163//............................................................................
165 QEvt const * const e,
166 std::uint_fast8_t const qsId) noexcept
167{
168#ifndef Q_SPY
169 Q_UNUSED_PAR(qsId);
170#endif
171
174
175 // event e to be posted must be valid
176 Q_REQUIRE_INCRIT(200, e != nullptr);
177
178 QEQueueCtr nFree = m_nFree; // get member into temporary
179
180 // must be able to LIFO-post the event
181 Q_REQUIRE_INCRIT(230, nFree != 0U);
182
183 if (e->poolNum_ != 0U) { // is it a mutable event?
184 QEvt_refCtr_inc_(e); // increment the reference counter
185 }
186
187 --nFree; // one free entry just used up
188 m_nFree = nFree; // update the member original
189
190 if (m_nMin > nFree) { // is this the new minimum?
191 m_nMin = nFree; // update minimum so far
192 }
193
195 QS_TIME_PRE(); // timestamp
196 QS_SIG_PRE(e->sig); // the signal of this event
197 QS_OBJ_PRE(this); // this queue object
198 QS_2U8_PRE(e->poolNum_, e->refCtr_);
199 QS_EQC_PRE(nFree); // # free entries
200 QS_EQC_PRE(m_nMin); // min # free entries
201 QS_END_PRE()
202
203 QEvt const * const frontEvt = m_frontEvt; // get member into temporary
204 m_frontEvt = e; // deliver the event directly to the front
205
206 if (frontEvt != nullptr) { // was the queue NOT empty?
207 QEQueueCtr tail = m_tail; // get member into temporary
208 ++tail;
209 if (tail == m_end) { // need to wrap the tail?
210 tail = 0U; // wrap around
211 }
212 m_tail = tail; // update the member original
213 m_ring[tail] = frontEvt;
214 }
215
216 QF_CRIT_EXIT();
217}
218
219//............................................................................
220QEvt const * QEQueue::get(std::uint_fast8_t const qsId) noexcept {
221#ifndef Q_SPY
222 Q_UNUSED_PAR(qsId);
223#endif
224
227
228 QEvt const * const e = m_frontEvt; // always remove evt from the front
229
230 if (e != nullptr) { // is the queue NOT empty?
231 QEQueueCtr nFree = m_nFree; // get member into temporary
232
233 ++nFree; // one more free event in the queue
234 m_nFree = nFree; // update the # free
235
236 if (nFree <= m_end) { // any events in the ring buffer?
237 // remove event from the tail
238 QEQueueCtr tail = m_tail; // get member into temporary
239
240 QEvt const * const frontEvt = m_ring[tail];
241
242 // the queue must have at least one event (at the front)
243 Q_ASSERT_INCRIT(350, frontEvt != nullptr);
244
246 QS_TIME_PRE(); // timestamp
247 QS_SIG_PRE(e->sig); // the signal of this event
248 QS_OBJ_PRE(this); // this queue object
250 QS_EQC_PRE(nFree); // # free entries
251 QS_END_PRE()
252
253 m_frontEvt = frontEvt; // update the member original
254
255 if (tail == 0U) { // need to wrap the tail?
256 tail = m_end; // wrap around
257 }
258 --tail; // advance the tail (counter-clockwise)
259 m_tail = tail; // update the member original
260 }
261 else {
262 m_frontEvt = nullptr; // queue becomes empty
263
264 // all entries in the queue must be free (+1 for frontEvt)
265 Q_INVARIANT_INCRIT(360, nFree == (m_end + 1U));
266
268 QS_TIME_PRE(); // timestamp
269 QS_SIG_PRE(e->sig); // the signal of this event
270 QS_OBJ_PRE(this); // this queue object
272 QS_END_PRE()
273 }
274 }
275
276 QF_CRIT_EXIT();
277
278 return e;
279}
280
281//............................................................................
282std::uint16_t QEQueue::getUse() const noexcept {
283 // NOTE: this function does NOT apply critical section, so it can
284 // be safely called from an already established critical section.
285 std::uint16_t nUse = 0U;
286 if (m_frontEvt != nullptr) { // queue not empty?
287 nUse = static_cast<std::uint16_t>(
288 static_cast<std::uint16_t>(m_end) + 1U
289 - static_cast<std::uint16_t>(m_nFree));
290 }
291 return nUse;
292}
293//............................................................................
294std::uint16_t QEQueue::getFree() const noexcept {
295 // NOTE: this function does NOT apply critical section, so it can
296 // be safely called from an already established critical section.
297 return static_cast<std::uint16_t>(m_nFree);
298}
299//............................................................................
300std::uint16_t QEQueue::getMin() const noexcept {
301 // NOTE: this function does NOT apply critical section, so it can
302 // be safely called from an already established critical section.
303 return static_cast<std::uint16_t>(m_nMin);
304}
305//............................................................................
306bool QEQueue::isEmpty() const noexcept {
307 // NOTE: this function does NOT apply critical section, so it can
308 // be safely called from an already established critical section.
309 return (m_frontEvt == nullptr);
310}
311//............................................................................
312QEvt const *QEQueue::peekFront() const & {
313 // NOTE: this function does NOT apply critical section, so it can
314 // be safely called from an already established critical section.
315 return m_frontEvt;
316}
317
318} // namespace QP
std::uint16_t getUse() const noexcept
Obtain the number of entries in use in the queue.
Definition qf_qeq.cpp:282
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:220
QEvt const * peekFront() const &
Definition qf_qeq.cpp:312
bool isEmpty() const noexcept
Find out if the queue is empty.
Definition qf_qeq.cpp:306
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:300
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:294
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:164
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:488
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 mark unused parameters of functions.
Definition qp.hpp:89
QP/C++ 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:91
#define QS_EQC_PRE(ctr_)
Output pre-formatted event queue counter data element.
Definition qs_pkg.hpp:114
#define QS_SIG_PRE(sig_)
Output pre-formatted event signal data element.
Definition qs_pkg.hpp:92
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.hpp:83
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.hpp:79
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.hpp:73
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