QP/C++  7.3.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qxk_xthr.cpp
Go to the documentation of this file.
1//$file${src::qxk::qxk_xthr.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qxk::qxk_xthr.cpp}
5//
6// This code has been generated by QM 6.1.1 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// This code is covered by the following QP license:
10// License # : LicenseRef-QL-dual
11// Issued to : Any user of the QP/C++ real-time embedded framework
12// Framework(s) : qpcpp
13// Support ends : 2024-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// Q u a n t u m L e a P s
19// ------------------------
20// Modern Embedded Software
21//
22// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
23//
24// This software is dual-licensed under the terms of the open source GNU
25// General Public License version 3 (or any later version), or alternatively,
26// under the terms of one of the closed source Quantum Leaps commercial
27// licenses.
28//
29// The terms of the open source GNU General Public License version 3
30// can be found at: <www.gnu.org/licenses/gpl-3.0>
31//
32// The terms of the closed source Quantum Leaps commercial licenses
33// can be found at: <www.state-machine.com/licensing>
34//
35// Redistributions in source code must retain this top-level comment block.
36// Plagiarizing this software to sidestep the license obligations is illegal.
37//
38// Contact information:
39// <www.state-machine.com/licensing>
40// <info@state-machine.com>
41//
42//$endhead${src::qxk::qxk_xthr.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.hpp" // QP port
45#include "qp_pkg.hpp" // QP package-scope interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.hpp" // QS port
49 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.hpp" // disable the QS software tracing
52#endif // Q_SPY
53
54// protection against including this source file in a wrong project
55#ifndef QXK_HPP_
56 #error "Source file included in a project NOT based on the QXK kernel"
57#endif // QXK_HPP_
58
59// unnamed namespace for local definitions with internal linkage
60namespace {
61Q_DEFINE_THIS_MODULE("qxk_xthr")
62} // unnamed namespace
63
64//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
65// Check for the minimum required QP version
66#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
67#error qpcpp version 7.3.0 or higher required
68#endif
69//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70
71//$define${QXK::QXThread} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
72namespace QP {
73
74//${QXK::QXThread} ...........................................................
75
76//${QXK::QXThread::QXThread} .................................................
78 QXThreadHandler const handler,
79 std::uint_fast8_t const tickRate) noexcept
80 : QActive(Q_STATE_CAST(handler)),
81 m_timeEvt(this, static_cast<QSignal>(QXK::DELAY_SIG), tickRate)
82{
83 m_state.act = nullptr; // mark as extended thread
84}
85
86//${QXK::QXThread::init} .....................................................
88 void const * const e,
89 std::uint_fast8_t const qsId)
90{
91 Q_UNUSED_PAR(e);
92 Q_UNUSED_PAR(qsId);
93 Q_ERROR_INCRIT(110);
94}
95
96//${QXK::QXThread::dispatch} .................................................
98 QEvt const * const e,
99 std::uint_fast8_t const qsId)
100{
101 Q_UNUSED_PAR(e);
102 Q_UNUSED_PAR(qsId);
103 Q_ERROR_INCRIT(120);
104}
105
106//${QXK::QXThread::delay} ....................................................
107bool QXThread::delay(QTimeEvtCtr const nTicks) noexcept {
110 QF_MEM_SYS();
111
113
114 // precondition, this function:
115 // - must NOT be called from an ISR;
116 // - number of ticks cannot be zero
117 // - be called from an extended thread;
118 // - the thread must NOT be already blocked on any object.
120 && (nTicks != 0U)
121 && (thr != nullptr)
122 && (thr->m_temp.obj == nullptr));
123 // - the thread must NOT be holding a scheduler lock.
125
126 // remember the blocking object
127 thr->m_temp.obj = QXK_PTR_CAST_(QMState const*, &thr->m_timeEvt);
128 thr->teArm_(static_cast<enum_t>(QXK::DELAY_SIG), nTicks);
129 thr->block_();
130
131 QF_MEM_APP();
132 QF_CRIT_EXIT();
133 QF_CRIT_EXIT_NOP(); // BLOCK here
134
135 // after unblocking...
137 QF_MEM_SYS();
138
139 // the blocking object must be the time event
140 Q_ASSERT_INCRIT(890, thr->m_temp.obj
141 == QXK_PTR_CAST_(QMState*, &thr->m_timeEvt));
142 thr->m_temp.obj = nullptr; // clear
143
144 QF_MEM_APP();
145 QF_CRIT_EXIT();
146
147 // signal of zero means that the time event was posted without
148 // being canceled.
149 return (thr->m_timeEvt.sig == 0U);
150}
151
152//${QXK::QXThread::delayCancel} ..............................................
153bool QXThread::delayCancel() noexcept {
156 QF_MEM_SYS();
157
158 bool wasArmed;
160 wasArmed = teDisarm_();
161 unblock_();
162 }
163 else {
164 wasArmed = false;
165 }
166 QF_MEM_APP();
167 QF_CRIT_EXIT();
168
169 return wasArmed;
170}
171
172//${QXK::QXThread::queueGet} .................................................
173QEvt const * QXThread::queueGet(QTimeEvtCtr const nTicks) noexcept {
176 QF_MEM_SYS();
177
178 QXThread * const thr = QXTHREAD_CAST_(QXK_priv_.curr);
179
180 // precondition, this function:
181 // - must NOT be called from an ISR;
182 // - be called from an extended thread;
183 // - the thread must NOT be already blocked on any object.
185 && (thr != nullptr)
186 && (thr->m_temp.obj == nullptr));
187 // - the thread must NOT be holding a scheduler lock.
189
190 // is the queue empty?
191 if (thr->m_eQueue.m_frontEvt == nullptr) {
192
193 // remember the blocking object (the thread's queue)
194 thr->m_temp.obj = QXK_PTR_CAST_(QMState*, &thr->m_eQueue);
195
196 thr->teArm_(static_cast<enum_t>(QXK::TIMEOUT_SIG), nTicks);
198 static_cast<std::uint_fast8_t>(thr->m_prio));
199 #ifndef Q_UNSAFE
201 #endif
202
203 static_cast<void>(QXK_sched_()); // synchronous scheduling
204
205 QF_MEM_APP();
206 QF_CRIT_EXIT();
207 QF_CRIT_EXIT_NOP(); // BLOCK here
208
209 // after unblocking...
211 QF_MEM_SYS();
212
213 // the blocking object must be this queue
214 Q_ASSERT_INCRIT(510, thr->m_temp.obj ==
215 QXK_PTR_CAST_(QMState *, &thr->m_eQueue));
216 thr->m_temp.obj = nullptr; // clear
217 }
218
219 // is the queue not empty?
220 QEvt const *e;
221 if (thr->m_eQueue.m_frontEvt != nullptr) {
222 e = thr->m_eQueue.m_frontEvt; // remove from the front
223 QEQueueCtr const nFree = thr->m_eQueue.m_nFree + 1U;
224 thr->m_eQueue.m_nFree = nFree; // update the # free
225
226 // any events in the ring buffer?
227 if (nFree <= thr->m_eQueue.m_end) {
228
229 // remove event from the tail
230 thr->m_eQueue.m_frontEvt =
231 thr->m_eQueue.m_ring[thr->m_eQueue.m_tail];
232 if (thr->m_eQueue.m_tail == 0U) {
233 thr->m_eQueue.m_tail = thr->m_eQueue.m_end; // wrap
234 }
235 // advance the tail (counter clockwise)
236 thr->m_eQueue.m_tail = (thr->m_eQueue.m_tail - 1U);
237
238 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET, thr->m_prio)
239 QS_TIME_PRE_(); // timestamp
240 QS_SIG_PRE_(e->sig); // the signal of this event
241 QS_OBJ_PRE_(&thr); // this active object
242 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
243 QS_EQC_PRE_(nFree); // # free entries
244 QS_END_PRE_()
245 }
246 else {
247 thr->m_eQueue.m_frontEvt = nullptr; // empty queue
248
249 // all entries in the queue must be free (+1 for fronEvt)
250 Q_ASSERT_INCRIT(520, nFree == (thr->m_eQueue.m_end + 1U));
251
252 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET_LAST, thr->m_prio)
253 QS_TIME_PRE_(); // timestamp
254 QS_SIG_PRE_(e->sig); // the signal of this event
255 QS_OBJ_PRE_(&thr); // this active object
256 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
257 QS_END_PRE_()
258 }
259 }
260 else { // the queue is still empty -- the timeout must have fired
261 e = nullptr;
262 }
263 QF_MEM_APP();
264 QF_CRIT_EXIT();
265
266 return e;
267}
268
269//${QXK::QXThread::block_} ...................................................
270void QXThread::block_() const noexcept {
271 // NOTE: must be called IN a critical section
272
274
275 QXK_priv_.readySet.remove(static_cast<std::uint_fast8_t>(m_prio));
276 #ifndef Q_UNSAFE
278 #endif
279
280 static_cast<void>(QXK_sched_()); // schedule other threads
281}
282
283//${QXK::QXThread::unblock_} .................................................
284void QXThread::unblock_() const noexcept {
285 // NOTE: must be called IN a critical section
286
287 QXK_priv_.readySet.insert(static_cast<std::uint_fast8_t>(m_prio));
288 #ifndef Q_UNSAFE
290 #endif
291
292 if ((!QXK_ISR_CONTEXT_()) // not inside ISR?
293 && (QActive::registry_[0] != nullptr)) // kernel started?
294 {
295 static_cast<void>(QXK_sched_()); // schedule other threads
296 }
297}
298
299//${QXK::QXThread::timeout_} .................................................
300void QXThread::timeout_(QActive * const act) {
301 // NOTE: must be called IN a critical section
302
303 // the private time event is now disarmed and not in any queue,
304 // so it is safe to change its signal. The signal of 0 means
305 // that the time event has expired.
306 QXTHREAD_CAST_(act)->m_timeEvt.sig = 0U;
307
308 QXTHREAD_CAST_(act)->unblock_();
309}
310
311//${QXK::QXThread::teArm_} ...................................................
313 enum_t const sig,
314 QTimeEvtCtr const nTicks) noexcept
315{
316 // NOTE: must be called IN a critical section
317
318 // precondition:
319 // - the time event must be unused
320 Q_REQUIRE_INCRIT(700, m_timeEvt.m_ctr == 0U);
321
322 m_timeEvt.sig = static_cast<QSignal>(sig);
323
324 if (nTicks != QXTHREAD_NO_TIMEOUT) {
325 m_timeEvt.m_ctr = static_cast<QTimeEvtCtr>(nTicks);
326 m_timeEvt.m_interval = 0U;
327
328 // is the time event unlinked?
329 // NOTE: For the duration of a single clock tick of the specified tick
330 // rate a time event can be disarmed and yet still linked in the list,
331 // because un-linking is performed exclusively in QTimeEvt::tickX().
332 if (static_cast<std::uint8_t>(m_timeEvt.refCtr_ & TE_IS_LINKED) == 0U)
333 {
334 std::uint_fast8_t const tickRate =
335 static_cast<std::uint_fast8_t>(m_timeEvt.refCtr_);
336 Q_ASSERT_INCRIT(710, tickRate < QF_MAX_TICK_RATE);
337
338 // mark as linked
339 m_timeEvt.refCtr_ = static_cast<std::uint8_t>(
340 m_timeEvt.refCtr_ | TE_IS_LINKED);
341
342 // The time event is initially inserted into the separate
343 // "freshly armed" list based on timeEvtHead_[tickRate].act.
344 // Only later, inside QTimeEvt::tick(), the "freshly armed"
345 // list is appended to the main list of armed time events based on
346 // timeEvtHead_[tickRate].next. Again, this is to keep any
347 // changes to the main list exclusively inside QTimeEvt::tick().
348 m_timeEvt.m_next
350 QTimeEvt::timeEvtHead_[tickRate].m_act);
351 QTimeEvt::timeEvtHead_[tickRate].m_act = &m_timeEvt;
352 }
353 }
354}
355
356//${QXK::QXThread::teDisarm_} ................................................
357bool QXThread::teDisarm_() noexcept {
358 // NOTE: must be called IN a critical section
359
360 bool wasArmed;
361 // is the time evt running?
362 if (m_timeEvt.m_ctr != 0U) {
363 wasArmed = true;
364 // schedule removal from list
365 m_timeEvt.m_ctr = 0U;
366 }
367 // the time event was already automatically disarmed
368 else {
369 wasArmed = false;
370 }
371 return wasArmed;
372}
373
374} // namespace QP
375//$enddef${QXK::QXThread} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:724
QACTIVE_EQUEUE_TYPE m_eQueue
Definition qp.hpp:738
static QActive * registry_[QF_MAX_ACTIVE+1U]
Definition qp.hpp:750
std::uint8_t m_prio
Definition qp.hpp:726
friend class QXThread
Definition qp.hpp:757
QAsmAttr m_temp
Definition qp.hpp:223
Event class.
Definition qp.hpp:139
std::uint_fast8_t getPoolNum_() const noexcept
Definition qp.hpp:167
std::uint8_t volatile refCtr_
Definition qp.hpp:142
QSignal sig
Definition qp.hpp:141
void update_(QPSet *const dis) const noexcept
Definition qp.hpp:681
void remove(std::uint_fast8_t const n) noexcept
Definition qp.hpp:658
void insert(std::uint_fast8_t const n) noexcept
Definition qp.hpp:646
Time Event class.
Definition qp.hpp:955
static QTimeEvt timeEvtHead_[QF_MAX_TICK_RATE]
Definition qp.hpp:963
QTimeEvtCtr volatile m_ctr
Definition qp.hpp:959
void * m_act
Definition qp.hpp:958
eXtended (blocking) thread of the QXK preemptive kernel
Definition qxk.hpp:88
static QEvt const * queueGet(QTimeEvtCtr const nTicks=QXTHREAD_NO_TIMEOUT) noexcept
Definition qxk_xthr.cpp:173
bool teDisarm_() noexcept
Definition qxk_xthr.cpp:357
static void timeout_(QActive *const act)
Definition qxk_xthr.cpp:300
QTimeEvt m_timeEvt
Definition qxk.hpp:90
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Definition qxk_xthr.cpp:97
void init(void const *const e, std::uint_fast8_t const qsId) override
Definition qxk_xthr.cpp:87
void block_() const noexcept
Definition qxk_xthr.cpp:270
bool delayCancel() noexcept
Definition qxk_xthr.cpp:153
void unblock_() const noexcept
Definition qxk_xthr.cpp:284
void teArm_(enum_t const sig, QTimeEvtCtr const nTicks) noexcept
Definition qxk_xthr.cpp:312
static bool delay(QTimeEvtCtr const nTicks) noexcept
Definition qxk_xthr.cpp:107
QP::QPSet readySet_dis
Definition qxk.hpp:195
QP::QActive *volatile curr
Definition qxk.hpp:186
std::uint_fast8_t volatile lockHolder
Definition qxk.hpp:191
QP::QPSet readySet
Definition qxk.hpp:192
@ TIMEOUT_SIG
Definition qxk.hpp:335
@ DELAY_SIG
Definition qxk.hpp:334
QP/C++ framework.
Definition qequeue.hpp:50
std::uint16_t QSignal
Definition qp.hpp:130
constexpr std::uint8_t TE_IS_LINKED
Definition qp_pkg.hpp:88
void(*)(QXThread *const me) QXThreadHandler
Definition qp.hpp:186
std::uint32_t QTimeEvtCtr
Definition qp.hpp:588
std::uint16_t QEQueueCtr
Definition qequeue.hpp:55
constexpr QTimeEvtCtr QXTHREAD_NO_TIMEOUT
Definition qxk.hpp:59
@ QS_QF_ACTIVE_GET_LAST
AO got an event and its queue is empty.
Definition qs.hpp:92
@ QS_QF_ACTIVE_GET
AO got an event and its queue is not empty.
Definition qs.hpp:91
int enum_t
Definition qp.hpp:108
#define QF_MEM_APP()
Definition qp.hpp:1276
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:541
#define Q_STATE_CAST(handler_)
Definition qp.hpp:493
#define QF_MEM_SYS()
Definition qp.hpp:1271
#define QF_CRIT_EXIT_NOP()
Definition qp.hpp:1266
#define QF_MAX_TICK_RATE
Internal (package scope) QP/C++ interface.
Sample QP/C++ port.
#define QXK_ISR_CONTEXT_()
Check if the code executes in the ISR context.
Definition qp_port.hpp:137
#define QS_TIME_PRE_()
Definition qs.hpp:473
QS/C++ package-scope interface.
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 QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define Q_ERROR_INCRIT(id_)
Definition qsafe.h:76
#define QF_CRIT_STAT
Definition qsafe.h:54
QXK_Attr QXK_priv_
Definition qxk.cpp:174
#define QXTHREAD_CAST_(ptr_)
Definition qxk.hpp:305
#define QXK_PTR_CAST_(type_, ptr_)
Definition qxk.hpp:308
std::uint_fast8_t QXK_sched_() noexcept
Definition qxk.cpp:177
State object for the QP::QMsm class (QM State Machine).
Definition qp.hpp:189
QMState const * obj
Definition qp.hpp:208