QP/C++  8.0.0
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_qeq.cpp
Go to the documentation of this file.
1//$file${src::qf::qf_qeq.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qf::qf_qeq.cpp}
5//
6// This code has been generated by QM 7.0.0 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
10//
11// Q u a n t u m L e a P s
12// ------------------------
13// Modern Embedded Software
14//
15// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
16//
17// The QP/C++ software is dual-licensed under the terms of the open-source
18// GNU General Public License (GPL) or under the terms of one of the closed-
19// source Quantum Leaps commercial licenses.
20//
21// Redistributions in source code must retain this top-level comment block.
22// Plagiarizing this software to sidestep the license obligations is illegal.
23//
24// NOTE:
25// The GPL does NOT permit the incorporation of this code into proprietary
26// programs. Please contact Quantum Leaps for commercial licensing options,
27// which expressly supersede the GPL and are designed explicitly for
28// closed-source distribution.
29//
30// Quantum Leaps contact information:
31// <www.state-machine.com/licensing>
32// <info@state-machine.com>
33//
34//$endhead${src::qf::qf_qeq.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35#define QP_IMPL // this is QP implementation
36#include "qp_port.hpp" // QP port
37#include "qp_pkg.hpp" // QP package-scope interface
38#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
39#ifdef Q_SPY // QS software tracing enabled?
40 #include "qs_port.hpp" // QS port
41 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
42#else
43 #include "qs_dummy.hpp" // disable the QS software tracing
44#endif // Q_SPY
45
46// unnamed namespace for local definitions with internal linkage
47namespace {
48Q_DEFINE_THIS_MODULE("qf_qeq")
49} // unnamed namespace
50
51//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
52// Check for the minimum required QP version
53#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
54#error qpcpp version 7.3.0 or higher required
55#endif
56//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
57//$define${QF::QEQueue} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
58namespace QP {
59
60//${QF::QEQueue} .............................................................
61
62//${QF::QEQueue::init} .......................................................
64 QEvt const * qSto[],
65 std::uint_fast16_t const qLen) noexcept
66{
69 QF_MEM_SYS();
70
71 #if (QF_EQUEUE_CTR_SIZE == 1U)
72 Q_REQUIRE_INCRIT(100, qLen < 0xFFU);
73 #endif
74
75 m_frontEvt = nullptr; // no events in the queue
76 m_ring = &qSto[0];
77 m_end = static_cast<QEQueueCtr>(qLen);
78 if (qLen > 0U) {
79 m_head = 0U;
80 m_tail = 0U;
81 }
82 m_nFree = static_cast<QEQueueCtr>(qLen + 1U); //+1 for frontEvt
83 m_nMin = m_nFree;
84
85 #ifndef Q_UNSAFE
86 m_frontEvt_dis = static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(m_frontEvt));
87 m_head_dis = static_cast<QEQueueCtr>(~m_head);
88 m_tail_dis = static_cast<QEQueueCtr>(~m_tail);
89 m_nFree_dis = static_cast<QEQueueCtr>(~m_nFree);
90 #endif
91
92 QF_MEM_APP();
94}
95
96//${QF::QEQueue::post} .......................................................
98 QEvt const * const e,
99 std::uint_fast16_t const margin,
100 std::uint_fast8_t const qsId) noexcept
101{
102 #ifndef Q_SPY
103 Q_UNUSED_PAR(qsId);
104 #endif
105
108 QF_MEM_SYS();
109
110 Q_REQUIRE_INCRIT(200, e != nullptr);
111 Q_INVARIANT_INCRIT(201, e->verify_());
112
113 QEQueueCtr tmp = m_nFree; // get volatile into temporary
114 #ifndef Q_UNSAFE
115 QEQueueCtr dis = static_cast<QEQueueCtr>(~m_nFree_dis);
116 Q_INVARIANT_INCRIT(201, tmp == dis);
117 #endif // ndef Q_UNSAFE
118
119 // test-probe#1 for faking queue overflow
122 tmp = 0U; // fake no free events
123 )
124
125 // required margin available?
126 bool status;
127 if (((margin == QF::NO_MARGIN) && (tmp > 0U))
128 || (tmp > static_cast<QEQueueCtr>(margin)))
129 {
130 // is it a mutable event?
131 if (e->getPoolNum_() != 0U) {
132 QEvt_refCtr_inc_(e); // increment the reference counter
133 }
134
135 --tmp; // one free entry just used up
136
137 m_nFree = tmp; // update the original
138 #ifndef Q_UNSAFE
139 m_nFree_dis = static_cast<QEQueueCtr>(~tmp);
140 #endif // ndef Q_UNSAFE
141
142 if (m_nMin > tmp) {
143 m_nMin = tmp; // update minimum so far
144 }
145
146 QS_BEGIN_PRE(QS_QF_EQUEUE_POST, qsId)
147 QS_TIME_PRE(); // timestamp
148 QS_SIG_PRE(e->sig); // the signal of the event
149 QS_OBJ_PRE(this); // this queue object
150 QS_2U8_PRE(e->getPoolNum_(), e->refCtr_);
151 QS_EQC_PRE(tmp); // # free entries
152 QS_EQC_PRE(m_nMin); // min # free entries
153 QS_END_PRE()
154
155 if (m_frontEvt == nullptr) { // is the queue empty?
156 m_frontEvt = e; // deliver event directly
157 #ifndef Q_UNSAFE
158 Q_INVARIANT_INCRIT(211, m_frontEvt_dis
159 == static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(nullptr)));
160 m_frontEvt_dis = static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(e));
161 #endif // ndef Q_UNSAFE
162 }
163 else { // queue was not empty, insert event into the ring-buffer
164 tmp = m_head; // get volatile into temporary
165 #ifndef Q_UNSAFE
166 dis = static_cast<QEQueueCtr>(~m_head_dis);
167 Q_INVARIANT_INCRIT(212, tmp == dis);
168 #endif // ndef Q_UNSAFE
169 m_ring[tmp] = e; // insert e into buffer
170
171 if (tmp == 0U) { // need to wrap the head?
172 tmp = m_end;
173 }
174 --tmp; // advance head (counter-clockwise)
175
176 m_head = tmp; // update the original
177 #ifndef Q_UNSAFE
178 m_head_dis = static_cast<QEQueueCtr>(~tmp);
179 #endif // ndef Q_UNSAFE
180 }
181 status = true; // event posted successfully
182 }
183 else { // event cannot be posted
184 // dropping events must be acceptable
185 Q_ASSERT_INCRIT(210, margin != QF::NO_MARGIN);
186
187 QS_BEGIN_PRE(QS_QF_EQUEUE_POST_ATTEMPT, qsId)
188 QS_TIME_PRE(); // timestamp
189 QS_SIG_PRE(e->sig); // the signal of this event
190 QS_OBJ_PRE(this); // this queue object
191 QS_2U8_PRE(e->getPoolNum_(), e->refCtr_);
192 QS_EQC_PRE(tmp); // # free entries
193 QS_EQC_PRE(margin); // margin requested
194 QS_END_PRE()
195
196 status = false; // event not posted
197 }
198
199 QF_MEM_APP();
200 QF_CRIT_EXIT();
201
202 return status;
203}
204
205//${QF::QEQueue::postLIFO} ...................................................
207 QEvt const * const e,
208 std::uint_fast8_t const qsId) noexcept
209{
210 #ifndef Q_SPY
211 Q_UNUSED_PAR(qsId);
212 #endif
213
216 QF_MEM_SYS();
217
218 Q_REQUIRE_INCRIT(300, e != nullptr);
219 Q_INVARIANT_INCRIT(301, e->verify_());
220
221 QEQueueCtr tmp = m_nFree; // get volatile into temporary
222 #ifndef Q_UNSAFE
223 QEQueueCtr dis = static_cast<QEQueueCtr>(~m_nFree_dis);
224 Q_INVARIANT_INCRIT(301, tmp == dis);
225 #endif // ndef Q_UNSAFE
226
227 // test-probe#1 for faking queue overflow
230 tmp = 0U; // fake no free events
231 )
232
233 // must be able to LIFO-post the event
234 Q_REQUIRE_INCRIT(310, tmp != 0U);
235
236 if (e->getPoolNum_() != 0U) { // is it a mutable event?
237 QEvt_refCtr_inc_(e); // increment the reference counter
238 }
239
240 --tmp; // one free entry just used up
241
242 m_nFree = tmp; // update the original
243 #ifndef Q_UNSAFE
244 m_nFree_dis = static_cast<QEQueueCtr>(~tmp);
245 #endif // ndef Q_UNSAFE
246
247 if (m_nMin > tmp) {
248 m_nMin = tmp; // update minimum so far
249 }
250
251 QS_BEGIN_PRE(QS_QF_EQUEUE_POST_LIFO, qsId)
252 QS_TIME_PRE(); // timestamp
253 QS_SIG_PRE(e->sig); // the signal of this event
254 QS_OBJ_PRE(this); // this queue object
255 QS_2U8_PRE(e->getPoolNum_(), e->refCtr_);
256 QS_EQC_PRE(tmp); // # free entries
257 QS_EQC_PRE(m_nMin); // min # free entries
258 QS_END_PRE()
259
260 QEvt const * const frontEvt = m_frontEvt; // read into temporary
261 m_frontEvt = e; // deliver the event directly to the front
262 #ifndef Q_UNSAFE
263 m_frontEvt_dis = static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(e));
264 #endif // ndef Q_UNSAFE
265
266 if (frontEvt != nullptr) { // was the queue NOT empty?
267 tmp = m_tail; // get volatile into temporary;
268 #ifndef Q_UNSAFE
269 dis = static_cast<QEQueueCtr>(~m_tail_dis);
270 Q_INVARIANT_INCRIT(311, tmp == dis);
271 #endif // ndef Q_UNSAFE
272 ++tmp;
273 if (tmp == m_end) { // need to wrap the tail?
274 tmp = 0U; // wrap around
275 }
276 m_tail = tmp;
277 #ifndef Q_UNSAFE
278 m_tail_dis = static_cast<QEQueueCtr>(~tmp);
279 #endif
280 m_ring[tmp] = frontEvt;
281 }
282
283 QF_MEM_APP();
284 QF_CRIT_EXIT();
285}
286
287//${QF::QEQueue::get} ........................................................
288QEvt const * QEQueue::get(std::uint_fast8_t const qsId) noexcept {
289 #ifndef Q_SPY
290 Q_UNUSED_PAR(qsId);
291 #endif
292
295 QF_MEM_SYS();
296
297 QEvt const * const e = m_frontEvt; // always remove evt from the front
298 #ifndef Q_UNSAFE
300 == static_cast<std::uintptr_t>(~m_frontEvt_dis));
301 #endif // ndef Q_UNSAFE
302
303 if (e != nullptr) { // was the queue not empty?
304 QEQueueCtr tmp = m_nFree; // get volatile into temporary
305 #ifndef Q_UNSAFE
306 QEQueueCtr const dis = static_cast<QEQueueCtr>(~m_nFree_dis);
307 Q_INVARIANT_INCRIT(412, tmp == dis);
308 #endif // ndef Q_UNSAFE
309
310 ++tmp; // one more free event in the queue
311
312 m_nFree = tmp; // update the # free
313 #ifndef Q_UNSAFE
314 m_nFree_dis = static_cast<QEQueueCtr>(~tmp);
315 #endif // ndef Q_UNSAFE
316
317 // any events in the ring buffer?
318 if (tmp <= m_end) {
319
320 QS_BEGIN_PRE(QS_QF_EQUEUE_GET, qsId)
321 QS_TIME_PRE(); // timestamp
322 QS_SIG_PRE(e->sig); // the signal of this event
323 QS_OBJ_PRE(this); // this queue object
325 QS_EQC_PRE(tmp); // # free entries
326 QS_END_PRE()
327
328 tmp = m_tail; // get volatile into temporary
329 QEvt const * const frontEvt = m_ring[tmp];
330 #ifndef Q_UNSAFE
331 Q_ASSERT_INCRIT(421, frontEvt != nullptr);
332 m_frontEvt_dis =
333 static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(frontEvt));
334 #endif // ndef Q_UNSAFE
335 m_frontEvt = frontEvt; // update the original
336
337 if (tmp == 0U) { // need to wrap the tail?
338 tmp = m_end;
339 }
340 --tmp; // advance the tail (counter-clockwise)
341 m_tail = tmp; // update the original
342 #ifndef Q_UNSAFE
343 m_tail_dis = static_cast<QEQueueCtr>(~tmp);
344 #endif // ndef Q_UNSAFE
345 }
346 else {
347 m_frontEvt = nullptr; // queue becomes empty
348 #ifndef Q_UNSAFE
349 m_frontEvt_dis =
350 static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(nullptr));
351 #endif // ndef Q_UNSAFE
352
353 // all entries in the queue must be free (+1 for frontEvt)
354 Q_INVARIANT_INCRIT(440, tmp == (m_end + 1U));
355
356 QS_BEGIN_PRE(QS_QF_EQUEUE_GET_LAST, qsId)
357 QS_TIME_PRE(); // timestamp
358 QS_SIG_PRE(e->sig); // the signal of this event
359 QS_OBJ_PRE(this); // this queue object
361 QS_END_PRE()
362 }
363 }
364
365 QF_MEM_APP();
366 QF_CRIT_EXIT();
367
368 return e;
369}
370
371} // namespace QP
372//$enddef${QF::QEQueue} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
QEvt const * get(std::uint_fast8_t const qsId) noexcept
Definition qf_qeq.cpp:288
void init(QEvt const *qSto[], std::uint_fast16_t const qLen) noexcept
Definition qf_qeq.cpp:63
bool post(QEvt const *const e, std::uint_fast16_t const margin, std::uint_fast8_t const qsId) noexcept
Definition qf_qeq.cpp:97
void postLIFO(QEvt const *const e, std::uint_fast8_t const qsId) noexcept
Definition qf_qeq.cpp:206
Event class.
Definition qp.hpp:131
QSignal sig
Signal of the event (see Event Signal)
Definition qp.hpp:133
std::uint8_t volatile refCtr_
Event reference counter.)
Definition qp.hpp:135
std::uint_fast8_t getPoolNum_() const noexcept
Internal function to get the event pool-number of the given event.
Definition qp.hpp:159
constexpr std::uint_fast16_t NO_MARGIN
Definition qp.hpp:1086
QP/C++ framework.
Definition qequeue.hpp:42
void QEvt_refCtr_inc_(QEvt const *const e) noexcept
Definition qp_pkg.hpp:81
std::uint16_t QEQueueCtr
Definition qequeue.hpp:47
#define QF_MEM_APP()
Definition qp.hpp:1322
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:498
#define QF_MEM_SYS()
Definition qp.hpp:1317
Internal (package scope) QP/C++ interface.
#define Q_PTR2UINT_CAST_(ptr_)
Internal helper macro to cast pointers to integers.
Definition qp_pkg.hpp:72
Sample QP/C++ port.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.hpp:158
#define QS_EQC_PRE(ctr_)
Definition qs_dummy.hpp:160
#define QS_SIG_PRE(sig_)
Definition qs_dummy.hpp:156
#define QS_TIME_PRE()
Definition qs_dummy.hpp:155
#define QS_2U8_PRE(data1_, data2_)
Definition qs_dummy.hpp:152
#define QS_TEST_PROBE_DEF(fun_)
Definition qs_dummy.hpp:78
#define QS_TEST_PROBE_ID(id_, code_)
Definition qs_dummy.hpp:80
#define QS_END_PRE()
Definition qs_dummy.hpp:150
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.hpp:149
QS/C++ port to a 32-bit CPU, generic C++ compiler.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:72
#define Q_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:154
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define QF_CRIT_STAT
Definition qsafe.h:54