QP/C++  7.3.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qxk_sema.cpp
Go to the documentation of this file.
1//$file${src::qxk::qxk_sema.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qxk::qxk_sema.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_sema.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_sema")
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::QXSemaphore} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
72namespace QP {
73
74//${QXK::QXSemaphore} ........................................................
75
76//${QXK::QXSemaphore::init} ..................................................
78 std::uint_fast8_t const count,
79 std::uint_fast8_t const max_count) noexcept
80{
83 QF_MEM_SYS();
84
85 Q_REQUIRE_INCRIT(100, (count <= max_count)
86 && (0U < max_count) && (max_count <= 0xFFU));
87
88 m_count = static_cast<std::uint8_t>(count);
89 m_max_count = static_cast<std::uint8_t>(max_count);
90 m_waitSet.setEmpty();
91
92 QF_MEM_APP();
94}
95
96//${QXK::QXSemaphore::wait} ..................................................
97bool QXSemaphore::wait(QTimeEvtCtr const nTicks) noexcept {
100 QF_MEM_SYS();
101
102 QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_priv_.curr);
103
104 // precondition, this function:
105 // - must NOT be called from an ISR;
106 // - the semaphore must be initialized
107 // - be called from an extended thread;
108 // - the thread must NOT be already blocked on any object.
110 && (m_max_count > 0U)
111 && (curr != nullptr)
112 && (curr->m_temp.obj == nullptr));
113 // - the thread must NOT be holding a scheduler lock.
115
116 bool taken = true; // assume that the semaphore will be signaled
117 if (m_count > 0U) {
118 m_count = m_count - 1U; // semaphore taken: decrement the count
119
120 QS_BEGIN_PRE_(QS_SEM_TAKE, curr->m_prio)
121 QS_TIME_PRE_(); // timestamp
122 QS_OBJ_PRE_(this); // this semaphore
123 QS_2U8_PRE_(curr->m_prio, m_count);
124 QS_END_PRE_()
125 }
126 else { // semaphore not available -- BLOCK the thread
127 std::uint_fast8_t const p =
128 static_cast<std::uint_fast8_t>(curr->m_prio);
129 // remove the curr prio from the ready set (will block)
130 // and insert to the waiting set on this semaphore
132 #ifndef Q_UNSAFE
134 #endif
135 m_waitSet.insert(p);
136
137 // remember the blocking object (this semaphore)
138 curr->m_temp.obj = QXK_PTR_CAST_(QMState*, this);
139 curr->teArm_(static_cast<enum_t>(QXK::TIMEOUT_SIG), nTicks);
140
141 QS_BEGIN_PRE_(QS_SEM_BLOCK, curr->m_prio)
142 QS_TIME_PRE_(); // timestamp
143 QS_OBJ_PRE_(this); // this semaphore
144 QS_2U8_PRE_(curr->m_prio, m_count);
145 QS_END_PRE_()
146
147 // schedule the next thread if multitasking started
148 static_cast<void>(QXK_sched_()); // schedule other threads
149
150 QF_MEM_APP();
151 QF_CRIT_EXIT();
152 QF_CRIT_EXIT_NOP(); // BLOCK here !!!
153
154 QF_CRIT_ENTRY(); // AFTER unblocking...
155 QF_MEM_SYS();
156
157 // the blocking object must be this semaphore
158 Q_ASSERT_INCRIT(240, curr->m_temp.obj
159 == QXK_PTR_CAST_(QMState*, this));
160
161 // did the blocking time-out? (signal of zero means that it did)
162 if (curr->m_timeEvt.sig == 0U) {
163 if (m_waitSet.hasElement(p)) { // still waiting?
164 m_waitSet.remove(p); // remove unblocked thread
165 taken = false; // the semaphore was NOT taken
166 }
167 }
168 else { // blocking did NOT time out
169 // the thread must NOT be waiting on this semaphore
170 Q_ASSERT_INCRIT(250, !m_waitSet.hasElement(p));
171 }
172 curr->m_temp.obj = nullptr; // clear blocking obj.
173 }
174 QF_MEM_APP();
175 QF_CRIT_EXIT();
176
177 return taken;
178}
179
180//${QXK::QXSemaphore::tryWait} ...............................................
181bool QXSemaphore::tryWait() noexcept {
184 QF_MEM_SYS();
185
186 // precondition:
187 // - the semaphore must be initialized
188 Q_REQUIRE_INCRIT(300, m_max_count > 0U);
189
190 #ifdef Q_SPY
191 QActive const * const curr = QXK_PTR_CAST_(QActive*, QXK_priv_.curr);
192 #endif // Q_SPY
193
194 bool taken;
195 // is the semaphore available?
196 if (m_count > 0U) {
197 m_count = m_count - 1U; // semaphore signaled: decrement
198 taken = true;
199
200 QS_BEGIN_PRE_(QS_SEM_TAKE, curr->m_prio)
201 QS_TIME_PRE_(); // timestamp
202 QS_OBJ_PRE_(this); // this semaphore
203 QS_2U8_PRE_(curr->m_prio, m_count);
204 QS_END_PRE_()
205 }
206 else { // the semaphore is NOT available (would block)
207 taken = false;
208
209 QS_BEGIN_PRE_(QS_SEM_BLOCK_ATTEMPT, curr->m_prio)
210 QS_TIME_PRE_(); // timestamp
211 QS_OBJ_PRE_(this); // this semaphore
212 QS_2U8_PRE_(curr->m_prio, m_count);
213 QS_END_PRE_()
214 }
215 QF_MEM_APP();
216 QF_CRIT_EXIT();
217
218 return taken;
219}
220
221//${QXK::QXSemaphore::signal} ................................................
222bool QXSemaphore::signal() noexcept {
223 bool signaled = true; // assume that the semaphore will be signaled
224
227 QF_MEM_SYS();
228
229 // precondition:
230 // - the semaphore must be initialized
231 Q_REQUIRE_INCRIT(400, m_max_count > 0U);
232
233 // any threads blocked on this semaphore?
234 if (m_waitSet.notEmpty()) {
235 // find the highest-prio. thread waiting on this semaphore
236 std::uint_fast8_t const p = m_waitSet.findMax();
237 QXThread * const thr =
239
240 // assert that the thread:
241 // - must be registered in QF;
242 // - must be extended; and
243 // - must be blocked on this semaphore;
244 Q_ASSERT_INCRIT(410, (thr != nullptr)
245 && (thr->m_osObject != nullptr)
246 && (thr->m_temp.obj
247 == QXK_PTR_CAST_(QMState*, this)));
248
249 // disarm the internal time event
250 static_cast<void>(thr->teDisarm_());
251
252 // make the thread ready to run and remove from the wait-list
254 #ifndef Q_UNSAFE
256 #endif
257 m_waitSet.remove(p);
258
259 QS_BEGIN_PRE_(QS_SEM_TAKE, thr->m_prio)
260 QS_TIME_PRE_(); // timestamp
261 QS_OBJ_PRE_(this); // this semaphore
262 QS_2U8_PRE_(thr->m_prio, m_count);
263 QS_END_PRE_()
264
265 if (!QXK_ISR_CONTEXT_()) { // not inside ISR?
266 static_cast<void>(QXK_sched_()); // schedule other threads
267 }
268 }
269 else if (m_count < m_max_count) {
270 m_count = m_count + 1U; // semaphore signaled: increment
271
272 QS_BEGIN_PRE_(QS_SEM_SIGNAL, 0U)
273 QS_TIME_PRE_(); // timestamp
274 QS_OBJ_PRE_(this); // this semaphore
275 QS_2U8_PRE_(0U, m_count);
276 QS_END_PRE_()
277 }
278 else {
279 signaled = false; // semaphore NOT signaled
280 }
281 QF_MEM_APP();
282 QF_CRIT_EXIT();
283
284 return signaled;
285}
286
287} // namespace QP
288//$enddef${QXK::QXSemaphore} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:724
static QActive * registry_[QF_MAX_ACTIVE+1U]
Definition qp.hpp:750
std::uint8_t m_prio
Definition qp.hpp:726
QACTIVE_OS_OBJ_TYPE m_osObject
Definition qp.hpp:734
QAsmAttr m_temp
Definition qp.hpp:223
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
std::uint_fast8_t findMax() const noexcept
Definition qp.hpp:670
void insert(std::uint_fast8_t const n) noexcept
Definition qp.hpp:646
bool notEmpty() const noexcept
Definition qp.hpp:630
void init(std::uint_fast8_t const count, std::uint_fast8_t const max_count=0xFFU) noexcept
Definition qxk_sema.cpp:77
bool signal() noexcept
Definition qxk_sema.cpp:222
QPSet m_waitSet
Definition qxk.hpp:144
std::uint8_t m_count
Definition qxk.hpp:145
bool tryWait() noexcept
Definition qxk_sema.cpp:181
std::uint8_t m_max_count
Definition qxk.hpp:146
bool wait(QTimeEvtCtr const nTicks=QXTHREAD_NO_TIMEOUT) noexcept
Definition qxk_sema.cpp:97
eXtended (blocking) thread of the QXK preemptive kernel
Definition qxk.hpp:88
bool teDisarm_() noexcept
Definition qxk_xthr.cpp:357
QTimeEvt m_timeEvt
Definition qxk.hpp:90
void teArm_(enum_t const sig, QTimeEvtCtr const nTicks) noexcept
Definition qxk_xthr.cpp:312
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
QP/C++ framework.
Definition qequeue.hpp:50
std::uint32_t QTimeEvtCtr
Definition qp.hpp:588
@ QS_SEM_SIGNAL
a semaphore was signaled
Definition qs.hpp:176
@ QS_SEM_TAKE
a semaphore was taken by a thread
Definition qs.hpp:174
@ QS_SEM_BLOCK
a semaphore blocked a thread
Definition qs.hpp:175
@ QS_SEM_BLOCK_ATTEMPT
a semaphore blocked was attempted
Definition qs.hpp:177
int enum_t
Definition qp.hpp:108
#define QF_MEM_APP()
Definition qp.hpp:1276
#define QF_MEM_SYS()
Definition qp.hpp:1271
#define QF_CRIT_EXIT_NOP()
Definition qp.hpp:1266
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 QF_CRIT_STAT
Definition qsafe.h:54
QXK_Attr QXK_priv_
Definition qxk.cpp:174
#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