QP/C++  7.0.1
Real-Time Embedded Framework
qf_qeq.cpp
Go to the documentation of this file.
1//============================================================================
2// QP/C++ Real-Time Embedded Framework (RTEF)
3// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
4//
5// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
6//
7// This software is dual-licensed under the terms of the open source GNU
8// General Public License version 3 (or any later version), or alternatively,
9// under the terms of one of the closed source Quantum Leaps commercial
10// licenses.
11//
12// The terms of the open source GNU General Public License version 3
13// can be found at: <www.gnu.org/licenses/gpl-3.0>
14//
15// The terms of the closed source Quantum Leaps commercial licenses
16// can be found at: <www.state-machine.com/licensing>
17//
18// Redistributions in source code must retain this top-level comment block.
19// Plagiarizing this software to sidestep the license obligations is illegal.
20//
21// Contact information:
22// <www.state-machine.com>
23// <info@state-machine.com>
24//============================================================================
30
31#define QP_IMPL // this is QP implementation
32#include "qf_port.hpp" // QF port
33#include "qf_pkg.hpp" // QF package-scope interface
34#include "qassert.h" // QP embedded systems-friendly assertions
35#ifdef Q_SPY // QS software tracing enabled?
36 #include "qs_port.hpp" // QS port
37 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
38#else
39 #include "qs_dummy.hpp" // disable the QS software tracing
40#endif // Q_SPY
41
42// unnamed namespace for local definitions with internal linkage
43namespace {
44
46
47} // unnamed namespace
48
49namespace QP {
50
51//============================================================================
55QEQueue::QEQueue(void) noexcept
56 : m_frontEvt(nullptr),
57 m_ring(nullptr),
58 m_end(0U),
59 m_head(0U),
60 m_tail(0U),
61 m_nFree(0U),
62 m_nMin(0U)
63{}
64
65//============================================================================
81void QEQueue::init(QEvt const *qSto[],
82 std::uint_fast16_t const qLen) noexcept
83{
84 m_frontEvt = nullptr; // no events in the queue
85 m_ring = &qSto[0];
86 m_end = static_cast<QEQueueCtr>(qLen);
87 if (qLen > 0U) {
88 m_head = 0U;
89 m_tail = 0U;
90 }
91 m_nFree = static_cast<QEQueueCtr>(qLen + 1U); //+1 for frontEvt
92 m_nMin = m_nFree;
93}
94
95//============================================================================
119bool QEQueue::post(QEvt const * const e,
120 std::uint_fast16_t const margin,
121 std::uint_fast8_t const qs_id) noexcept
122{
124 Q_REQUIRE_ID(200, e != nullptr);
125
127 QF_CRIT_E_();
128 QEQueueCtr nFree = m_nFree; // temporary to avoid UB for volatile access
129
130 // margin available?
131 bool status;
132 if (((margin == QF_NO_MARGIN) && (nFree > 0U))
133 || (nFree > static_cast<QEQueueCtr>(margin)))
134 {
135 // is it a dynamic event?
136 if (e->poolId_ != 0U) {
137 QF_EVT_REF_CTR_INC_(e); // increment the reference counter
138 }
139
140 --nFree; // one free entry just used up
141 m_nFree = nFree; // update the volatile
142 if (m_nMin > nFree) {
143 m_nMin = nFree; // update minimum so far
144 }
145
147 QS_TIME_PRE_(); // timestamp
148 QS_SIG_PRE_(e->sig); // the signal of this event
149 QS_OBJ_PRE_(this); // this queue object
150 QS_2U8_PRE_(e->poolId_, e->refCtr_);// pool Id & refCtr of the evt
151 QS_EQC_PRE_(nFree); // number of free entries
152 QS_EQC_PRE_(m_nMin); // min number of free entries
154
155 // is the queue empty?
156 if (m_frontEvt == nullptr) {
157 m_frontEvt = e; // deliver event directly
158 }
159 // queue is not empty, leave event in the ring-buffer
160 else {
161 // insert event into the ring buffer (FIFO)
162 m_ring[m_head] = e; // insert e into buffer
163
164 // need to wrap?
165 if (m_head == 0U) {
166 m_head = m_end; // wrap around
167 }
168 m_head = (m_head - 1U);
169 }
170 status = true; // event posted successfully
171 }
172 else {
175 Q_ASSERT_CRIT_(210, margin != QF_NO_MARGIN);
176
178 QS_TIME_PRE_(); // timestamp
179 QS_SIG_PRE_(e->sig); // the signal of this event
180 QS_OBJ_PRE_(this); // this queue object
181 QS_2U8_PRE_(e->poolId_, e->refCtr_);// pool Id & refCtr of the evt
182 QS_EQC_PRE_(nFree); // number of free entries
183 QS_EQC_PRE_(margin); // margin requested
185
186 status = false; // event not posted
187 }
188 QF_CRIT_X_();
189
190 static_cast<void>(qs_id); // unused parameter, if Q_SPY not defined
191
192 return status;
193}
194
195//============================================================================
217void QEQueue::postLIFO(QEvt const * const e,
218 std::uint_fast8_t const qs_id) noexcept
219{
220 static_cast<void>(qs_id); // unused parameter, if Q_SPY not defined
221
223 QF_CRIT_E_();
224 QEQueueCtr nFree = m_nFree; // temporary to avoid UB for volatile access
225
227 Q_REQUIRE_CRIT_(300, nFree != 0U);
228
229 // is it a dynamic event?
230 if (e->poolId_ != 0U) {
231 QF_EVT_REF_CTR_INC_(e); // increment the reference counter
232 }
233
234 --nFree; // one free entry just used up
235 m_nFree = nFree; // update the volatile
236 if (m_nMin > nFree) {
237 m_nMin = nFree; // update minimum so far
238 }
239
241 QS_TIME_PRE_(); // timestamp
242 QS_SIG_PRE_(e->sig); // the signal of this event
243 QS_OBJ_PRE_(this); // this queue object
244 QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & refCtr of the evt
245 QS_EQC_PRE_(nFree); // number of free entries
246 QS_EQC_PRE_(m_nMin); // min number of free entries
248
249 QEvt const * const frontEvt = m_frontEvt; // read volatile into temporary
250 m_frontEvt = e; // deliver event directly to the front of the queue
251
252 // was the queue not empty?
253 if (frontEvt != nullptr) {
254 m_tail = (m_tail + 1U);
255 if (m_tail == m_end) { // need to wrap the tail?
256 m_tail = 0U; // wrap around
257 }
258 m_ring[m_tail] = frontEvt; // buffer the old front evt
259 }
260 QF_CRIT_X_();
261}
262
263//============================================================================
281QEvt const *QEQueue::get(std::uint_fast8_t const qs_id) noexcept {
282 static_cast<void>(qs_id); // unused parameter, if Q_SPY not defined
283
285 QF_CRIT_E_();
286 QEvt const * const e = m_frontEvt; // always remove evt from the front
287
288 // is the queue not empty?
289 if (e != nullptr) {
290 QEQueueCtr const nFree = m_nFree + 1U;
291 m_nFree = nFree; // upate the number of free
292
293 // any events in the the ring buffer?
294 if (nFree <= m_end) {
295 m_frontEvt = m_ring[m_tail]; // remove from the tail
296 if (m_tail == 0U) { // need to wrap?
297 m_tail = m_end; // wrap around
298 }
299 m_tail = (m_tail - 1U);
300
302 QS_TIME_PRE_(); // timestamp
303 QS_SIG_PRE_(e->sig); // the signal of this event
304 QS_OBJ_PRE_(this); // this queue object
306 QS_EQC_PRE_(nFree); // # free entries
308 }
309 else {
310 m_frontEvt = nullptr; // queue becomes empty
311
312 // all entries in the queue must be free (+1 for fronEvt)
313 Q_ASSERT_CRIT_(410, nFree == (m_end + 1U));
314
316 QS_TIME_PRE_(); // timestamp
317 QS_SIG_PRE_(e->sig); // the signal of this event
318 QS_OBJ_PRE_(this); // this queue object
321 }
322 }
323 QF_CRIT_X_();
324
325 return e;
326}
327
328} // namespace QP
QEvt const * get(std::uint_fast8_t const qs_id) noexcept
"raw" thread-safe QF event queue implementation for the Last-In-First-Out (LIFO) event posting.
Definition: qf_qeq.cpp:281
void init(QEvt const *qSto[], std::uint_fast16_t const qLen) noexcept
Initializes the native QF event queue.
Definition: qf_qeq.cpp:81
void postLIFO(QEvt const *const e, std::uint_fast8_t const qs_id) noexcept
"raw" thread-safe QF event queue implementation for the First-In-First-Out (FIFO) event posting.
Definition: qf_qeq.cpp:217
bool post(QEvt const *const e, std::uint_fast16_t const margin, std::uint_fast8_t const qs_id) noexcept
"raw" thread-safe QF event queue implementation for the event posting (FIFO).
Definition: qf_qeq.cpp:119
QEQueue(void) noexcept
public default constructor
Definition: qf_qeq.cpp:55
namespace associated with the QP/C++ framework
Definition: exa_native.dox:1
std::uint8_t QEQueueCtr
The data type to store the ring-buffer counters based on the macro #QF_EQUEUE_CTR_SIZE.
Definition: qequeue.hpp:63
std::uint_fast16_t const QF_NO_MARGIN
special value of margin that causes asserting failure in case event allocation or event posting fails
Definition: qf.hpp:618
@ QS_QF_EQUEUE_GET_LAST
get the last event from the queue
Definition: qs.hpp:84
@ QS_QF_EQUEUE_POST_ATTEMPT
attempt to post an evt to QEQueue failed
Definition: qs.hpp:122
@ QS_QF_EQUEUE_POST_LIFO
an event was posted (LIFO) to a raw queue
Definition: qs.hpp:82
@ QS_QF_EQUEUE_GET
get an event and queue still not empty
Definition: qs.hpp:83
@ QS_QF_EQUEUE_POST
an event was posted (FIFO) to a raw queue
Definition: qs.hpp:81
void QF_EVT_REF_CTR_INC_(QEvt const *const e) noexcept
increment the refCtr_ of an event e
Definition: qf_pkg.hpp:142
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:102
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:252
Internal (package scope) QF/C++ interface.
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.hpp:48
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.hpp:86
#define QF_CRIT_X_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.hpp:69
#define Q_REQUIRE_CRIT_(id_, test_)
Definition: qf_pkg.hpp:93
#define QF_CRIT_E_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.hpp:58
#define QS_TIME_PRE_()
Definition: qs.hpp:225
Internal (package scope) QS/C++ interface.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Internal QS macro to begin a predefined QS record without critical section.
Definition: qs_pkg.hpp:130
#define QS_OBJ_PRE_(obj_)
Internal QS macro to output object pointer data element.
Definition: qs_pkg.hpp:178
#define QS_END_NOCRIT_PRE_()
Internal QS macro to end a predefiend QS record without critical section.
Definition: qs_pkg.hpp:138
#define QS_2U8_PRE_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs_pkg.hpp:161
#define QS_EQC_PRE_(ctr_)
Internal QS macro to output an unformatted event queue counter data element.
Definition: qs_pkg.hpp:208
QEvt base class.
Definition: qep.hpp:191
QSignal sig
signal of the event instance
Definition: qep.hpp:192
std::uint8_t volatile refCtr_
reference counter
Definition: qep.hpp:194
std::uint8_t poolId_
pool ID (0 for static event)
Definition: qep.hpp:193