QP/C++  6.9.3
Real-Time Embedded Framework
qf_actq.cpp
Go to the documentation of this file.
1 
44 #define QP_IMPL // this is QP implementation
45 #include "qf_port.hpp" // QF port
46 #include "qf_pkg.hpp" // QF package-scope interface
47 #include "qassert.h" // QP embedded systems-friendly assertions
48 #ifdef Q_SPY // QS software tracing enabled?
49  #include "qs_port.hpp" // QS port
50  #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
51 #else
52  #include "qs_dummy.hpp" // disable the QS software tracing
53 #endif // Q_SPY
54 
55 namespace QP {
56 
57 Q_DEFINE_THIS_MODULE("qf_actq")
58 
59 #ifdef Q_SPY
60 //****************************************************************************
90 bool QActive::post_(QEvt const * const e,
91  std::uint_fast16_t const margin,
92  void const * const sender) noexcept
93 #else
94 bool QActive::post_(QEvt const * const e,
95  std::uint_fast16_t const margin) noexcept
96 #endif
97 {
98  bool status;
101 
102 
103  Q_REQUIRE_ID(100, e != nullptr);
104 
105  QF_CRIT_E_();
106  QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into the temporary
107 
108  // test-probe#1 for faking queue overflow
110  nFree = 0U;
111  )
112 
113  if (margin == QF_NO_MARGIN) {
114  if (nFree > 0U) {
115  status = true; // can post
116  }
117  else {
118  status = false; // cannot post
119  Q_ERROR_CRIT_(110); // must be able to post the event
120  }
121  }
122  else if (nFree > static_cast<QEQueueCtr>(margin)) {
123  status = true; // can post
124  }
125  else {
126  status = false; // cannot post, but don't assert
127  }
128 
129  // is it a dynamic event?
130  if (e->poolId_ != 0U) {
131  QF_EVT_REF_CTR_INC_(e); // increment the reference counter
132  }
133 
134  if (status) { // can post the event?
135 
136  --nFree; // one free entry just used up
137  m_eQueue.m_nFree = nFree; // update the volatile
138  if (m_eQueue.m_nMin > nFree) {
139  m_eQueue.m_nMin = nFree; // update minimum so far
140  }
141 
143  QS_TIME_PRE_(); // timestamp
144  QS_OBJ_PRE_(sender); // the sender object
145  QS_SIG_PRE_(e->sig); // the signal of the event
146  QS_OBJ_PRE_(this); // this active object
147  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
148  QS_EQC_PRE_(nFree); // number of free entries
149  QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
151 
152 #ifdef Q_UTEST
153  // callback to examine the posted event under the same conditions
154  // as producing the #QS_QF_ACTIVE_POST trace record, which are:
155  // the local filter for this AO ('me->prio') is set
156  //
157  if ((QS::priv_.locFilter[m_prio >> 3U]
158  & static_cast<std::uint8_t>(1U << (m_prio & 7U))) != 0U)
159  {
160  QS::onTestPost(sender, this, e, status);
161  }
162 #endif
163  // empty queue?
164  if (m_eQueue.m_frontEvt == nullptr) {
165  m_eQueue.m_frontEvt = e; // deliver event directly
166  QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
167  }
168  // queue is not empty, insert event into the ring-buffer
169  else {
170  // insert event pointer e into the buffer (FIFO)
171  QF_PTR_AT_(m_eQueue.m_ring, m_eQueue.m_head) = e;
172 
173  // need to wrap head?
174  if (m_eQueue.m_head == 0U) {
175  m_eQueue.m_head = m_eQueue.m_end; // wrap around
176  }
177  --m_eQueue.m_head; // advance the head (counter clockwise)
178  }
179 
180  QF_CRIT_X_();
181  }
182  else { // cannot post the event
183 
185  QS_TIME_PRE_(); // timestamp
186  QS_OBJ_PRE_(sender); // the sender object
187  QS_SIG_PRE_(e->sig); // the signal of the event
188  QS_OBJ_PRE_(this); // this active object
189  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
190  QS_EQC_PRE_(nFree); // number of free entries
191  QS_EQC_PRE_(margin); // margin requested
193 
194 #ifdef Q_UTEST
195  // callback to examine the posted event under the same conditions
196  // as producing the #QS_QF_ACTIVE_POST trace record, which are:
197  // the local filter for this AO ('me->prio') is set
198  //
199  if ((QS::priv_.locFilter[m_prio >> 3U]
200  & static_cast<std::uint8_t>(1U << (m_prio & 7U))) != 0U)
201  {
202  QS::onTestPost(sender, this, e, status);
203  }
204 #endif
205 
206  QF_CRIT_X_();
207 
208  QF::gc(e); // recycle the event to avoid a leak
209  }
210 
211  return status;
212 }
213 
214 //****************************************************************************
228 void QActive::postLIFO(QEvt const * const e) noexcept {
231 
232  QF_CRIT_E_();
233  QEQueueCtr nFree = m_eQueue.m_nFree;// tmp to avoid UB for volatile access
234 
236  nFree = 0U;
237  )
238 
239  // the queue must be able to accept the event (cannot overflow)
240  Q_ASSERT_CRIT_(210, nFree != 0U);
241 
242  // is it a dynamic event?
243  if (e->poolId_ != 0U) {
244  QF_EVT_REF_CTR_INC_(e); // increment the reference counter
245  }
246 
247  --nFree; // one free entry just used up
248  m_eQueue.m_nFree = nFree; // update the volatile
249  if (m_eQueue.m_nMin > nFree) {
250  m_eQueue.m_nMin = nFree; // update minimum so far
251  }
252 
254  QS_TIME_PRE_(); // timestamp
255  QS_SIG_PRE_(e->sig); // the signal of this event
256  QS_OBJ_PRE_(this); // this active object
257  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
258  QS_EQC_PRE_(nFree); // number of free entries
259  QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
261 
262 #ifdef Q_UTEST
263  // callback to examine the posted event under the same conditions
264  // as producing the #QS_QF_ACTIVE_POST trace record, which are:
265  // the local filter for this AO ('me->prio') is set
266  //
267  if ((QS::priv_.locFilter[m_prio >> 3U]
268  & static_cast<std::uint8_t>(1U << (m_prio & 7U))) != 0U)
269  {
270  QS::onTestPost(nullptr, this, e, true);
271  }
272 #endif
273 
274  // read volatile into temporary
275  QEvt const * const frontEvt = m_eQueue.m_frontEvt;
276  m_eQueue.m_frontEvt = e; // deliver the event directly to the front
277 
278  // was the queue empty?
279  if (frontEvt == nullptr) {
280  QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
281  }
282  // queue was not empty, leave the event in the ring-buffer
283  else {
284  ++m_eQueue.m_tail;
285  if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail?
286  m_eQueue.m_tail = 0U; // wrap around
287  }
288 
289  QF_PTR_AT_(m_eQueue.m_ring, m_eQueue.m_tail) = frontEvt;
290  }
291  QF_CRIT_X_();
292 }
293 
294 //****************************************************************************
313 QEvt const *QActive::get_(void) noexcept {
315 
316  QF_CRIT_E_();
317  QACTIVE_EQUEUE_WAIT_(this); // wait for event to arrive directly
318 
319  // always remove evt from the front
320  QEvt const * const e = m_eQueue.m_frontEvt;
321  QEQueueCtr const nFree = m_eQueue.m_nFree + 1U;
322  m_eQueue.m_nFree = nFree; // upate the number of free
323 
324  // any events in the ring buffer?
325  if (nFree <= m_eQueue.m_end) {
326 
327  // remove event from the tail
328  m_eQueue.m_frontEvt = QF_PTR_AT_(m_eQueue.m_ring, m_eQueue.m_tail);
329  if (m_eQueue.m_tail == 0U) { // need to wrap?
330  m_eQueue.m_tail = m_eQueue.m_end; // wrap around
331  }
332  --m_eQueue.m_tail;
333 
335  QS_TIME_PRE_(); // timestamp
336  QS_SIG_PRE_(e->sig); // the signal of this event
337  QS_OBJ_PRE_(this); // this active object
338  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
339  QS_EQC_PRE_(nFree); // number of free entries
341  }
342  else {
343  // the queue becomes empty
344  m_eQueue.m_frontEvt = nullptr;
345 
346  // all entries in the queue must be free (+1 for fronEvt)
347  Q_ASSERT_CRIT_(310, nFree == (m_eQueue.m_end + 1U));
348 
350  QS_TIME_PRE_(); // timestamp
351  QS_SIG_PRE_(e->sig); // the signal of this event
352  QS_OBJ_PRE_(this); // this active object
353  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
355  }
356  QF_CRIT_X_();
357  return e;
358 }
359 
360 //****************************************************************************
379 
380  Q_REQUIRE_ID(400, (prio <= QF_MAX_ACTIVE)
381  && (active_[prio] != nullptr));
382 
384  QF_CRIT_E_();
385  std::uint_fast16_t const min =
386  static_cast<std::uint_fast16_t>(active_[prio]->m_eQueue.m_nMin);
387  QF_CRIT_X_();
388 
389  return min;
390 }
391 
392 //****************************************************************************
393 QTicker::QTicker(std::uint_fast8_t const tickRate) noexcept
394  : QActive(nullptr)
395 {
396  // reuse m_head for tick-rate
397  m_eQueue.m_head = static_cast<QEQueueCtr>(tickRate);
398 }
399 //............................................................................
400 void QTicker::init(void const * const e,
401  std::uint_fast8_t const qs_id) noexcept
402 {
403  static_cast<void>(e); // unused parameter
404  static_cast<void>(qs_id); // unused parameter
405  m_eQueue.m_tail = 0U;
406 }
407 //............................................................................
408 void QTicker::dispatch(QEvt const * const e,
409  std::uint_fast8_t const qs_id) noexcept
410 {
411  static_cast<void>(e); // unused parameter
412  static_cast<void>(qs_id); // unused parameter
413 
415  QF_CRIT_E_();
416  QEQueueCtr nTicks = m_eQueue.m_tail; // # ticks since the last call
417  m_eQueue.m_tail = 0U; // clear the # ticks
418  QF_CRIT_X_();
419 
420  for (; nTicks > 0U; --nTicks) {
421  QF::TICK_X(static_cast<std::uint_fast8_t>(m_eQueue.m_head), this);
422  }
423 }
424 //............................................................................
425 #ifdef Q_SPY
426 //****************************************************************************
430 bool QTicker::post_(QEvt const * const e, std::uint_fast16_t const margin,
431  void const * const sender) noexcept
432 #else
433 bool QTicker::post_(QEvt const * const e, std::uint_fast16_t const margin)
434  noexcept
435 #endif
436 {
437  static_cast<void>(e); // unused parameter
438  static_cast<void>(margin); // unused parameter
439 
441  QF_CRIT_E_();
442  if (m_eQueue.m_frontEvt == nullptr) {
443 
444 #ifdef Q_EVT_CTOR
445  static QEvt const tickEvt(0U, QEvt::STATIC_EVT);
446 #else
447  static QEvt const tickEvt = { 0U, 0U, 0U };
448 #endif // Q_EVT_CTOR
449 
450  m_eQueue.m_frontEvt = &tickEvt; // deliver event directly
451  --m_eQueue.m_nFree; // one less free event
452 
453  QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
454  }
455 
456  ++m_eQueue.m_tail; // account for one more tick event
457 
459  QS_TIME_PRE_(); // timestamp
460  QS_OBJ_PRE_(sender); // the sender object
461  QS_SIG_PRE_(0U); // the signal of the event
462  QS_OBJ_PRE_(this); // this active object
463  QS_2U8_PRE_(0U, 0U); // pool-Id & ref-ctr
464  QS_EQC_PRE_(0U); // number of free entries
465  QS_EQC_PRE_(0U); // min number of free entries
467 
468  QF_CRIT_X_();
469 
470  return true; // the event is always posted correctly
471 }
472 
473 //****************************************************************************
474 void QTicker::postLIFO(QEvt const * const e) noexcept {
475  static_cast<void>(e); // unused parameter
476  Q_ERROR_ID(900); // operation not allowed
477 }
478 
479 } // namespace QP
480 
unsigned int uint_fast16_t
Definition: 16bit/stdint.h:38
unsigned char uint8_t
Definition: 16bit/stdint.h:29
unsigned int uint_fast8_t
Definition: 16bit/stdint.h:36
friend class QTicker
Definition: qf.hpp:294
virtual void postLIFO(QEvt const *const e) noexcept
Definition: qf_actq.cpp:228
virtual bool post_(QEvt const *const e, std::uint_fast16_t const margin, void const *const sender) noexcept
Definition: qf_actq.cpp:90
QEvt const * get_(void) noexcept
Get an event from the event queue of an active object.
Definition: qf_actq.cpp:313
static std::uint_fast16_t getQueueMin(std::uint_fast8_t const prio) noexcept
Definition: qf_actq.cpp:378
static void gc(QEvt const *const e) noexcept
Recycle a dynamic event.
Definition: qf_dyn.cpp:219
static QS priv_
Definition: qs.hpp:554
static void onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status)
void init(void const *const e, std::uint_fast8_t const qs_id) noexcept override
executes the top-most initial transition in QP::QHsm
Definition: qf_actq.cpp:400
void postLIFO(QEvt const *const e) noexcept override
Definition: qf_actq.cpp:474
bool post_(QEvt const *const e, std::uint_fast16_t const margin, void const *const sender) noexcept override
Definition: qf_actq.cpp:430
void dispatch(QEvt const *const e, std::uint_fast8_t const qs_id) noexcept override
Dispatches an event to QHsm.
Definition: qf_actq.cpp:408
#define QACTIVE_EQUEUE_SIGNAL_(me_)
Definition: macros.hpp:87
#define QACTIVE_EQUEUE_WAIT_(me_)
using.
Definition: macros.hpp:71
Definition: struct.dox:1
std::uint8_t QEQueueCtr
Definition: qequeue.hpp:72
std::uint_fast16_t const QF_NO_MARGIN
Definition: qf.hpp:627
@ QS_QF_ACTIVE_POST_LIFO
an event was posted (LIFO) directly to AO
Definition: qs.hpp:83
@ QS_QF_ACTIVE_GET
AO got an event and its queue is not empty.
Definition: qs.hpp:84
@ QS_QF_ACTIVE_POST_ATTEMPT
attempt to post an evt to AO failed
Definition: qs.hpp:127
@ QS_QF_ACTIVE_POST
an event was posted (FIFO) directly to AO
Definition: qs.hpp:82
@ QS_QF_ACTIVE_GET_LAST
AO got an event and its queue is empty.
Definition: qs.hpp:85
void QF_EVT_REF_CTR_INC_(QEvt const *const e) noexcept
increment the refCtr_ of an event e
Definition: qf_pkg.hpp:150
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:120
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:279
#define Q_ERROR_ID(id_)
Definition: qassert.h:211
#define TICK_X(tickRate_, sender_)
Definition: qf.hpp:816
Internal (package scope) QF/C++ interface.
#define QF_CRIT_STAT_
Definition: qf_pkg.hpp:56
#define QF_PTR_AT_(base_, i_)
access element at index i_ from the base pointer base_
Definition: qf_pkg.hpp:171
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.hpp:94
#define QF_CRIT_X_()
Definition: qf_pkg.hpp:77
#define QF_CRIT_E_()
Definition: qf_pkg.hpp:66
#define Q_ERROR_CRIT_(id_)
Definition: qf_pkg.hpp:103
#define QS_TIME_PRE_()
Definition: qs.hpp:266
#define QS_TEST_PROBE_DEF(fun_)
QS macro to define the Test-Probe for a given fun_.
Definition: qs.hpp:1068
#define QS_TEST_PROBE_ID(id_, code_)
QS macro to apply a Test-Probe.
Definition: qs.hpp:1077
Dummy definitions of the QS macros that avoid code generation from the QS instrumentation.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Definition: qs_dummy.hpp:98
#define QS_OBJ_PRE_(obj_)
Definition: qs_dummy.hpp:107
#define QS_END_NOCRIT_PRE_()
Definition: qs_dummy.hpp:99
#define QS_2U8_PRE_(data1_, data2_)
Definition: qs_dummy.hpp:101
#define QS_SIG_PRE_(sig_)
Definition: qs_dummy.hpp:105
#define QS_EQC_PRE_(ctr_)
Definition: qs_dummy.hpp:109
Internal (package scope) QS/C++ interface.
QS/C++ port to a 32-bit CPU, generic compiler.
#define QF_MAX_ACTIVE
Definition: qxk/qf_port.hpp:57
QSignal sig
signal of the event instance
Definition: qep.hpp:210
std::uint8_t volatile refCtr_
reference counter
Definition: qep.hpp:212
std::uint8_t poolId_
pool ID (0 for static event)
Definition: qep.hpp:211