QP/C++  7.0.1
Real-Time Embedded Framework
qf_ps.cpp
Go to the documentation of this file.
1//$file${src::qf::qf_ps.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qf::qf_ps.cpp}
5//
6// This code has been generated by QM 5.2.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 : 2023-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
19//
20// This software is dual-licensed under the terms of the open source GNU
21// General Public License version 3 (or any later version), or alternatively,
22// under the terms of one of the closed source Quantum Leaps commercial
23// licenses.
24//
25// The terms of the open source GNU General Public License version 3
26// can be found at: <www.gnu.org/licenses/gpl-3.0>
27//
28// The terms of the closed source Quantum Leaps commercial licenses
29// can be found at: <www.state-machine.com/licensing>
30//
31// Redistributions in source code must retain this top-level comment block.
32// Plagiarizing this software to sidestep the license obligations is illegal.
33//
34// Contact information:
35// <www.state-machine.com/licensing>
36// <info@state-machine.com>
37//
38//$endhead${src::qf::qf_ps.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45
46#define QP_IMPL // this is QP implementation
47#include "qf_port.hpp" // QF port
48#include "qf_pkg.hpp" // QF package-scope interface
49#include "qassert.h" // QP embedded systems-friendly assertions
50#ifdef Q_SPY // QS software tracing enabled?
51 #include "qs_port.hpp" // QS port
52 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
53#else
54 #include "qs_dummy.hpp" // disable the QS software tracing
55#endif // Q_SPY
56
57// unnamed namespace for local definitions with internal linkage
58namespace {
60} // unnamed namespace
61
62//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
63// Check for the minimum required QP version
64#if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
65#error qpcpp version 6.9.0 or higher required
66#endif
67//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68
69//$define${QF::QActive::subscrList_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
70namespace QP {
72
73} // namespace QP
74//$enddef${QF::QActive::subscrList_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75//$define${QF::QActive::maxPubSignal_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
76namespace QP {
78
79} // namespace QP
80//$enddef${QF::QActive::maxPubSignal_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81
82//$define${QF::QActive::psInit} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
83namespace QP {
84
85//${QF::QActive::psInit} .....................................................
87 QSubscrList * const subscrSto,
88 enum_t const maxSignal) noexcept
89{
90 subscrList_ = subscrSto;
91 maxPubSignal_ = maxSignal;
92 QF::bzero(subscrSto, static_cast<unsigned>(maxSignal)
93 * sizeof(QSubscrList));
94}
95
96} // namespace QP
97//$enddef${QF::QActive::psInit} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
98//$define${QF::QActive::publish_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
99namespace QP {
100
101//${QF::QActive::publish_} ...................................................
103 QEvt const * const e,
104 void const * const sender,
105 std::uint_fast8_t const qs_id) noexcept
106{
107 Q_UNUSED_PAR(sender); // when Q_SPY not defined
108 Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
109
111 Q_REQUIRE_ID(100, static_cast<enum_t>(e->sig) < maxPubSignal_);
112
114 QF_CRIT_E_();
115
117 QS_TIME_PRE_(); // the timestamp
118 QS_OBJ_PRE_(sender); // the sender object
119 QS_SIG_PRE_(e->sig); // the signal of the event
120 QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & refCtr of the evt
122
123 // is it a dynamic event?
124 if (e->poolId_ != 0U) {
125 // NOTE: The reference counter of a dynamic event is incremented to
126 // prevent premature recycling of the event while the multicasting
127 // is still in progress. At the end of the function, the garbage
128 // collector step (QF::gc()) decrements the reference counter and
129 // recycles the event if the counter drops to zero. This covers the
130 // case when the event was published without any subscribers.
131 //
133 }
134
135 // make a local, modifiable copy of the subscriber list
136 QPSet subscrList = subscrList_[e->sig];
137 QF_CRIT_X_();
138
139 if (subscrList.notEmpty()) { // any subscribers?
140 // the highest-prio subscriber
141 std::uint_fast8_t p = subscrList.findMax();
143
144 QF_SCHED_LOCK_(p); // lock the scheduler up to prio 'p'
145 do { // loop over all subscribers */
146 // the prio of the AO must be registered with the framework
147 Q_ASSERT_ID(210, registry_[p] != nullptr);
148
149 // POST() asserts internally if the queue overflows
150 registry_[p]->POST(e, sender);
151
152 subscrList.rmove(p); // remove the handled subscriber
153 if (subscrList.notEmpty()) { // still more subscribers?
154 p = subscrList.findMax(); // the highest-prio subscriber
155 }
156 else {
157 p = 0U; // no more subscribers
158 }
159 } while (p != 0U);
160 QF_SCHED_UNLOCK_(); // unlock the scheduler
161 }
162
163 // The following garbage collection step decrements the reference counter
164 // and recycles the event if the counter drops to zero. This covers both
165 // cases when the event was published with or without any subscribers.
166 //
167 QF::gc(e);
168}
169
170} // namespace QP
171//$enddef${QF::QActive::publish_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
172//$define${QF::QActive::subscribe} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
173namespace QP {
174
175//${QF::QActive::subscribe} ..................................................
176void QActive::subscribe(enum_t const sig) const noexcept {
177 std::uint_fast8_t const p = static_cast<std::uint_fast8_t>(m_prio);
178
179 Q_REQUIRE_ID(300, (Q_USER_SIG <= sig)
180 && (sig < maxPubSignal_)
181 && (0U < p) && (p <= QF_MAX_ACTIVE)
182 && (registry_[p] == this));
183
185 QF_CRIT_E_();
186
188 QS_TIME_PRE_(); // timestamp
189 QS_SIG_PRE_(sig); // the signal of this event
190 QS_OBJ_PRE_(this); // this active object
192
193 subscrList_[sig].insert(p); // insert into subscriber-list
194 QF_CRIT_X_();
195}
196
197} // namespace QP
198//$enddef${QF::QActive::subscribe} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199//$define${QF::QActive::unsubscribe} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
200namespace QP {
201
202//${QF::QActive::unsubscribe} ................................................
203void QActive::unsubscribe(enum_t const sig) const noexcept {
204 std::uint_fast8_t const p = static_cast<std::uint_fast8_t>(m_prio);
205
207 // be registered with the framework
208 Q_REQUIRE_ID(400, (Q_USER_SIG <= sig)
209 && (sig < maxPubSignal_)
210 && (0U < p) && (p <= QF_MAX_ACTIVE)
211 && (registry_[p] == this));
212
214 QF_CRIT_E_();
215
217 QS_TIME_PRE_(); // timestamp
218 QS_SIG_PRE_(sig); // the signal of this event
219 QS_OBJ_PRE_(this); // this active object
221
222 subscrList_[sig].rmove(p); // remove from subscriber-list
223
224 QF_CRIT_X_();
225}
226
227} // namespace QP
228//$enddef${QF::QActive::unsubscribe} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
229//$define${QF::QActive::unsubscribeAll} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
230namespace QP {
231
232//${QF::QActive::unsubscribeAll} .............................................
233void QActive::unsubscribeAll() const noexcept {
234 std::uint_fast8_t const p = static_cast<std::uint_fast8_t>(m_prio);
235
236 Q_REQUIRE_ID(500, (0U < p) && (p <= QF_MAX_ACTIVE)
237 && (registry_[p] == this));
238
239 for (enum_t sig = Q_USER_SIG; sig < maxPubSignal_; ++sig) {
241 QF_CRIT_E_();
242 if (subscrList_[sig].hasElement(p)) {
243 subscrList_[sig].rmove(p);
244
246 QS_TIME_PRE_(); // timestamp
247 QS_SIG_PRE_(sig); // the signal of this event
248 QS_OBJ_PRE_(this); // this active object
250
251 }
252 QF_CRIT_X_();
253
254 // prevent merging critical sections
256 }
257}
258
259} // namespace QP
260//$enddef${QF::QActive::unsubscribeAll} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
std::uint8_t m_prio
QF priority (1..QF_MAX_ACTIVE) of this active object.
Definition: qf.hpp:367
static enum_t maxPubSignal_
The maximum published signal (the size of the subscrList_ array)
Definition: qf.hpp:399
static void psInit(QSubscrList *const subscrSto, enum_t const maxSignal) noexcept
Publish-subscribe initialization.
Definition: qf_ps.cpp:86
static QActive * registry_[QF_MAX_ACTIVE+1U]
Internal array of registered active objects.
Definition: qf.hpp:393
void subscribe(enum_t const sig) const noexcept
Subscribes for delivery of signal sig to the active object.
Definition: qf_ps.cpp:176
void unsubscribeAll() const noexcept
Unsubscribes from the delivery of all signals to the active object.
Definition: qf_ps.cpp:233
void unsubscribe(enum_t const sig) const noexcept
Unsubscribes from the delivery of signal sig to the active object.
Definition: qf_ps.cpp:203
static void publish_(QEvt const *const e, void const *const sender, std::uint_fast8_t const qs_id) noexcept
Publish event to all subscribers of a given signal e->sig
Definition: qf_ps.cpp:102
static QSubscrList * subscrList_
pointer to the array of all subscriber AOs for a given event signal
Definition: qf.hpp:396
Event class.
Definition: qep.hpp:168
Priority Set of up to QF_MAX_ACTIVE elements.
Definition: qf.hpp:166
std::uint_fast8_t findMax() const noexcept
Find the maximum element in the set, returns zero if the set is empty.
Definition: qf.hpp:258
void rmove(std::uint_fast8_t const n) noexcept
Remove element n from the set (n = 1U..64U)
Definition: qf.hpp:241
bool notEmpty() const noexcept
Return 'true' if the priority set is NOT empty.
Definition: qf.hpp:201
#define QF_MAX_ACTIVE
The maximum number of active objects in the application.
Definition: config.hpp:32
void gc(QEvt const *const e) noexcept
Recycle a dynamic event.
Definition: qf_dyn.cpp:161
void bzero(void *const start, std::uint_fast16_t const len) noexcept
Clear a specified region of memory to zero.
Definition: qf_qact.cpp:99
QP/C++ framework.
Definition: exa_native.dox:1
@ QS_QF_PUBLISH
an event was published to active objects
Definition: qs.hpp:171
@ QS_QF_ACTIVE_UNSUBSCRIBE
an AO unsubscribed to an event
Definition: qs.hpp:150
@ QS_QF_ACTIVE_SUBSCRIBE
an AO subscribed to an event
Definition: qs.hpp:149
constexpr enum_t Q_USER_SIG
Type returned from state-handler functions.
Definition: qep.hpp:278
QPSet QSubscrList
Subscriber List (for publish-subscribe)
Definition: qf.hpp:283
void QF_EVT_REF_CTR_INC_(QEvt const *const e) noexcept
increment the refCtr_ of an event e
Definition: qf_pkg.hpp:123
Customizable and memory-efficient Design by Contract (DbC) for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:141
#define Q_REQUIRE_ID(id_, expr_)
Definition: qassert.h:243
#define Q_ASSERT_ID(id_, expr_)
Definition: qassert.h:170
int enum_t
alias for enumerations used for event signals
Definition: qep.hpp:84
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition: qep.hpp:965
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition: qf.hpp:1517
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:147
#define QF_CRIT_X_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.hpp:170
#define QF_CRIT_E_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.hpp:158
#define QF_SCHED_LOCK_(prio_)
QK selective scheduler locking.
Definition: qk.hpp:225
#define QF_SCHED_UNLOCK_()
QK selective scheduler unlocking.
Definition: qk.hpp:235
#define QF_SCHED_STAT_
QK scheduler lock status.
Definition: qk.hpp:221
#define QS_TIME_PRE_()
Output time stamp to a QS record (used in predefined and application-specific trace records)
Definition: qs.hpp:1082
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:144
#define QS_OBJ_PRE_(obj_)
Internal QS macro to output object pointer data element.
Definition: qs_pkg.hpp:193
#define QS_END_NOCRIT_PRE_()
Internal QS macro to end a predefiend QS record without critical section.
Definition: qs_pkg.hpp:153
#define QS_2U8_PRE_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs_pkg.hpp:176