QP/C  7.3.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qxk_xthr.c
Go to the documentation of this file.
1//$file${src::qxk::qxk_xthr.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qxk::qxk_xthr.c}
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) : qpc
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.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.h" // QP port
45#include "qp_pkg.h" // 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.h" // QS port
49 #include "qs_pkg.h" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.h" // disable the QS software tracing
52#endif // Q_SPY
53
54// protection against including this source file in a wrong project
55#ifndef QXK_H_
56 #error "Source file included in a project NOT based on the QXK kernel"
57#endif // QXK_H_
58
59Q_DEFINE_THIS_MODULE("qxk_xthr")
60
61//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
62// Check for the minimum required QP version
63#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
64#error qpc version 7.3.0 or higher required
65#endif
66//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67
68//$define${QXK::QXThread} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
69
70//${QXK::QXThread} ...........................................................
71QXThread const * QXThread_dummy;
72
73//${QXK::QXThread::ctor} .....................................................
74//! @public @memberof QXThread
75void QXThread_ctor(QXThread * const me,
76 QXThreadHandler const handler,
77 uint_fast8_t const tickRate)
78{
79 union QAsmAttr tmp;
80 tmp.thr = handler;
81 QActive_ctor(&me->super, tmp.fun); // superclass' ctor
82
83 me->super.super.state.act = Q_ACTION_CAST(0); // mark as extended thread
84
85 // instantiate the time-event member in the QXThread class
86 QTimeEvt_ctorX(&me->timeEvt, &me->super,
87 (enum_t)QXK_DELAY_SIG, tickRate);
88}
89
90//${QXK::QXThread::delay} ....................................................
91//! @public @memberof QXThread
92bool QXThread_delay(QTimeEvtCtr const nTicks) {
95 QF_MEM_SYS();
96
97 QXThread * const thr = QXTHREAD_CAST_(QXK_priv_.curr);
98
99 // precondition, this function:
100 // - must NOT be called from an ISR;
101 // - number of ticks cannot be zero
102 // - be called from an extended thread;
103 // - the thread must NOT be already blocked on any object.
105 && (nTicks != 0U)
106 && (thr != (QXThread *)0)
107 && (thr->super.super.temp.obj == (QMState *)0));
108 // - the thread must NOT be holding a scheduler lock.
110 QXK_priv_.lockHolder != (uint_fast8_t)thr->super.prio);
111
112 // remember the blocking object
113 thr->super.super.temp.obj = QXK_PTR_CAST_(QMState const*, &thr->timeEvt);
114 QXThread_teArm_(thr, (enum_t)QXK_DELAY_SIG, nTicks);
115 QXThread_block_(thr);
116
117 QF_MEM_APP();
118 QF_CRIT_EXIT();
119 QF_CRIT_EXIT_NOP(); // BLOCK here
120
121 // after unblocking...
123 QF_MEM_SYS();
124
125 // the blocking object must be the time event
126 Q_ASSERT_INCRIT(890, thr->super.super.temp.obj
127 == QXK_PTR_CAST_(QMState const*, &thr->timeEvt));
128 thr->super.super.temp.obj = (QMState *)0; // clear
129
130 QF_MEM_APP();
131 QF_CRIT_EXIT();
132
133 // signal of zero means that the time event was posted without
134 // being canceled.
135 return thr->timeEvt.super.sig == 0U;
136}
137
138//${QXK::QXThread::delayCancel} ..............................................
139//! @public @memberof QXThread
140bool QXThread_delayCancel(QXThread * const me) {
143 QF_MEM_SYS();
144
145 bool wasArmed;
146 if (me->super.super.temp.obj == QXK_PTR_CAST_(QMState*, &me->timeEvt)) {
147 wasArmed = QXThread_teDisarm_(me);
148 QXThread_unblock_(me);
149 }
150 else {
151 wasArmed = false;
152 }
153 QF_MEM_APP();
154 QF_CRIT_EXIT();
155
156 return wasArmed;
157}
158
159//${QXK::QXThread::queueGet} .................................................
160//! @static @public @memberof QXThread
161QEvt const * QXThread_queueGet(QTimeEvtCtr const nTicks) {
164 QF_MEM_SYS();
165
166 QXThread * const thr = QXTHREAD_CAST_(QXK_priv_.curr);
167
168 // precondition, this function:
169 // - must NOT be called from an ISR;
170 // - be called from an extended thread;
171 // - the thread must NOT be already blocked on any object.
173 && (thr != (QXThread *)0)
174 && (thr->super.super.temp.obj == (QMState *)0));
175 // - the thread must NOT be holding a scheduler lock.
177 QXK_priv_.lockHolder != (uint_fast8_t)thr->super.prio);
178
179 // is the queue empty?
180 if (thr->super.eQueue.frontEvt == (QEvt *)0) {
181
182 // remember the blocking object (the thread's queue)
183 thr->super.super.temp.obj
184 = QXK_PTR_CAST_(QMState const*, &thr->super.eQueue);
185
186 QXThread_teArm_(thr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
187 QPSet_remove(&QXK_priv_.readySet, (uint_fast8_t)thr->super.prio);
188 #ifndef Q_UNSAFE
189 QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
190 #endif
191
192 (void)QXK_sched_(); // schedule other threads
193
194 QF_MEM_APP();
195 QF_CRIT_EXIT();
196 QF_CRIT_EXIT_NOP(); // BLOCK here
197
198 // after unblocking...
200 QF_MEM_SYS();
201
202 // the blocking object must be this queue
203 Q_ASSERT_INCRIT(510, thr->super.super.temp.obj
204 == QXK_PTR_CAST_(QMState const*, &thr->super.eQueue));
205 thr->super.super.temp.obj = (QMState *)0; // clear
206 }
207
208 // is the queue not empty?
209 QEvt const *e;
210 if (thr->super.eQueue.frontEvt != (QEvt *)0) {
211 e = thr->super.eQueue.frontEvt; // remove from the front
212 QEQueueCtr const nFree= thr->super.eQueue.nFree + 1U;
213 thr->super.eQueue.nFree = nFree; // update the # free
214
215 // any events in the ring buffer?
216 if (nFree <= thr->super.eQueue.end) {
217
218 // remove event from the tail
219 thr->super.eQueue.frontEvt =
220 thr->super.eQueue.ring[thr->super.eQueue.tail];
221 if (thr->super.eQueue.tail == 0U) { // need to wrap?
222 thr->super.eQueue.tail = thr->super.eQueue.end; // wrap
223 }
224 --thr->super.eQueue.tail;
225
226 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET, thr->super.prio)
227 QS_TIME_PRE_(); // timestamp
228 QS_SIG_PRE_(e->sig); // the signal of this event
229 QS_OBJ_PRE_(&thr->super); // this active object
230 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_); // poolNum & refCtr
231 QS_EQC_PRE_(nFree); // # free entries
232 QS_END_PRE_()
233 }
234 else {
235 thr->super.eQueue.frontEvt = (QEvt *)0; // empty queue
236
237 // all entries in the queue must be free (+1 for fronEvt)
238 Q_ASSERT_INCRIT(520, nFree == (thr->super.eQueue.end + 1U));
239
240 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET_LAST, thr->super.prio)
241 QS_TIME_PRE_(); // timestamp
242 QS_SIG_PRE_(e->sig); // the signal of this event
243 QS_OBJ_PRE_(&thr->super); // this active object
244 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_); // poolNum & refCtr
245 QS_END_PRE_()
246 }
247 }
248 else { // the queue is still empty -- the timeout must have fired
249 e = (QEvt *)0;
250 }
251 QF_MEM_APP();
252 QF_CRIT_EXIT();
253
254 return e;
255}
256
257//${QXK::QXThread::block_} ...................................................
258//! @private @memberof QXThread
259void QXThread_block_(QXThread const * const me) {
260 // NOTE: must be called IN a critical section
261
263 QXK_priv_.lockHolder != (uint_fast8_t)me->super.prio);
264
265 QPSet_remove(&QXK_priv_.readySet, (uint_fast8_t)me->super.prio);
266 #ifndef Q_UNSAFE
267 QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
268 #endif
269
270 (void)QXK_sched_(); // schedule other threads
271}
272
273//${QXK::QXThread::unblock_} .................................................
274//! @private @memberof QXThread
275void QXThread_unblock_(QXThread const * const me) {
276 // NOTE: must be called IN a critical section
277
278 QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)me->super.prio);
279 #ifndef Q_UNSAFE
280 QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
281 #endif
282
283 if ((!QXK_ISR_CONTEXT_()) // not inside ISR?
284 && (QActive_registry_[0] != (QActive *)0)) // kernel started?
285 {
286 (void)QXK_sched_(); // schedule other threads
287 }
288}
289
290//${QXK::QXThread::timeout_} .................................................
291//! @private @memberof QXThread
292void QXThread_timeout_(QActive * const act) {
293 // NOTE: must be called IN a critical section
294
295 // the private time event is now disarmed and not in any queue,
296 // so it is safe to change its signal. The signal of 0 means
297 // that the time event has expired.
298 QXTHREAD_CAST_(act)->timeEvt.super.sig = 0U;
299
300 QXThread_unblock_(QXTHREAD_CAST_(act));
301}
302
303//${QXK::QXThread::teArm_} ...................................................
304//! @private @memberof QXThread
305void QXThread_teArm_(QXThread * const me,
306 enum_t const sig,
307 QTimeEvtCtr const nTicks)
308{
309 // NOTE: must be called IN a critical section
310
311 // precondition:
312 // - the time event must be unused
313 Q_REQUIRE_INCRIT(700, me->timeEvt.ctr == 0U);
314
315 me->timeEvt.super.sig = (QSignal)sig;
316
317 if (nTicks != QXTHREAD_NO_TIMEOUT) {
318 me->timeEvt.ctr = (QTimeEvtCtr)nTicks;
319 me->timeEvt.interval = 0U;
320
321 // is the time event unlinked?
322 // NOTE: For the duration of a single clock tick of the specified tick
323 // rate a time event can be disarmed and yet still linked in the list,
324 // because un-linking is performed exclusively in QTimeEvt_tick_().
325 if ((me->timeEvt.super.refCtr_ & QTE_IS_LINKED) == 0U) {
326 uint_fast8_t const tickRate
327 = ((uint_fast8_t)me->timeEvt.super.refCtr_ & QTE_TICK_RATE);
328 Q_ASSERT_INCRIT(710, tickRate < QF_MAX_TICK_RATE);
329
330 // mark as linked
332
333 // The time event is initially inserted into the separate
334 // "freshly armed" list based on QTimeEvt_timeEvtHead_[tickRate].act.
335 // Only later, inside the QTimeEvt_tick_() function, the "freshly
336 // armed" list is appended to the main list of armed time events
337 // based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
338 // to keep any changes to the main list exclusively inside
339 // QTimeEvt_tick_().
340 me->timeEvt.next
341 = QXK_PTR_CAST_(QTimeEvt*, QTimeEvt_timeEvtHead_[tickRate].act);
342 QTimeEvt_timeEvtHead_[tickRate].act = &me->timeEvt;
343 }
344 }
345}
346
347//${QXK::QXThread::teDisarm_} ................................................
348//! @private @memberof QXThread
349bool QXThread_teDisarm_(QXThread * const me) {
350 // NOTE: must be called IN a critical section
351
352 bool wasArmed;
353 // is the time evt running?
354 if (me->timeEvt.ctr != 0U) {
355 wasArmed = true;
356 me->timeEvt.ctr = 0U; // schedule removal from list
357 }
358 // the time event was already automatically disarmed
359 else {
360 wasArmed = false;
361 }
362 return wasArmed;
363}
364//$enddef${QXK::QXThread} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
uint16_t QEQueueCtr
Definition qequeue.h:53
QActive * QActive_registry_[QF_MAX_ACTIVE+1U]
Definition qf_act.c:64
#define QF_MEM_APP()
Definition qp.h:1284
uint16_t QSignal
Definition qp.h:131
#define Q_ACTION_CAST(action_)
Definition qp.h:529
uint32_t QTimeEvtCtr
Definition qp.h:633
#define QF_MEM_SYS()
Definition qp.h:1279
int enum_t
Definition qp.h:109
#define QF_CRIT_EXIT_NOP()
Definition qp.h:1265
void(* QXThreadHandler)(struct QXThread *const me)
Definition qp.h:236
#define QF_MAX_TICK_RATE
Definition qp_config.h:130
Internal (package scope) QP/C interface.
#define QTE_IS_LINKED
Definition qp_pkg.h:82
#define QTE_TICK_RATE
Definition qp_pkg.h:84
Sample QP/C port.
#define QXK_ISR_CONTEXT_()
Check if the code executes in the ISR context.
Definition qp_port.h:131
#define QS_TIME_PRE_()
Definition qs.h:450
@ QS_QF_ACTIVE_GET
AO got an event and its queue is not empty.
Definition qs.h:99
@ QS_QF_ACTIVE_GET_LAST
AO got an event and its queue is empty.
Definition qs.h:100
QS/C package-scope interface.
Sample QS/C port.
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 QF_CRIT_STAT
Definition qsafe.h:54
#define QXTHREAD_NO_TIMEOUT
Definition qxk.h:66
#define QXTHREAD_CAST_(ptr_)
Definition qxk.h:366
#define QXK_PTR_CAST_(type_, ptr_)
Definition qxk.h:363
@ QXK_TIMEOUT_SIG
Definition qxk.h:392
@ QXK_DELAY_SIG
Definition qxk.h:391
Active object class (based on the QHsm implementation strategy)
Definition qp.h:800
uint8_t prio
Definition qp.h:805
QAsm super
Definition qp.h:802
union QAsmAttr temp
Definition qp.h:289
union QAsmAttr state
Definition qp.h:286
Event class.
Definition qp.h:147
uint8_t volatile refCtr_
Definition qp.h:156
QSignal sig
Definition qp.h:151
State object for the QMsm class (QM State Machine).
Definition qp.h:239
Time Event class.
Definition qp.h:969
struct QTimeEvt *volatile next
Definition qp.h:976
QEvt super
Definition qp.h:971
QTimeEvtCtr interval
Definition qp.h:985
QTimeEvtCtr volatile ctr
Definition qp.h:982
eXtended (blocking) thread of the QXK preemptive kernel
Definition qxk.h:145
QActive super
Definition qxk.h:147
QTimeEvt timeEvt
Definition qxk.h:152
Attribute of for the QAsm class (Abstract State Machine).
Definition qp.h:264
QXThreadHandler thr
Definition qp.h:267
struct QMState const * obj
Definition qp.h:269
QActionHandler act
Definition qp.h:266