QP/C++ 8.1.1
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_ps.cpp
Go to the documentation of this file.
1//============================================================================
2// QP/C++ Real-Time Event Framework (RTEF)
3//
4// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
5//
6// Q u a n t u m L e a P s
7// ------------------------
8// Modern Embedded Software
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
11//
12// This software is dual-licensed under the terms of the open-source GNU
13// General Public License (GPL) or under the terms of one of the closed-
14// source Quantum Leaps commercial licenses.
15//
16// Redistributions in source code must retain this top-level comment block.
17// Plagiarizing this software to sidestep the license obligations is illegal.
18//
19// NOTE:
20// The GPL does NOT permit the incorporation of this code into proprietary
21// programs. Please contact Quantum Leaps for commercial licensing options,
22// which expressly supersede the GPL and are designed explicitly for
23// closed-source distribution.
24//
25// Quantum Leaps contact information:
26// <www.state-machine.com/licensing>
27// <info@state-machine.com>
28//============================================================================
29#define QP_IMPL // this is QP implementation
30#include "qp_port.hpp" // QP port
31#include "qp_pkg.hpp" // QP package-scope interface
32#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
33#ifdef Q_SPY // QS software tracing enabled?
34 #include "qs_port.hpp" // QS port
35 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
36#else
37 #include "qs_dummy.hpp" // disable the QS software tracing
38#endif // Q_SPY
39
40// unnamed namespace for local definitions with internal linkage
41namespace {
42Q_DEFINE_THIS_MODULE("qf_ps")
43} // unnamed namespace
44
45namespace QP {
46
49
50//............................................................................
52 QSubscrList * const subscrSto,
53 QSignal const maxSignal) noexcept
54{
55 // provided subscSto must be valid
56 Q_REQUIRE_INCRIT(100, subscrSto != nullptr);
57
58 // provided maximum of subscribed signals must be >= Q_USER_SIG
59 Q_REQUIRE_INCRIT(110, maxSignal >= Q_USER_SIG);
60
61 QActive_subscrList_ = subscrSto;
62 QActive_maxPubSignal_ = static_cast<QSignal>(maxSignal);
63
64 // initialize all signals in the subscriber list...
65 for (QSignal sig = 0U; sig < maxSignal; ++sig) {
66 subscrSto[sig].m_set.setEmpty();
67 }
68}
69
70//............................................................................
72 QEvt const * const e,
73 void const * const sender,
74 std::uint_fast8_t const qsId) noexcept
75{
76#ifndef Q_SPY
77 Q_UNUSED_PAR(sender);
78 Q_UNUSED_PAR(qsId);
79#endif
80
83
84 // the published event must be valid
85 Q_REQUIRE_INCRIT(200, e != nullptr);
86
87 QSignal const sig = e->sig;
88
89 // published event signal must not exceed the maximum
91
92 // make a local, modifiable copy of the subscriber set
93 QPSet subscrSet = QActive_subscrList_[sig].m_set;
94
96 QS_TIME_PRE(); // the timestamp
97 QS_OBJ_PRE(sender); // the sender object
98 QS_SIG_PRE(sig); // the signal of the event
99 QS_2U8_PRE(e->poolNum_, e->refCtr_);
100 QS_END_PRE()
101
102 if (e->poolNum_ != 0U) { // is it a mutable event?
103 // NOTE: The reference counter of a mutable event is incremented to
104 // prevent premature recycling of the event while multicasting is
105 // still in progress. The garbage collector step (QF_gc()) at the
106 // end of the function decrements the reference counter and recycles
107 // the event if the counter drops to zero. This covers the case when
108 // event was published without any subscribers.
110 }
111
112 QF_CRIT_EXIT();
113
114 if (subscrSet.notEmpty()) { // any subscribers?
115 multicast_(&subscrSet, e, sender); // multicast to all
116 }
117
118 // The following garbage collection step decrements the reference counter
119 // and recycles the event if the counter drops to zero. This covers both
120 // cases when the event was published with or without any subscribers.
121#if (QF_MAX_EPOOL > 0U)
122 QF::gc(e); // recycle the event to avoid a leak
123#endif
124}
125
126//............................................................................
128 QPSet * const subscrSet,
129 QEvt const * const e,
130 void const * const sender)
131{
132#ifndef Q_SPY
133 Q_UNUSED_PAR(sender);
134#endif
135
136 // highest-prio subscriber ('subscrSet' guaranteed to be NOT empty)
137 std::uint8_t p = static_cast<std::uint8_t>(subscrSet->findMax());
138
141
142 // p != 0 is guaranteed as the result of QPSet_findMax()
145
146 // the active object must be registered (started)
147 Q_ASSERT_INCRIT(310, a != nullptr);
148
149 QF_CRIT_EXIT();
150
152 QF_SCHED_LOCK_(p); // lock the scheduler up to AO's prio
153
154 // NOTE: the following loop does not need the fixed loop bound check
155 // because the local subscriber set 'subscrSet' can hold at most
156 // QF_MAX_ACTIVE elements (rounded up to the nearest 8), which are
157 // removed one by one at every pass.
158 for (;;) { // loop over all subscribers
159
160 // POST() asserts internally if the queue overflows
161 a->POST(e, sender);
162
163 subscrSet->remove(p); // remove the handled subscriber
164 if (subscrSet->isEmpty()) { // no more subscribers?
165 break;
166 }
167
168 // find the next highest-prio subscriber
169 p = static_cast<std::uint8_t>(subscrSet->findMax());
170
172
173 a = QActive_registry_[p];
174
175 // the AO must be registered with the framework
176 Q_ASSERT_INCRIT(340, a != nullptr);
177
178 QF_CRIT_EXIT();
179 }
180
181 QF_SCHED_UNLOCK_(); // unlock the scheduler
182}
183
184//............................................................................
185void QActive::subscribe(QSignal const sig) const noexcept {
188
189 std::uint8_t const p = m_prio;
190
191 // the AO's prio. must be in range
192 Q_REQUIRE_INCRIT(420, (0U < p) && (p <= QF_MAX_ACTIVE));
193
194 // the subscriber AO must be registered (started)
195 Q_REQUIRE_INCRIT(440, this == QActive_registry_[p]);
196
197 // the sig parameter must not overlap reserved signals
198 Q_REQUIRE_INCRIT(460, sig >= Q_USER_SIG);
199
200 // the subscribed signal must be below the maximum of published signals
201 Q_REQUIRE_INCRIT(480, static_cast<QSignal>(sig) < QActive_maxPubSignal_);
202
204 QS_TIME_PRE(); // timestamp
205 QS_SIG_PRE(sig); // the signal of this event
206 QS_OBJ_PRE(this); // this active object
207 QS_END_PRE()
208
209 // insert the AO's prio. into the subscriber set for the signal
210 QActive_subscrList_[sig].m_set.insert(p);
211
212 QF_CRIT_EXIT();
213}
214
215//............................................................................
216void QActive::unsubscribe(QSignal const sig) const noexcept {
219
220 std::uint8_t const p = m_prio;
221
222 // the AO's prio. must be in range
223 Q_REQUIRE_INCRIT(520, (0U < p) && (p <= QF_MAX_ACTIVE));
224
225 // the subscriber AO must be registered (started)
226 Q_REQUIRE_INCRIT(540, this == QActive_registry_[p]);
227
228 // the sig parameter must not overlap reserved signals
229 Q_REQUIRE_INCRIT(560, sig >= Q_USER_SIG);
230 Q_REQUIRE_INCRIT(580, static_cast<QSignal>(sig) < QActive_maxPubSignal_);
231
233 QS_TIME_PRE(); // timestamp
234 QS_SIG_PRE(sig); // the signal of this event
235 QS_OBJ_PRE(this); // this active object
236 QS_END_PRE()
237
238 // remove the AO's prio. from the subscriber set for the signal
239 QActive_subscrList_[sig].m_set.remove(p);
240
241 QF_CRIT_EXIT();
242}
243
244//............................................................................
245void QActive::unsubscribeAll() const noexcept {
248
249 std::uint8_t const p = m_prio;
250
251 // the AO's prio. must be in range
252 Q_REQUIRE_INCRIT(620, (0U < p) && (p <= QF_MAX_ACTIVE));
253
254 // the subscriber AO must be registered (started)
255 Q_REQUIRE_INCRIT(640, this == QActive_registry_[p]);
256
257 QSignal const maxPubSig = QActive_maxPubSignal_;
258
259 // the maximum of published signals must not overlap the reserved signals
260 Q_REQUIRE_INCRIT(670, maxPubSig >= static_cast<QSignal>(Q_USER_SIG));
261
262 QF_CRIT_EXIT();
263
264 // remove this AO's prio. from subscriber lists of all published signals
265 for (QSignal sig = static_cast<QSignal>(Q_USER_SIG);
266 sig < maxPubSig;
267 ++sig)
268 {
270
271 if (QActive_subscrList_[sig].m_set.hasElement(p)) {
272 // remove the AO's prio. from the subscriber set for the signal
273 QActive_subscrList_[sig].m_set.remove(p);
274
276 QS_TIME_PRE(); // timestamp
277 QS_SIG_PRE(sig); // the signal of this event
278 QS_OBJ_PRE(this); // this active object
279 QS_END_PRE()
280 }
281 QF_CRIT_EXIT();
282
283 QF_CRIT_EXIT_NOP(); // prevent merging critical sections
284 }
285}
286
287} // namespace QP
static void multicast_(QPSet *const subscrSet, QEvt const *const e, void const *const sender)
Definition qf_ps.cpp:127
void unsubscribe(QSignal const sig) const noexcept
Unsubscribes from the delivery of signal sig to the active object.
Definition qf_ps.cpp:216
static void publish_(QEvt const *const e, void const *const sender, std::uint_fast8_t const qsId) noexcept
Publish event to all subscribers of a given signal e->sig.
Definition qf_ps.cpp:71
void subscribe(QSignal const sig) const noexcept
Subscribes for delivery of signal sig to the active object.
Definition qf_ps.cpp:185
QActive(QStateHandler const initial) noexcept
QActive constructor (abstract base class).
Definition qf_qact.cpp:55
static void psInit(QSubscrList *const subscrSto, QSignal const maxSignal) noexcept
Publish event to all subscribers of a given signal e->sig.
Definition qf_ps.cpp:51
std::uint8_t m_prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:490
void unsubscribeAll() const noexcept
Unsubscribes from the delivery of all signals to the active object.
Definition qf_ps.cpp:245
Event class.
Definition qp.hpp:101
Set of Active Objects of up to QF_MAX_ACTIVE elements.
Definition qp.hpp:443
std::uint_fast8_t findMax() const noexcept
Find the maximum element in the set.
Definition qf_qact.cpp:273
void remove(std::uint_fast8_t const n) noexcept
Remove element n from the priority-set (n = 1..QF_MAX_ACTIVE).
Definition qf_qact.cpp:259
bool notEmpty() const noexcept
Find out whether the priority-set is NOT empty.
Definition qf_qact.cpp:224
bool isEmpty() const noexcept
Find out whether the priority-set is empty.
Definition qf_qact.cpp:214
Subscriber List (for publish-subscribe).
Definition qp.hpp:464
void gc(QEvt const *const e) noexcept
Recycle a mutable (mutable) event.
Definition qf_dyn.cpp:276
QP/C++ Framework namespace.
Definition qequeue.hpp:36
constexpr QSignal Q_USER_SIG
Definition qp.hpp:164
@ QS_QF_ACTIVE_UNSUBSCRIBE
an AO unsubscribed to an event
Definition qs.hpp:71
@ QS_QF_ACTIVE_SUBSCRIBE
an AO subscribed to an event
Definition qs.hpp:70
@ QS_QF_PUBLISH
an event was published to active objects
Definition qs.hpp:92
QSubscrList * QActive_subscrList_
Internal pointer to the array of subscribers to the event-signals.
Definition qf_ps.cpp:47
void QEvt_refCtr_inc_(QEvt const *const me) noexcept
Internal function to increment the refCtr of a const event.
Definition qf_act.cpp:57
std::array< QActive *, QF_MAX_ACTIVE+1U > QActive_registry_
Internal array of pointers to the registered Active Objects.
Definition qf_qact.cpp:47
std::uint16_t QSignal
The signal of event QP::QEvt.
Definition qp.hpp:98
QSignal QActive_maxPubSignal_
Internal maximum published signal (# used entries in the QP::QActive_subscrList_ array).
Definition qf_ps.cpp:48
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:89
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition qp.hpp:932
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64).
Definition qp_config.hpp:98
QP Framework in C++ internal (package-scope) interface
Sample QP/C++ port.
#define QF_SCHED_LOCK_(ceil_)
Definition qp_port.hpp:159
#define QF_SCHED_UNLOCK_()
Definition qp_port.hpp:167
#define QF_SCHED_STAT_
Definition qp_port.hpp:158
#define QS_TIME_PRE()
Definition qs.hpp:362
QS (QP/Spy software tracing) internal (package-scope) interface.
#define QS_OBJ_PRE(obj_)
Output pre-formatted object pointer element.
Definition qs_pkg.hpp:89
#define QS_SIG_PRE(sig_)
Output pre-formatted event signal data element.
Definition qs_pkg.hpp:90
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.hpp:81
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.hpp:77
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.hpp:71
Sample QS/C++ port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:40
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section).
Definition qsafe.h:54
#define QF_CRIT_EXIT()
Definition qsafe.h:44
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section).
Definition qsafe.h:98
#define QF_CRIT_STAT
Definition qsafe.h:36