QP/C 8.1.2
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_ps.c
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.h" // QP port
31#include "qp_pkg.h" // 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.h" // QS port
35 #include "qs_pkg.h" // QS facilities for pre-defined trace records
36#else
37 #include "qs_dummy.h" // disable the QS software tracing
38#endif // Q_SPY
39
40Q_DEFINE_THIS_MODULE("qf_ps")
41
44
45
46// static local helper function (declaration)
48 QPSet * const subscrSet,
49 QEvt const * const e,
50 void const * const sender);
51
52//............................................................................
53//! @static @public @memberof QActive
55 QSubscrList * const subscrSto,
56 enum_t const maxSignal)
57{
58 // provided subscSto must be valid
59 Q_REQUIRE_INCRIT(100, subscrSto != (QSubscrList *)0);
60
61 // provided maximum of subscribed signals must be >= Q_USER_SIG
62 Q_REQUIRE_INCRIT(110, maxSignal >= Q_USER_SIG);
63
64 QActive_subscrList_ = subscrSto;
65 QActive_maxPubSignal_ = (QSignal)maxSignal;
66
67 // initialize all signals in the subscriber list...
68 for (enum_t sig = 0; sig < maxSignal; ++sig) {
69 QPSet_setEmpty(&subscrSto[sig].set); // no subscibers to this signal
70 }
71}
72
73//............................................................................
74//! @static @private @memberof QActive
76 QEvt const * const e,
77 void const * const sender,
78 uint_fast8_t const qsId)
79{
80#ifndef Q_SPY
81 Q_UNUSED_PAR(sender);
82 Q_UNUSED_PAR(qsId);
83#endif
84
87
88 // the published event must be valid
89 Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
90
91 QSignal const sig = (QSignal)e->sig;
92
93 // published event signal must not exceed the maximum
95
96 // make a local, modifiable copy of the subscriber set
97 QPSet subscrSet = QActive_subscrList_[sig].set;
98
100 QS_TIME_PRE(); // the timestamp
101 QS_OBJ_PRE(sender); // the sender object
102 QS_SIG_PRE(sig); // the signal of the event
104 QS_END_PRE()
105
106 if (e->poolNum_ != 0U) { // is it a mutable event?
107 // NOTE: The reference counter of a mutable event is incremented to
108 // prevent premature recycling of the event while multicasting is
109 // still in progress. The garbage collector step (QF_gc()) at the
110 // end of the function decrements the reference counter and recycles
111 // the event if the counter drops to zero. This covers the case when
112 // event was published without any subscribers.
113 QEvt_refCtr_inc_(e);
114 }
115
116 QF_CRIT_EXIT();
117
118 if (QPSet_notEmpty(&subscrSet)) { // any subscribers?
119 QActive_multicast_(&subscrSet, e, sender); // multicast to all
120 }
121
122 // The following garbage collection step decrements the reference counter
123 // and recycles the event if the counter drops to zero. This covers both
124 // cases when the event was published with or without any subscribers.
125#if (QF_MAX_EPOOL > 0U)
126 QF_gc(e); // recycle the event to avoid a leak
127#endif
128}
129
130//............................................................................
131//! @private @memberof QActive
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 uint8_t p = (uint8_t)QPSet_findMax(subscrSet);
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 != (QActive *)0);
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 // QACTIVE_POST() asserts internally if the queue overflows
166 QACTIVE_POST(a, e, sender);
167
168 QPSet_remove(subscrSet, p); // remove the handled subscriber
169 if (QPSet_isEmpty(subscrSet)) { // no more subscribers?
170 break;
171 }
172
173 // find the next highest-prio subscriber
174 p = (uint8_t)QPSet_findMax(subscrSet);
175
177
178 a = QActive_registry_[p];
179
180 // the AO must be registered with the framework
181 Q_ASSERT_INCRIT(340, a != (QActive *)0);
182
183 QF_CRIT_EXIT();
184 }
185
186 QF_SCHED_UNLOCK_(); // unlock the scheduler
187}
188
189//............................................................................
190//! @protected @memberof QActive
191void QActive_subscribe(QActive const * const me,
192 enum_t const sig)
193{
196
197 uint8_t const p = me->prio;
198
199 // the AO's prio. must be in range
200 Q_REQUIRE_INCRIT(420, (0U < p) && (p <= QF_MAX_ACTIVE));
201
202 // the subscriber AO must be registered (started)
203 Q_REQUIRE_INCRIT(440, me == QActive_registry_[p]);
204
205 // the sig parameter must not overlap reserved signals
206 Q_REQUIRE_INCRIT(460, sig >= Q_USER_SIG);
207
208 // the subscribed signal must be below the maximum of published signals
210
212 QS_TIME_PRE(); // timestamp
213 QS_SIG_PRE(sig); // the signal of this event
214 QS_OBJ_PRE(me); // this active object
215 QS_END_PRE()
216
217 // insert the AO's prio. into the subscriber set for the signal
218 QPSet_insert(&QActive_subscrList_[sig].set, p);
219
220 QF_CRIT_EXIT();
221}
222
223//............................................................................
224//! @protected @memberof QActive
225void QActive_unsubscribe(QActive const * const me,
226 enum_t const sig)
227{
230
231 uint8_t const p = me->prio;
232
233 // the AO's prio. must be in range
234 Q_REQUIRE_INCRIT(520, (0U < p) && (p <= QF_MAX_ACTIVE));
235
236 // the subscriber AO must be registered (started)
237 Q_REQUIRE_INCRIT(540, me == QActive_registry_[p]);
238
239 // the sig parameter must not overlap reserved signals
240 Q_REQUIRE_INCRIT(560, sig >= Q_USER_SIG);
241
242 // the unsubscribed signal must be below the maximum of published signals
244
246 QS_TIME_PRE(); // timestamp
247 QS_SIG_PRE(sig); // the signal of this event
248 QS_OBJ_PRE(me); // this active object
249 QS_END_PRE()
250
251 // remove the AO's prio. from the subscriber set for the signal
252 QPSet_remove(&QActive_subscrList_[sig].set, p);
253
254 QF_CRIT_EXIT();
255}
256
257//............................................................................
258//! @protected @memberof QActive
259void QActive_unsubscribeAll(QActive const * const me) {
262
263 uint8_t const p = me->prio;
264
265 // the AO's prio. must be in range
266 Q_REQUIRE_INCRIT(620, (0U < p) && (p <= QF_MAX_ACTIVE));
267
268 // the subscriber AO must be registered (started)
269 Q_REQUIRE_INCRIT(640, me == QActive_registry_[p]);
270
271 QSignal const maxPubSig = QActive_maxPubSignal_;
272
273 // the maximum of published signals must not overlap the reserved signals
274 Q_REQUIRE_INCRIT(670, maxPubSig >= (QSignal)Q_USER_SIG);
275
276 QF_CRIT_EXIT();
277
278 // remove this AO's prio. from subscriber lists of all published signals
279 for (QSignal sig = Q_USER_SIG; sig < maxPubSig; ++sig) {
281
282 if (QPSet_hasElement(&QActive_subscrList_[sig].set, p)) {
283 // remove the AO's prio. from the subscriber set for the signal
284 QPSet_remove(&QActive_subscrList_[sig].set, p);
285
287 QS_TIME_PRE(); // timestamp
288 QS_SIG_PRE(sig); // the signal of this event
289 QS_OBJ_PRE(me); // this active object
290 QS_END_PRE()
291 }
292 QF_CRIT_EXIT();
293
294 QF_CRIT_EXIT_NOP(); // prevent merging critical sections
295 }
296}
QSubscrList * QActive_subscrList_
Definition qf_ps.c:42
QSignal QActive_maxPubSignal_
Definition qf_ps.c:43
static void QActive_multicast_(QPSet *const subscrSet, QEvt const *const e, void const *const sender)
#define Q_UNUSED_PAR(par_)
Helper macro to mark unused parameters of functions.
Definition qp.h:90
#define Q_USER_SIG
Offset for the user signals (QP/C Application).
Definition qp.h:170
#define QACTIVE_POST(me_, e_, sender_)
Invoke the direct event posting facility QActive_post_().
Definition qp.h:760
int enum_t
Definition qp.h:88
uint16_t QSignal
The signal of event QEvt.
Definition qp.h:97
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64).
Definition qp_config.h:100
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.h:287
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition qp_port.h:106
#define QF_SCHED_UNLOCK_()
Port-specific method to unlock the scheduler (for internal use in QF only).
Definition qp_port.h:301
#define QF_SCHED_STAT_
Port-specific type of the scheduler lock status (for internal use in QF only).
Definition qp_port.h:278
#define QS_TIME_PRE()
Definition qs.h:340
@ QS_QF_PUBLISH
an event was published to active objects
Definition qs.h:90
@ QS_QF_ACTIVE_UNSUBSCRIBE
an AO unsubscribed to an event
Definition qs.h:69
@ QS_QF_ACTIVE_SUBSCRIBE
an AO subscribed to an event
Definition qs.h:68
QS (QP/Spy software tracing) internal (package-scope) interface.
#define QS_OBJ_PRE(obj_)
Output pre-formatted object pointer element.
Definition qs_pkg.h:46
#define QS_SIG_PRE(sig_)
Output pre-formatted event signal data element.
Definition qs_pkg.h:47
#define QS_2U8_PRE(data1_, data2_)
Output two pre-formatted unsigned 8-bit integer data elements.
Definition qs_pkg.h:41
#define QS_END_PRE()
Pre-formatted QS trace record end.
Definition qs_pkg.h:38
#define QS_BEGIN_PRE(rec_, qsId_)
Pre-formatted QS trace record begin.
Definition qs_pkg.h:32
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
Active object class (based on the QHsm implementation strategy).
Definition qp.h:447
QSubscrList * QActive_subscrList_
Static (one per-class) pointer to all subscriber AOs for a given event signal.
Definition qp_pkg.h:41
void QActive_unsubscribe(QActive const *const me, enum_t const sig)
Unsubscribes from the delivery of signal sig to the active object.
Definition qf_ps.c:225
void QActive_publish_(QEvt const *const e, void const *const sender, uint_fast8_t const qsId)
Publish event to all subscribers of a given signal e->sig.
Definition qf_ps.c:75
QSignal QActive_maxPubSignal_
Static (one per-class) maximum published signal (the size of the subscrList_ array).
Definition qp_pkg.h:44
static void QActive_multicast_(QPSet *const subscrSet, QEvt const *const e, void const *const sender)
Definition qf_ps.c:132
QActive * QActive_registry_[QF_MAX_ACTIVE+1U]
Static (one per-class) array of registered active objects.
Definition qp_pkg.h:38
uint8_t prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.h:449
void QActive_subscribe(QActive const *const me, enum_t const sig)
Subscribes for delivery of signal sig to the active object.
Definition qf_ps.c:191
void QActive_unsubscribeAll(QActive const *const me)
Unsubscribes from the delivery of all signals to the active object.
Definition qf_ps.c:259
void QActive_psInit(QSubscrList *const subscrSto, enum_t const maxSignal)
Publish event to all subscribers of a given signal e->sig.
Definition qf_ps.c:54
Event class.
Definition qp.h:100
uint32_t refCtr_
Event reference counter.
Definition qp.h:103
uint32_t poolNum_
Event pool number of this event.
Definition qp.h:102
uint32_t sig
Event signal (see Event Signal).
Definition qp.h:101
Set of Active Objects of up to QF_MAX_ACTIVE elements.
Definition qp.h:407
Subscriber List (for publish-subscribe).
Definition qp.h:438