QP/C++ Real-Time Event Framework 8.1.5
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{
57
58 // provided subscSto must be valid
59 Q_REQUIRE_INCRIT(100, subscrSto != nullptr);
60
61 // provided maximum of subscribed signals must be >= Q_USER_SIG
62 Q_REQUIRE_INCRIT(110, maxSignal >= Q_USER_SIG);
63
65
66 QActive_subscrList_ = subscrSto;
67 QActive_maxPubSignal_ = static_cast<QSignal>(maxSignal);
68
69 // initialize all signals in the subscriber list...
70 for (QSignal sig = 0U; sig < maxSignal; ++sig) {
71 subscrSto[sig].m_set.setEmpty();
72 }
73}
74
75//............................................................................
77 QEvt const * const e,
78 void const * const sender,
79 std::uint_fast8_t const qsId) noexcept
80{
81#ifndef Q_SPY
82 Q_UNUSED_PAR(sender);
83 Q_UNUSED_PAR(qsId);
84#endif
85
88
89 // the published event must be valid
90 Q_REQUIRE_INCRIT(200, e != nullptr);
91
92 QSignal const sig = e->sig;
93
94 // published event signal must not exceed the maximum
96
97 // make a local, modifiable copy of the subscriber set
98 QPSet subscrSet = QActive_subscrList_[sig].m_set;
99
101 QS_TIME_PRE(); // the timestamp
102 QS_OBJ_PRE(sender); // the sender object
103 QS_SIG_PRE(sig); // the signal of the event
104 QS_2U8_PRE(e->poolNum_, e->refCtr_);
105 QS_END_PRE()
106
107 if (e->poolNum_ != 0U) { // is it a mutable event?
108 // NOTE: The reference counter of a mutable event is incremented to
109 // prevent premature recycling of the event while multicasting is
110 // still in progress. The garbage collector step (QF_gc()) at the
111 // end of the function decrements the reference counter and recycles
112 // the event if the counter drops to zero. This covers the case when
113 // event was published without any subscribers.
115 }
116
117 QF_CRIT_EXIT();
118
119 if (subscrSet.notEmpty()) { // any subscribers?
120 multicast_(&subscrSet, e, sender); // multicast to all
121 }
122
123 // The following garbage collection step decrements the reference counter
124 // and recycles the event if the counter drops to zero. This covers both
125 // cases when the event was published with or without any subscribers.
126#if (QF_MAX_EPOOL > 0U)
127 QF::gc(e); // recycle the event to avoid a leak
128#endif
129}
130
131//............................................................................
133 QPSet * const subscrSet,
134 QEvt const * const e,
135 void const * const sender)
136{
137#ifndef Q_SPY
138 Q_UNUSED_PAR(sender);
139#endif
140
141 // highest-prio subscriber ('subscrSet' guaranteed to be NOT empty)
142 std::uint8_t p = static_cast<std::uint8_t>(subscrSet->findMax());
143
146
147 // p != 0 is guaranteed as the result of QPSet_findMax()
150
151 // the active object must be registered (started)
152 Q_ASSERT_INCRIT(310, a != nullptr);
153
154 QF_CRIT_EXIT();
155
157 QF_SCHED_LOCK_(p); // lock the scheduler up to AO's prio
158
159 // NOTE: the following loop does not need the fixed loop bound check
160 // because the local subscriber set 'subscrSet' can hold at most
161 // QF_MAX_ACTIVE elements (rounded up to the nearest 8), which are
162 // removed one by one at every pass.
163 for (;;) { // loop over all subscribers
164
165 // POST() asserts internally if the queue overflows
166 a->POST(e, sender);
167
168 subscrSet->remove(p); // remove the handled subscriber
169 if (subscrSet->isEmpty()) { // no more subscribers?
170 break;
171 }
172
173 // find the next highest-prio subscriber
174 p = static_cast<std::uint8_t>(subscrSet->findMax());
175
177
178 a = QActive_registry_[p];
179
180 // the AO must be registered with the framework
181 Q_ASSERT_INCRIT(340, a != nullptr);
182
183 QF_CRIT_EXIT();
184 }
185
186 QF_SCHED_UNLOCK_(); // unlock the scheduler
187}
188
189//............................................................................
190void QActive::subscribe(QSignal const sig) const noexcept {
193
194 std::uint8_t const p = m_prio;
195
196 // the AO's prio. must be in range
197 Q_REQUIRE_INCRIT(420, (0U < p) && (p <= QF_MAX_ACTIVE));
198
199 // the subscriber AO must be registered (started)
200 Q_REQUIRE_INCRIT(440, this == QActive_registry_[p]);
201
202 // the sig parameter must not overlap reserved signals
203 Q_REQUIRE_INCRIT(460, sig >= Q_USER_SIG);
204
205 // the subscribed signal must be below the maximum of published signals
206 Q_REQUIRE_INCRIT(480, static_cast<QSignal>(sig) < QActive_maxPubSignal_);
207
209 QS_TIME_PRE(); // timestamp
210 QS_SIG_PRE(sig); // the signal of this event
211 QS_OBJ_PRE(this); // this active object
212 QS_END_PRE()
213
214 // insert the AO's prio. into the subscriber set for the signal
215 QActive_subscrList_[sig].m_set.insert(p);
216
217 QF_CRIT_EXIT();
218}
219
220//............................................................................
221void QActive::unsubscribe(QSignal const sig) const noexcept {
224
225 std::uint8_t const p = m_prio;
226
227 // the AO's prio. must be in range
228 Q_REQUIRE_INCRIT(520, (0U < p) && (p <= QF_MAX_ACTIVE));
229
230 // the subscriber AO must be registered (started)
231 Q_REQUIRE_INCRIT(540, this == QActive_registry_[p]);
232
233 // the sig parameter must not overlap reserved signals
234 Q_REQUIRE_INCRIT(560, sig >= Q_USER_SIG);
235 Q_REQUIRE_INCRIT(580, static_cast<QSignal>(sig) < QActive_maxPubSignal_);
236
238 QS_TIME_PRE(); // timestamp
239 QS_SIG_PRE(sig); // the signal of this event
240 QS_OBJ_PRE(this); // this active object
241 QS_END_PRE()
242
243 // remove the AO's prio. from the subscriber set for the signal
244 QActive_subscrList_[sig].m_set.remove(p);
245
246 QF_CRIT_EXIT();
247}
248
249//............................................................................
250void QActive::unsubscribeAll() const noexcept {
253
254 std::uint8_t const p = m_prio;
255
256 // the AO's prio. must be in range
257 Q_REQUIRE_INCRIT(620, (0U < p) && (p <= QF_MAX_ACTIVE));
258
259 // the subscriber AO must be registered (started)
260 Q_REQUIRE_INCRIT(640, this == QActive_registry_[p]);
261
262 QSignal const maxPubSig = QActive_maxPubSignal_;
263
264 // the maximum of published signals must not overlap the reserved signals
265 Q_REQUIRE_INCRIT(670, maxPubSig >= static_cast<QSignal>(Q_USER_SIG));
266
267 QF_CRIT_EXIT();
268
269 // remove this AO's prio. from subscriber lists of all published signals
270 for (QSignal sig = static_cast<QSignal>(Q_USER_SIG);
271 sig < maxPubSig;
272 ++sig)
273 {
275
276 if (QActive_subscrList_[sig].m_set.hasElement(p)) {
277 // remove the AO's prio. from the subscriber set for the signal
278 QActive_subscrList_[sig].m_set.remove(p);
279
281 QS_TIME_PRE(); // timestamp
282 QS_SIG_PRE(sig); // the signal of this event
283 QS_OBJ_PRE(this); // this active object
284 QS_END_PRE()
285 }
286 QF_CRIT_EXIT();
287
288 QF_CRIT_EXIT_NOP(); // prevent merging critical sections
289 }
290}
291
292} // namespace QP
static void multicast_(QPSet *const subscrSet, QEvt const *const e, void const *const sender)
Definition qf_ps.cpp:132
void unsubscribe(QSignal const sig) const noexcept
Unsubscribes from the delivery of signal sig to the active object.
Definition qf_ps.cpp:221
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:76
void subscribe(QSignal const sig) const noexcept
Subscribes for delivery of signal sig to the active object.
Definition qf_ps.cpp:190
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
Initializes the publish-subscribe facility for the application.
Definition qf_ps.cpp:51
std::uint8_t m_prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:503
void unsubscribeAll() const noexcept
Unsubscribes from the delivery of all signals to the active object.
Definition qf_ps.cpp:250
Event class.
Definition qp.hpp:101
Set of Active Objects of up to QF_MAX_ACTIVE elements.
Definition qp.hpp:449
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:477
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:169
@ 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 mark unused parameters of functions.
Definition qp.hpp:89
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64).
Definition qp_config.hpp:72
QP/C++ Framework in C++ internal (package-scope) interface.
Sample QP/C++ port.
#define QF_SCHED_LOCK_(ceil_)
Port-specific method to lock the scheduler (for internal use in QF only).
Definition qp_port.hpp:323
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition qp_port.hpp:106
#define QF_SCHED_UNLOCK_()
Port-specific method to unlock the scheduler (for internal use in QF only).
Definition qp_port.hpp:337
#define QF_SCHED_STAT_
Port-specific type of the scheduler lock status (for internal use in QF only).
Definition qp_port.hpp:314
#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:91
#define QS_SIG_PRE(sig_)
Output pre-formatted event signal data element.
Definition qs_pkg.hpp:92
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.hpp:83
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.hpp:79
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.hpp:73
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