QP/C++  8.0.3
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 {
47
49
50//............................................................................
52 QSubscrList * const subscrSto,
53 enum_t const maxSignal) noexcept
54{
55 subscrList_ = subscrSto;
56 maxPubSignal_ = maxSignal;
57
58 // initialize the subscriber list
59 for (enum_t sig = 0; sig < maxSignal; ++sig) {
60 subscrSto[sig].m_set.setEmpty();
61 }
62}
63
64//............................................................................
66 QEvt const * const e,
67 void const * const sender,
68 std::uint_fast8_t const qsId) noexcept
69{
70#ifndef Q_SPY
71 Q_UNUSED_PAR(sender);
72 Q_UNUSED_PAR(qsId);
73#endif
74
75 QSignal const sig = e->sig;
76
79
80 Q_REQUIRE_INCRIT(200, sig < static_cast<QSignal>(maxPubSignal_));
81
82 QS_BEGIN_PRE(QS_QF_PUBLISH, qsId)
83 QS_TIME_PRE(); // the timestamp
84 QS_OBJ_PRE(sender); // the sender object
85 QS_SIG_PRE(e->sig); // the signal of the event
86 QS_2U8_PRE(e->poolNum_, e->refCtr_);
88
89 // is it a mutable event?
90 if (e->poolNum_ != 0U) {
91 // NOTE: The reference counter of a mutable event is incremented to
92 // prevent premature recycling of the event while the multicasting
93 // is still in progress. At the end of the function, the garbage
94 // collector step (QF::gc()) decrements the reference counter and
95 // recycles the event if the counter drops to zero. This covers the
96 // case when the event was published without any subscribers.
97 Q_ASSERT_INCRIT(205, e->refCtr_ < (2U * QF_MAX_ACTIVE));
99 }
100
101 // make a local, modifiable copy of the subscriber set
102 QPSet subscrSet = subscrList_[sig].m_set;
103
104 QF_CRIT_EXIT();
105
106 if (subscrSet.notEmpty()) { // any subscribers?
107 // highest-prio subscriber
108 std::uint_fast8_t p = subscrSet.findMax();
109
111
112 QActive *a = registry_[p];
113 // the AO must be registered with the framework
114 Q_ASSERT_INCRIT(210, a != nullptr);
115
116 QF_CRIT_EXIT();
117
119 QF_SCHED_LOCK_(p); // lock the scheduler up to AO's prio
120 do { // loop over all subscribers
121 // POST() asserts internally if the queue overflows
122 a->POST(e, sender);
123
124 subscrSet.remove(p); // remove the handled subscriber
125 if (subscrSet.notEmpty()) { // still more subscribers?
126 p = subscrSet.findMax(); // highest-prio subscriber
127
129
130 a = registry_[p];
131 // the AO must be registered with the framework
132 Q_ASSERT_INCRIT(220, a != nullptr);
133
134 QF_CRIT_EXIT();
135 }
136 else {
137 p = 0U; // no more subscribers
138 }
139 } while (p != 0U);
140
142 Q_ASSERT_INCRIT(290, p == 0U); // all subscribers processed
143 QF_CRIT_EXIT();
144
145 QF_SCHED_UNLOCK_(); // unlock the scheduler
146 }
147
148 // The following garbage collection step decrements the reference counter
149 // and recycles the event if the counter drops to zero. This covers both
150 // cases when the event was published with or without any subscribers.
151#if (QF_MAX_EPOOL > 0U)
152 QF::gc(e); // recycle the event to avoid a leak
153#endif
154}
155
156//............................................................................
157void QActive::subscribe(enum_t const sig) const noexcept {
158 std::uint_fast8_t const p = static_cast<std::uint_fast8_t>(m_prio);
159
162
163 Q_REQUIRE_INCRIT(300, (Q_USER_SIG <= sig)
164 && (sig < maxPubSignal_)
165 && (0U < p) && (p <= QF_MAX_ACTIVE)
166 && (registry_[p] == this));
167
168 QS_BEGIN_PRE(QS_QF_ACTIVE_SUBSCRIBE, m_prio)
169 QS_TIME_PRE(); // timestamp
170 QS_SIG_PRE(sig); // the signal of this event
171 QS_OBJ_PRE(this); // this active object
172 QS_END_PRE()
173
174 // insert the prio. into the subscriber set
175 subscrList_[sig].m_set.insert(p);
176
177 QF_CRIT_EXIT();
178}
179
180//............................................................................
181void QActive::unsubscribe(enum_t const sig) const noexcept {
182 std::uint_fast8_t const p = static_cast<std::uint_fast8_t>(m_prio);
183
186
187 Q_REQUIRE_INCRIT(400, (Q_USER_SIG <= sig)
188 && (sig < maxPubSignal_)
189 && (0U < p) && (p <= QF_MAX_ACTIVE)
190 && (registry_[p] == this));
191
192 QS_BEGIN_PRE(QS_QF_ACTIVE_UNSUBSCRIBE, p)
193 QS_TIME_PRE(); // timestamp
194 QS_SIG_PRE(sig); // the signal of this event
195 QS_OBJ_PRE(this); // this active object
196 QS_END_PRE()
197
198 // remove the prio. from the subscriber set
199 subscrList_[sig].m_set.remove(p);
200
201 QF_CRIT_EXIT();
202}
203
204//............................................................................
205void QActive::unsubscribeAll() const noexcept {
208
209 std::uint_fast8_t const p = static_cast<std::uint_fast8_t>(m_prio);
210
211 Q_REQUIRE_INCRIT(500, (0U < p) && (p <= QF_MAX_ACTIVE)
212 && (registry_[p] == this));
213 enum_t const maxPubSig = maxPubSignal_;
214
215 QF_CRIT_EXIT();
216
217 for (enum_t sig = Q_USER_SIG; sig < maxPubSig; ++sig) {
219
220 if (subscrList_[sig].m_set.hasElement(p)) {
221 subscrList_[sig].m_set.remove(p);
222 QS_BEGIN_PRE(QS_QF_ACTIVE_UNSUBSCRIBE, m_prio)
223 QS_TIME_PRE(); // timestamp
224 QS_SIG_PRE(sig); // the signal of this event
225 QS_OBJ_PRE(this); // this active object
226 QS_END_PRE()
227 }
228 QF_CRIT_EXIT();
229
230 QF_CRIT_EXIT_NOP(); // prevent merging critical sections
231 }
232}
233
234} // namespace QP
void subscribe(enum_t const sig) const noexcept
Definition qf_ps.cpp:157
static QActive * registry_[QF_MAX_ACTIVE+1U]
Definition qp.hpp:581
static QSubscrList * subscrList_
Definition qp.hpp:582
void unsubscribe(enum_t const sig) const noexcept
Definition qf_ps.cpp:181
static void publish_(QEvt const *const e, void const *const sender, std::uint_fast8_t const qsId) noexcept
Definition qf_ps.cpp:65
static void psInit(QSubscrList *const subscrSto, enum_t const maxSignal) noexcept
Definition qf_ps.cpp:51
static enum_t maxPubSignal_
Definition qp.hpp:583
QActive(QStateHandler const initial) noexcept
Definition qp.hpp:597
std::uint8_t m_prio
Definition qp.hpp:565
void unsubscribeAll() const noexcept
Definition qf_ps.cpp:205
Event class.
Definition qp.hpp:115
Set of Active Objects of up to QF_MAX_ACTIVE elements.
Definition qp.hpp:479
std::uint_fast8_t findMax() const noexcept
Definition qp.hpp:537
void remove(std::uint_fast8_t const n) noexcept
Definition qp.hpp:525
bool notEmpty() const noexcept
Definition qp.hpp:497
Subscriber List (for publish-subscribe)
Definition qp.hpp:550
void gc(QEvt const *const e) noexcept
Recycle a mutable (mutable) event.
Definition qf_dyn.cpp:188
QP/C++ framework.
Definition qequeue.hpp:36
constexpr enum_t Q_USER_SIG
Definition qp.hpp:175
void QEvt_refCtr_inc_(QEvt const *const e) noexcept
Definition qp_pkg.hpp:66
std::uint16_t QSignal
The signal of event QP::QEvt.
Definition qp.hpp:108
#define QF_SCHED_LOCK_(ceil_)
Definition qk.hpp:80
#define QF_SCHED_UNLOCK_()
Definition qk.hpp:88
#define QF_SCHED_STAT_
Definition qk.hpp:79
int enum_t
Definition qp.hpp:92
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:94
#define QF_CRIT_EXIT_NOP()
Definition qp.hpp:1036
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
Internal (package scope) QP/C++ interface.
Sample QP/C++ port.
QS/C++ dummy public interface.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.hpp:157
#define QS_SIG_PRE(sig_)
Definition qs_dummy.hpp:155
#define QS_TIME_PRE()
Definition qs_dummy.hpp:154
#define QS_2U8_PRE(data1_, data2_)
Definition qs_dummy.hpp:151
#define QS_END_PRE()
Definition qs_dummy.hpp:149
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.hpp:148
Sample QS/C++ port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:39
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section)
Definition qsafe.h:49
#define QF_CRIT_EXIT()
Definition qsafe.h:43
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section)
Definition qsafe.h:86
#define QF_CRIT_STAT
Definition qsafe.h:35