/*..........................................................................*/ uint8_t QActive_recall(QActive *me, QEQueue *eq) { QEvent const *e = QEQueue_get(eq); /* get an event from deferred queue */ uint8_t recalled; if (e != (QEvent const *)0) { /* event available? */ QF_CRIT_STAT_ QActive_postLIFO(me, e); /* post it to the front of the AO's queue */ QF_CRIT_ENTRY_(); if (QF_EVT_POOL_ID_(e) != (uint8_t)0) { /* is it a dynamic event? */ /* after posting to the AO's queue the event must be referenced * at least twice: once in the deferred event queue (eq->get() * did NOT decrement the reference counter) and once in the * AO's event queue. */ Q_ASSERT(QF_EVT_REF_CTR_(e) > (uint8_t)1); /* we need to decrement the reference counter once, to account * for removing the event from the deferred event queue. */ QF_EVT_REF_CTR_DEC_(e); /* decrement the reference counter */ } QF_CRIT_EXIT_(); recalled = (uint8_t)1; } else { recalled = (uint8_t)0; } return recalled; }
//**************************************************************************** /// @description /// This function implements a simple garbage collector for dynamic events. /// Only dynamic events are candidates for recycling. (A dynamic event is one /// that is allocated from an event pool, which is determined as non-zero /// e->poolId_ attribute.) Next, the function decrements the reference counter /// of the event (e->refCtr_), and recycles the event only if the counter /// drops to zero (meaning that no more references are outstanding for this /// event). The dynamic event is recycled by returning it to the pool from /// which it was originally allocated. /// /// @param[in] e pointer to the event to recycle /// /// @note /// QF invokes the garbage collector at all appropriate contexts, when /// an event can become garbage (automatic garbage collection), so the /// application code should have no need to call QP::QF::gc() directly. /// The QP::QF::gc() function is exposed only for special cases when your /// application sends dynamic events to the "raw" thread-safe queues /// (see QP::QEQueue). Such queues are processed outside of QF and the /// automatic garbage collection is **NOT** performed for these events. /// In this case you need to call QP::QF::gc() explicitly. /// void QF::gc(QEvt const * const e) { // is it a dynamic event? if (QF_EVT_POOL_ID_(e) != static_cast<uint8_t>(0)) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); // isn't this the last reference? if (e->refCtr_ > static_cast<uint8_t>(1)) { QF_EVT_REF_CTR_DEC_(e); // decrement the ref counter QS_BEGIN_NOCRIT_(QS_QF_GC_ATTEMPT, static_cast<void *>(0), static_cast<void *>(0)) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_2U8_(e->poolId_, e->refCtr_);// pool Id & refCtr of the evt QS_END_NOCRIT_() QF_CRIT_EXIT_(); } // this is the last reference to this event, recycle it else { uint_fast8_t idx = static_cast<uint_fast8_t>(e->poolId_) - static_cast<uint_fast8_t>(1); QS_BEGIN_NOCRIT_(QS_QF_GC, static_cast<void *>(0), static_cast<void *>(0)) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_2U8_(e->poolId_, e->refCtr_);// pool Id & refCtr of the evt QS_END_NOCRIT_() QF_CRIT_EXIT_(); // pool ID must be in range Q_ASSERT_ID(410, idx < QF_maxPool_); #ifdef Q_EVT_VIRTUAL // explicitly exectute the destructor' // NOTE: casting 'const' away is legitimate, // because it's a pool event QF_EVT_CONST_CAST_(e)->~QEvt(); // xtor, #endif // cast 'const' away, which is OK, because it's a pool event QF_EPOOL_PUT_(QF_pool_[idx], QF_EVT_CONST_CAST_(e)); } } }
//............................................................................ void QF::gc(QEvt const * const e) { if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (QF_EVT_REF_CTR_(e) > u8_1) { // isn't this the last reference? QF_EVT_REF_CTR_DEC_(e); // decrement the ref counter QS_BEGIN_NOCRIT_(QS_QF_GC_ATTEMPT, null_void, null_void) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_U8_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() QF_CRIT_EXIT_(); } else { // this is the last reference to this event, recycle it uint8_t idx = static_cast<uint8_t>(QF_EVT_POOL_ID_(e) - u8_1); QS_BEGIN_NOCRIT_(QS_QF_GC, null_void, null_void) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_U8_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() QF_CRIT_EXIT_(); Q_ASSERT(idx < QF_maxPool_); #ifdef Q_EVT_VIRTUAL QF_EVT_CONST_CAST_(e)->~QEvt(); // xtor, cast 'const' away, // which is legitimate, because it's a pool event #endif // cast 'const' away, which is OK, because it's a pool event QF_EPOOL_PUT_(QF_pool_[idx], QF_EVT_CONST_CAST_(e)); } } }
void QF_tick(void const * const sender) #endif { QTimeEvt *t; QTimeEvt *prev = (QTimeEvt *)0; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0) QS_TEC_((QTimeEvtCtr)(++QS_tickCtr_)); /* the tick counter */ QS_END_NOCRIT_() for (t = QF_timeEvtListHead_; t != (QTimeEvt *)0; t = t->next) { if (t->ctr == (QTimeEvtCtr)0) { /* time evt. scheduled for removal? */ if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->next; } else { Q_ASSERT(prev != (QTimeEvt *)0); prev->next = t->next; } QF_EVT_REF_CTR_DEC_(&t->super); /* mark as not linked */ } else { --t->ctr; if (t->ctr == (QTimeEvtCtr)0) { /* is time evt about to expire? */ if (t->interval != (QTimeEvtCtr)0) { /* periodic time evt? */ t->ctr = t->interval; /* rearm the time event */ } else { QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS_teObj_, t) QS_OBJ_(t); /* this time event object */ QS_OBJ_(t->act); /* the active object */ QS_END_NOCRIT_() } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS_teObj_, t) QS_TIME_(); /* timestamp */ QS_OBJ_(t); /* the time event object */ QS_SIG_(t->super.sig); /* signal of this time event */ QS_OBJ_(t->act); /* the active object */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); /* exit crit. section before posting */ /* QACTIVE_POST() asserts internally if the queue overflows */ QACTIVE_POST(t->act, &t->super, sender); QF_CRIT_ENTRY_(); /* re-enter crit. section to continue */ if (t->ctr == (QTimeEvtCtr)0) { /* still marked to expire? */ if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->next; } else { Q_ASSERT(prev != (QTimeEvt *)0); prev->next = t->next; } QF_EVT_REF_CTR_DEC_(&t->super); /* mark as removed */ } else { prev = t; } } else { prev = t; } } }