/* NOTE: disarm a timer (no harm in disarming an already disarmed timer) */ uint8_t QTimeEvt_disarm(QTimeEvt * const me) { uint8_t wasArmed; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (me->ctr != (QTimeEvtCtr)0) { /* is the time evt running? */ wasArmed = (uint8_t)1; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_DISARM, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the target AO */ QS_TEC_(me->ctr); /* the number of ticks */ QS_TEC_(me->interval); /* the interval */ QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/ QS_END_NOCRIT_() me->ctr = (QTimeEvtCtr)0; /* schedule removal from the list */ } else { /* the time event was already not running */ wasArmed = (uint8_t)0; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_DISARM_ATTEMPT, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the target AO */ QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/ QS_END_NOCRIT_() } QF_CRIT_EXIT_(); return wasArmed; }
/*..........................................................................*/ QEvent const *QEQueue_get(QEQueue *me) { QEvent const *e; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (me->frontEvt == (QEvent *)0) { /* is the queue empty? */ e = (QEvent *)0; /* no event available at this time */ } else { /* the queue is not empty */ e = me->frontEvt; if (me->nFree != me->end) { /* any events in the ring buffer? */ me->frontEvt = QF_PTR_AT_(me->ring, me->tail); /* get from tail */ if (me->tail == (QEQueueCtr)0) { /* need to wrap the tail? */ me->tail = me->end; /* wrap around */ } --me->tail; ++me->nFree; /* one more free event in the ring buffer */ QS_BEGIN_NOCRIT_(QS_QF_EQUEUE_GET, QS_eqObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this queue object */ 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_EQC_(me->nFree); /* number of free entries */ QS_END_NOCRIT_() } else {
/* NOTE: the QK scheduler is entered and exited with interrupts DISABLED */ void QK_sched_(uint8_t p) { uint8_t pin = QK_currPrio_; /* save the initial priority */ QActive *a; #ifdef QK_TLS /* thread-local storage used? */ uint8_t pprev = pin; #endif do { QEvt const *e; a = QF_active_[p]; /* obtain the pointer to the AO */ QK_currPrio_ = p; /* this becomes the current task priority */ #ifdef QK_TLS /* thread-local storage used? */ if (p != pprev) { /* are we changing threads? */ QK_TLS(a); /* switch new thread-local storage */ pprev = p; } #endif QS_BEGIN_NOCRIT_(QS_QK_SCHEDULE, QS_priv_.aoObjFilter, a) QS_TIME_(); /* timestamp */ QS_U8_(p); /* the priority of the AO */ QS_U8_(pin); /* the preempted priority */ QS_END_NOCRIT_() QF_INT_ENABLE(); /* unconditionally enable interrupts */ e = QActive_get_(a); /* get the next event for this AO */ QMSM_DISPATCH(&a->super, e); /* dispatch to the AO */ QF_gc(e); /* garbage collect the event, if necessary */ QF_INT_DISABLE(); /* disable interrupts */ #if (QF_MAX_ACTIVE <= 8) /* new highest-prio AO ready to run */ QPSet8_findMax(&QK_readySet_, p); #else QPSet64_findMax(&QK_readySet_, p); #endif if (p <= pin) { /* below the current preemption threshold? */ p = (uint8_t)0; } #ifndef QK_NO_MUTEX else if (p <= QK_ceilingPrio_) { /* below the mutex ceiling? */ p = (uint8_t)0; } else { /* empty */ } #endif } while (p != (uint8_t)0); QK_currPrio_ = pin; /* restore the initial priority */ #ifdef QK_TLS /* thread-local storage used? */ if (pin != (uint8_t)0) { /* no extended context for the idle loop */ a = QF_active_[pin]; /* the pointer to the preempted AO */ QK_TLS(a); /* restore the original TLS */ } #endif }
QP_BEGIN_ //Q_DEFINE_THIS_MODULE("qeq_get") //............................................................................ QEvt const *QEQueue::get(void) { QEvt const *e; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (m_frontEvt == null_evt) { // is the queue empty? e = null_evt; // no event available at this time } else { e = m_frontEvt; if (m_nFree != m_end) { // any events in the the ring buffer? m_frontEvt = QF_PTR_AT_(m_ring, m_tail); // remove from the tail if (m_tail == static_cast<QEQueueCtr>(0)) { // need to wrap? m_tail = m_end; // wrap around } --m_tail; ++m_nFree; // one more free event in the ring buffer QS_BEGIN_NOCRIT_(QS_QF_EQUEUE_GET, QS::eqObj_, this) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of this event QS_OBJ_(this); // this queue object 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_EQC_(m_nFree); // number of free entries QS_END_NOCRIT_() } else {
void QActive_postFIFO(QActive *me, QEvent const *e) { #else void QActive_postFIFO(QActive *me, QEvent const *e, void const *sender) { #endif QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_POST_FIFO, QS_aoObj_, me) QS_TIME_(); /* timestamp */ QS_OBJ_(sender); /* the sender object */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this active object (recipient) */ QS_U8_(EVT_POOL_ID(e)); /* the pool Id of the event */ QS_U8_(EVT_REF_CTR(e)); /* the ref count of the event */ QS_EQC_(0); /* number of free entries (unknown) */ QS_EQC_(0); /* min number of free entries (unknown) */ QS_END_NOLOCK_() if (EVT_POOL_ID(e) != (uint8_t)0) { /* is it a pool event? */ EVT_INC_REF_CTR(e); /* increment the reference counter */ } QF_INT_UNLOCK_(); Q_ALLEGE(OSQPost((OS_EVENT *)me->eQueue, (void *)e) == OS_NO_ERR); }
uint8_t QS_onStartup(void const *arg) { qsBuf = kmalloc(QS_SPY_SIZE, GFP_KERNEL); if (qsBuf == NULL) return 0; QS_initBuf(qsBuf, QS_SPY_SIZE); QS_FILTER_ON(QS_ALL_RECORDS); QS_FILTER_OFF(QS_QF_TICK); QS_BEGIN_NOCRIT_(QS_QEP_RESERVED0, (void *)0, (void *)0) QS_U8_(QS_TIME_SIZE); QS_U8_(QS_OBJ_PTR_SIZE); QS_U8_(QS_FUN_PTR_SIZE); QS_U8_(Q_SIGNAL_SIZE); QS_U8_(QF_EQUEUE_CTR_SIZE); QS_U8_(QF_EQUEUE_CTR_SIZE); QS_U8_(QF_MPOOL_CTR_SIZE); QS_U8_(QF_MPOOL_SIZ_SIZE); QS_U8_(QF_TIMEEVT_CTR_SIZE); QS_END_NOCRIT_(); return 1; }
/*..........................................................................*/ QEvent const *QActive_get_(QActive *me) { QEvent const *e; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly ^#defined as: Q_ASSERT((me_)->eQueue.frontEvt != (QEvent *)0) */ e = me->eQueue.frontEvt; if (me->eQueue.nFree != me->eQueue.end) { /* any events in the buffer? */ /* remove event from the tail */ me->eQueue.frontEvt = me->eQueue.ring[me->eQueue.tail]; if (me->eQueue.tail == (QEQueueCtr)0) { /* need to wrap the tail? */ me->eQueue.tail = me->eQueue.end; /* wrap around */ } --me->eQueue.tail; ++me->eQueue.nFree; /* one more free event in the ring buffer */ QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_GET, QS_aoObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this active object */ QS_U8_(e->dynamic_); /* the dynamic attribute of the event */ QS_EQC_(me->eQueue.nFree); /* number of free entries */ QS_END_NOLOCK_() }
/*..........................................................................*/ QEvent const *QEQueue_get(QEQueue *me) { QEvent const *e; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if (me->frontEvt == (QEvent *)0) { /* is the queue empty? */ e = (QEvent const *)0; /* no event available at this time */ } else { /* the queue is not empty */ e = me->frontEvt; if (me->nFree != me->end) { /* any events in the ring buffer? */ me->frontEvt = me->ring[me->tail]; /* remove from the tail */ if (me->tail == (QEQueueCtr)0) { /* need to wrap the tail? */ me->tail = me->end; /* wrap around */ } --me->tail; ++me->nFree; /* one more free event in the ring buffer */ QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_GET, QS_eqObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this queue object */ QS_U8_(e->dynamic_); /* the dynamic attribute of the event */ QS_EQC_(me->nFree); /* number of free entries */ QS_END_NOLOCK_() } else {
/*..........................................................................*/ uint8_t QTimeEvt_rearm(QTimeEvt * const me, QTimeEvtCtr const nTicks) { uint8_t isArmed; QF_CRIT_STAT_ Q_REQUIRE((nTicks != (QTimeEvtCtr)0) /* cannot arm a timer with 0 ticks */ && (me->act != (QActive *)0) /* active object must be valid */ && (me->super.sig >= (QSignal)Q_USER_SIG)); /* valid signal */ QF_CRIT_ENTRY_(); if (me->ctr == (QTimeEvtCtr)0) { /* is the time evt disarmed? */ isArmed = (uint8_t)0; if (QF_EVT_REF_CTR_(&me->super) == (uint8_t)0) { /* not linked? */ me->next = QF_timeEvtListHead_; QF_timeEvtListHead_ = me; QF_EVT_REF_CTR_INC_(&me->super); /* mark as linked */ } } else { /* the time event is armed */ isArmed = (uint8_t)1; } me->ctr = nTicks; /* re-load the tick counter (shift the phasing) */ QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_REARM, QS_teObj_, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the active object */ QS_TEC_(me->ctr); /* the number of ticks */ QS_TEC_(me->interval); /* the interval */ QS_U8_(isArmed); /* was the timer armed? */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); return isArmed; }
/*..........................................................................*/ QMutex QK_mutexLock(uint8_t prioCeiling) { uint8_t mutex; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); mutex = QK_ceilingPrio_; /* the original QK priority ceiling to return */ if (QK_ceilingPrio_ < prioCeiling) { QK_ceilingPrio_ = prioCeiling; /* raise the QK priority ceiling */ } QS_BEGIN_NOCRIT_(QS_QK_MUTEX_LOCK, (void *)0, (void *)0) QS_TIME_(); /* timestamp */ QS_U8_(mutex); /* the original priority */ QS_U8_(QK_ceilingPrio_); /* the current priority ceiling */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); return mutex; }
/*..........................................................................*/ QEvent const *QActive_get_(QActive *me) { INT8U err; QEvent const *e = (QEvent *)OSQPend((OS_EVENT *)me->eQueue, 0, &err); QS_INT_LOCK_KEY_ Q_ASSERT(err == OS_NO_ERR); QS_BEGIN_(QS_QF_ACTIVE_GET, QS_aoObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this active object */ QS_U8_(EVT_POOL_ID(e)); /* the pool Id of the event */ QS_U8_(EVT_REF_CTR(e)); /* the ref count of the event */ QS_EQC_(0); /* number of free entries (unknown) */ QS_END_() return e; }
void QActive_postFIFO(QActive *me, QEvent const *e) { #else void QActive_postFIFO(QActive *me, QEvent const *e, void const *sender) { #endif QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_POST_FIFO, QS_aoObj_, me) QS_TIME_(); /* timestamp */ QS_OBJ_(sender); /* the sender object */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this active object (recipient) */ QS_U8_(EVT_POOL_ID(e)); /* the pool Id of the event */ QS_U8_(EVT_REF_CTR(e)); /* the ref count of the event */ QS_EQC_(me->eQueue.nFree); /* number of free entries */ QS_EQC_(me->eQueue.nMin); /* min number of free entries */ QS_END_NOLOCK_() if (EVT_POOL_ID(e) != (uint8_t)0) { /* is it a pool event? */ EVT_INC_REF_CTR(e); /* increment the reference counter */ } if (me->eQueue.frontEvt == (QEvent *)0) { /* empty queue? */ me->eQueue.frontEvt = e; /* deliver event directly */ QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */ } else { /* queue is not empty, insert event into the ring-buffer */ /* the queue must be able to accept the event (cannot overflow) */ Q_ASSERT(me->eQueue.nFree != (QEQueueCtr)0); /* insert event into the ring buffer (FIFO) */ me->eQueue.ring[me->eQueue.head] = e; if (me->eQueue.head == (QEQueueCtr)0) { /* need to wrap the head? */ me->eQueue.head = me->eQueue.end; /* wrap around */ } --me->eQueue.head; --me->eQueue.nFree; /* update number of free events */ if (me->eQueue.nMin > me->eQueue.nFree) { me->eQueue.nMin = me->eQueue.nFree; /* update min so far */ } } QF_INT_UNLOCK_(); }
/*..........................................................................*/ void QK_mutexUnlock(QMutex mutex) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QK_MUTEX_UNLOCK, (void *)0, (void *)0) QS_TIME_(); /* timestamp */ QS_U8_(mutex); /* the original priority */ QS_U8_(QK_ceilingPrio_); /* the current priority ceiling */ QS_END_NOCRIT_() if (QK_ceilingPrio_ > mutex) { QK_ceilingPrio_ = mutex; /* restore the saved priority ceiling */ mutex = QK_schedPrio_(); /* reuse 'mutex' to hold priority */ if (mutex != (uint8_t)0) { QK_sched_(mutex); } } QF_CRIT_EXIT_(); }
/*..........................................................................*/ QEvent const *QActive_get_(QActive *me) { QEvent const *e; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QACTIVE_OSOBJECT_WAIT_(me); /* wait for event to arrive directly */ e = me->eQueue__.frontEvt__; if (me->eQueue__.nUsed__ != (QEQueueCtr)0) {/*any events in the buffer? */ /* remove from the tail */ me->eQueue__.frontEvt__ = me->eQueue__.ring__[me->eQueue__.tail__]; ++me->eQueue__.tail__; if (me->eQueue__.tail__ == me->eQueue__.end__) { /* wrap around? */ me->eQueue__.tail__ = (QEQueueCtr)0; /* wrap the tail */ } --me->eQueue__.nUsed__; /* one less event in the ring buffer */ QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_GET, QS_aoObj_, me); QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this active object */ QS_U8_(e->attrQF__); /* the QF attribute of the event */ QS_EQC_(me->eQueue__.nUsed__); /* number of used entries */ QS_END_NOLOCK_(); } else { me->eQueue__.frontEvt__ = (QEvent const *)0; /* queue becomes empty */ QACTIVE_OSOBJECT_ONIDLE_(me); QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_GET_LAST, QS_aoObj_, me); QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this active object */ QS_U8_(e->attrQF__); /* the QF attribute of the event */ QS_END_NOLOCK_(); } QF_INT_UNLOCK_(); return e; }
//............................................................................ void QActive::postLIFO(QEvt const * const e) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_POST_LIFO, QS::aoObj_, this) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of this event QS_OBJ_(this); // this active object 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_EQC_(m_eQueue.m_nFree); // number of free entries QS_EQC_(m_eQueue.m_nMin); // min number of free entries QS_END_NOCRIT_() if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_EVT_REF_CTR_INC_(e); // increment the reference counter } if (m_eQueue.m_frontEvt == null_evt) { // is the queue empty? m_eQueue.m_frontEvt = e; // deliver event directly QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue } else { // queue is not empty, leave event in the ring-buffer // queue must accept all posted events Q_ASSERT(m_eQueue.m_nFree != static_cast<QEQueueCtr>(0)); ++m_eQueue.m_tail; if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail? m_eQueue.m_tail = static_cast<QEQueueCtr>(0); // wrap around } QF_PTR_AT_(m_eQueue.m_ring, m_eQueue.m_tail) = m_eQueue.m_frontEvt; m_eQueue.m_frontEvt = e; // put event to front --m_eQueue.m_nFree; // update number of free events if (m_eQueue.m_nMin > m_eQueue.m_nFree) { m_eQueue.m_nMin = m_eQueue.m_nFree; // update minimum so far } } QF_CRIT_EXIT_(); }
/*..........................................................................*/ void QS_usr_dict(enum_t const rec, char_t const Q_ROM * const name) { QS_CRIT_STAT_ QS_CRIT_ENTRY_(); QS_beginRec((uint8_t)QS_USR_DICT); QS_U8_((uint8_t)rec); QS_STR_ROM_(name); QS_endRec(); QS_CRIT_EXIT_(); QS_onFlush(); }
//............................................................................ 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)); } } }
/** * \description * Arms a time event to fire in a specified number of clock ticks and with * a specified interval. If the interval is zero, the time event is armed for * one shot ('one-shot' time event). The time event gets directly posted * (using the FIFO policy) into the event queue of the host active object. * * \arguments * \arg[in,out] \c me pointer (see \ref derivation) * \arg[in] \c nTicks number of clock ticks (at the associated rate) * to rearm the time event with. * \arg[in] \c interval interval (in clock ticks) for periodic time event. * * \note After posting, a one-shot time event gets automatically disarmed * while a periodic time event (interval != 0) is automatically re-armed. * * \note A time event can be disarmed at any time by calling the * QTimeEvt_disarm() function. Also, a time event can be re-armed to fire * in a different number of clock ticks by calling the QTimeEvt_rearm() * function. * * \usage * The following example shows how to arm a one-shot time event from a state * machine of an active object: * \include qf_state.c */ void QTimeEvt_armX(QTimeEvt * const me, QTimeEvtCtr const nTicks, QTimeEvtCtr const interval) { uint_fast8_t tickRate = (uint_fast8_t)me->super.refCtr_ & (uint_fast8_t)0x7F; QTimeEvtCtr ctr = me->ctr; QF_CRIT_STAT_ /** \pre the host AO must be valid, time evnet must be disarmed, * number of clock ticks cannot be zero, and the signal must be valid. */ Q_REQUIRE_ID(100, (me->act != (void *)0) && (ctr == (QTimeEvtCtr)0) && (nTicks != (QTimeEvtCtr)0) && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE) && (me->super.sig >= (QSignal)Q_USER_SIG)); QF_CRIT_ENTRY_(); me->ctr = nTicks; me->interval = interval; /* is the time event unlinked? * NOTE: For the duration of a single clock tick of the specified tick * rate a time event can be disarmed and yet still linked into the list, * because un-linking is performed exclusively in the QF_tickX() function. */ if ((me->super.refCtr_ & (uint8_t)0x80) == (uint8_t)0) { me->super.refCtr_ |= (uint8_t)0x80; /* mark as linked */ /* The time event is initially inserted into the separate * "freshly armed" link list based on QF_timeEvtHead_[tickRate].act. * Only later, inside the QF_tickX() function, the "freshly armed" * list is appended to the main list of armed time events based on * QF_timeEvtHead_[tickRate].next. Again, this is to keep any * changes to the main list exclusively inside the QF_tickX() * function. */ me->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act; QF_timeEvtHead_[tickRate].act = me; } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_ARM, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the active object */ QS_TEC_(nTicks); /* the number of ticks */ QS_TEC_(interval); /* the interval */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); }
/*..........................................................................*/ void QEQueue_postLIFO(QEQueue *me, QEvent const *e) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_EQUEUE_POST_LIFO, QS_eqObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this queue object */ 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_EQC_(me->nFree); /* number of free entries */ QS_EQC_(me->nMin); /* min number of free entries */ QS_END_NOCRIT_() if (QF_EVT_POOL_ID_(e) != (uint8_t)0) { /* is it a pool event? */ QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */ } if (me->frontEvt != (QEvent *)0) { /* is the queue not empty? */ /* the queue must be able to accept the event (cannot overflow) */ Q_ASSERT(me->nFree != (QEQueueCtr)0); ++me->tail; if (me->tail == me->end) { /* need to wrap the tail? */ me->tail = (QEQueueCtr)0; /* wrap around */ } QF_PTR_AT_(me->ring, me->tail) = me->frontEvt;/* save old front evt */ --me->nFree; /* update number of free events */ if (me->nMin > me->nFree) { me->nMin = me->nFree; /* update minimum so far */ } } me->frontEvt = e; /* stick the new event to the front */ QF_CRIT_EXIT_(); }
//............................................................................ void QF::gc(QEvent const *e) { if (e->dynamic_ != (uint8_t)0) { // is it a dynamic event? QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if ((e->dynamic_ & 0x3F) > 1) { // isn't this the last reference? //lint -e1773 Attempt to cast away const --((QEvent *)e)->dynamic_; // decrement the reference counter // NOTE: cast the 'const' away, which is legitimate because // it's a dynamic event QS_BEGIN_NOLOCK_(QS_QF_GC_ATTEMPT, (void *)0, (void *)0) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_U8_(e->dynamic_); // the dynamic attributes of the event QS_END_NOLOCK_() QF_INT_UNLOCK_(); } else { // this is the last reference to this event, recycle it uint8_t idx = (uint8_t)((e->dynamic_ >> 6) - 1); QS_BEGIN_NOLOCK_(QS_QF_GC, (void *)0, (void *)0) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_U8_(e->dynamic_); // the dynamic attributes of the event QS_END_NOLOCK_() QF_INT_UNLOCK_(); Q_ASSERT(idx < QF_maxPool_); //lint -e1773 Attempt to cast away const QF_EPOOL_PUT_(QF_pool_[idx], (QEvent *)e); // cast 'const' away, // which is legitimate, because it's a pool event } }
/*..........................................................................*/ void QF_remove_(QActive const *a) { uint8_t p = a->prio; QF_INT_LOCK_KEY_ Q_REQUIRE(((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE) && (QF_active_[p] == a)); QF_INT_LOCK_(); QF_active_[p] = (QActive *)0; /* free-up the priority level */ QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_REMOVE, QS_aoObj_, a) QS_TIME_(); /* timestamp */ QS_OBJ_(a); /* the active object */ QS_U8_(p); /* the priority of the active object */ QS_END_NOLOCK_() QF_INT_UNLOCK_(); }
/*..........................................................................*/ void QF_add_(QActive *a) { uint8_t p = a->prio; QF_INT_LOCK_KEY_ Q_REQUIRE(((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE) && (QF_active_[p] == (QActive *)0)); QF_INT_LOCK_(); QF_active_[p] = a; /* registger the active object at this priority */ QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_ADD, QS_aoObj_, a) QS_TIME_(); /* timestamp */ QS_OBJ_(a); /* the active object */ QS_U8_(p); /* the priority of the active object */ QS_END_NOLOCK_() QF_INT_UNLOCK_(); }
/*..........................................................................*/ QTimeEvtCtr QTimeEvt_ctr(QTimeEvt const * const me) { QTimeEvtCtr ret; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); ret = me->ctr; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_CTR, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the target AO */ QS_TEC_(ret); /* the current counter */ QS_TEC_(me->interval); /* the interval */ QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F)); /* tick rate */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); return ret; }
//**************************************************************************** /// @description /// This function removes a given active object from the active objects /// managed by the QF framework. It should not be called by the application /// directly, only through the function QP::QMActive::stop(). /// /// @param[in] a pointer to the active object to remove from the framework. /// /// @note The active object that is removed from the framework can no longer /// participate in the publish-subscribe event exchange. /// /// @sa QP::QF::add_() /// void QF::remove_(QMActive const * const a) { uint_fast8_t p = a->m_prio; Q_REQUIRE_ID(200, (static_cast<uint_fast8_t>(0) < p) && (p <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE)) && (active_[p] == a)); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); active_[p] = static_cast<QMActive *>(0); // free-up the priority level QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_REMOVE, QS::priv_.aoObjFilter, a) QS_TIME_(); // timestamp QS_OBJ_(a); // the active object QS_U8_(p); // the priority of the active object QS_END_NOCRIT_() QF_CRIT_EXIT_(); }
/*..........................................................................*/ void QEQueue_postLIFO(QEQueue *me, QEvent const *e) { QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_POST_LIFO, QS_eqObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this queue object */ QS_U8_(e->dynamic_); /* the dynamic attribute of the event */ QS_EQC_(me->nFree); /* number of free entries */ QS_EQC_(me->nMin); /* min number of free entries */ QS_END_NOLOCK_() if (e->dynamic_ != (uint8_t)0) { /* is it a pool event? */ ++((QEvent *)e)->dynamic_; /* increment the reference counter */ /* NOTE: cast the 'const' away, which is legitimate because * it's a dynamic event */ } if (me->frontEvt != (QEvent *)0) { /* is the queue not empty? */ /* the queue must be able to accept the event (cannot overflow) */ Q_ASSERT(me->nFree != (QEQueueCtr)0); ++me->tail; if (me->tail == me->end) { /* need to wrap the tail? */ me->tail = (QEQueueCtr)0; /* wrap around */ } me->ring[me->tail] = me->frontEvt; /* buffer the old front evt */ --me->nFree; /* update number of free events */ if (me->nMin > me->nFree) { me->nMin = me->nFree; /* update minimum so far */ } } me->frontEvt = e; /* stick the new event to the front */ QF_INT_UNLOCK_(); }
/*..........................................................................*/ void QEQueue_postFIFO(QEQueue *me, QEvent const *e) { QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_POST_FIFO, QS_eqObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this queue object */ QS_U8_(e->dynamic_); /* the dynamic attribute of the event */ QS_EQC_(me->nFree); /* number of free entries */ QS_EQC_(me->nMin); /* min number of free entries */ QS_END_NOLOCK_() if (e->dynamic_ != (uint8_t)0) { /* is it a pool event? */ ++((QEvent *)e)->dynamic_; /* increment the reference counter */ /* NOTE: cast the 'const' away, which is legitimate because * it's a dynamic event */ } if (me->frontEvt == (QEvent *)0) { /* is the queue empty? */ me->frontEvt = e; /* deliver event directly */ } else { /* queue is not empty, leave event in the ring-buffer */ /* the queue must be able to accept the event (cannot overflow) */ Q_ASSERT(me->nFree != (QEQueueCtr)0); me->ring[me->head] = e; /* insert event into the buffer (FIFO) */ if (me->head == (QEQueueCtr)0) { /* need to wrap the head? */ me->head = me->end; /* wrap around */ } --me->head; --me->nFree; /* update number of free events */ if (me->nMin > me->nFree) { me->nMin = me->nFree; /* update minimum so far */ } } QF_INT_UNLOCK_(); }
void QK_schedule_(void) { #else void QK_schedule_(QF_INT_KEY_TYPE intLockKey_) { #endif uint8_t p; /* the QK scheduler must be called at task level only */ Q_REQUIRE(QK_intNest_ == (uint8_t)0); #if (QF_MAX_ACTIVE <= 8) if (QPSet8_notEmpty(&QK_readySet_)) { /* determine the priority of the highest-priority task ready to run */ QPSet8_findMax(&QK_readySet_, p); #else if (QPSet64_notEmpty(&QK_readySet_)) { /* determine the priority of the highest-priority task ready to run */ QPSet64_findMax(&QK_readySet_, p); #endif #ifdef QK_NO_MUTEX if (p > QK_currPrio_) { /* do we have a preemption? */ #else /* QK priority-ceiling mutexes allowed */ if ((p > QK_currPrio_) && (p > QK_ceilingPrio_)) { #endif uint8_t pin = QK_currPrio_; /* save the initial priority */ QActive *a; #ifdef QK_TLS /* thread-local storage used? */ uint8_t pprev = pin; #endif do { QEvent const *e; a = QF_active_[p]; /* obtain the pointer to the AO */ QK_currPrio_ = p; /* this becomes the current task priority */ #ifdef QK_TLS /* thread-local storage used? */ if (p != pprev) { /* are we changing threads? */ QK_TLS(a); /* switch new thread-local storage */ pprev = p; } #endif QS_BEGIN_NOLOCK_(QS_QK_SCHEDULE, QS_aoObj_, a) QS_TIME_(); /* timestamp */ QS_U8_(p); /* the priority of the AO */ QS_U8_(pin); /* the preempted priority */ QS_END_NOLOCK_() QK_INT_UNLOCK_(); /* unlock the interrupts */ e = QActive_get_(a); /* get the next event for this AO */ QF_ACTIVE_DISPATCH_(&a->super, e); /* dispatch to the AO */ QF_gc(e); /* garbage collect the event, if necessary */ QK_INT_LOCK_(); /* determine the highest-priority AO ready to run */ #if (QF_MAX_ACTIVE <= 8) if (QPSet8_notEmpty(&QK_readySet_)) { QPSet8_findMax(&QK_readySet_, p); #else if (QPSet64_notEmpty(&QK_readySet_)) { QPSet64_findMax(&QK_readySet_, p); #endif } else { p = (uint8_t)0; } #ifdef QK_NO_MUTEX } while (p > pin); /* is the new priority higher than initial? */ #else /* QK priority-ceiling mutexes allowed */ } while ((p > pin) && (p > QK_ceilingPrio_)); #endif QK_currPrio_ = pin; /* restore the initial priority */ #ifdef QK_TLS /* thread-local storage used? */ if (pin != (uint8_t)0) {/*no extended context for the idle loop */ a = QF_active_[pin]; /* the pointer to the preempted AO */ QK_TLS(a); /* restore the original TLS */ } #endif } } }
/** * \description * The "extended" QK scheduler performs all the steps of the regular scheduler * QK_sched_() and additionally switches the Thread-Local Storage (TLS) and * handles the extended context-switch. * * \arguments * \arg[in] \c p priority of the next AO to schedule * * \note The "extended" QK scheduler needs to be called only to handle * "asynchronous" preemption, under the assumption that neither the ISRs * nor the QK idle loop use TLS or the co-processors requiring * extended context switch (see [PSiCC2] Section 10.4.3). * * \note QK_schedExt_() must be always called with interrupts DISABLED. * * \note The extended scheduler might enable interrupts internally, * but always returns with interrupts DISABLED. */ void QK_schedExt_(uint_fast8_t p) { uint_fast8_t pin = QK_currPrio_; /* save the initial priority */ /* thread-local storage used? */ #ifdef QK_TLS uint_fast8_t pprev = pin; #endif QActive *a; /* extended context-switch used? */ #ifdef QK_EXT_SAVE /* aren't we preempting the idle loop? (idle loop has prio==0) */ if (pin != (uint_fast8_t)0) { a = QF_active_[pin]; /* the pointer to the preempted AO */ QK_EXT_SAVE(a); /* save the extended context */ } #endif /* loop until have ready-to-run AOs of higher priority than the initial */ do { QEvt const *e; a = QF_active_[p]; /* obtain the pointer to the AO */ QK_currPrio_ = p; /* this becomes the current task priority */ /* thread-local storage used? */ #ifdef QK_TLS /* are we changing threads? */ if (p != pprev) { QK_TLS(a); /* switch new thread-local storage */ pprev = p; } #endif QS_BEGIN_NOCRIT_(QS_QK_SCHEDULE, QS_priv_.aoObjFilter, a) QS_TIME_(); /* timestamp */ QS_U8_((uint8_t)p); /* the priority of the AO */ QS_U8_((uint8_t)pin); /* the preempted priority */ QS_END_NOCRIT_() QF_INT_ENABLE(); /* unconditionally enable interrupts */ /* perform the run-to-completion (RTS) step... * 1. retrieve the event from the AO's event queue, which by this * time must be non-empty and QActive_get_() asserts it. * 2. dispatch the event to the AO's state machine. * 3. determine if event is garbage and collect it if so */ e = QActive_get_(a); QMSM_DISPATCH(&a->super, e); QF_gc(e); QF_INT_DISABLE(); /* disable interrupts */ /* find new highest-priority AO ready to run... */ #if (QF_MAX_ACTIVE <= 8) QPSet8_findMax(&QK_readySet_, p); #else QPSet64_findMax(&QK_readySet_, p); #endif /* is the new priority below the current preemption threshold? */ if (p <= pin) { p = (uint_fast8_t)0; } #ifndef QK_NO_MUTEX /* is the new priority below the mutex ceiling? */ else if (p <= QK_ceilingPrio_) { p = (uint_fast8_t)0; } else { /* empty */ } #endif } while (p != (uint_fast8_t)0); QK_currPrio_ = pin; /* restore the initial priority */ #if defined(QK_TLS) || defined(QK_EXT_RESTORE) /* aren't we preempting the idle loop? (idle loop has prio==0) */ if (pin != (uint_fast8_t)0) { a = QF_active_[pin]; /* the pointer to the preempted AO */ /* thread-local storage used? */ #ifdef QK_TLS QK_TLS(a); /* restore the original TLS */ #endif /* extended context-switch used? */ #ifdef QK_EXT_RESTORE QK_EXT_RESTORE(a); /* restore the extended context */ #endif } #endif }
void QK_scheduleExt_(void) { #else void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey_) { #endif // the QK scheduler must be called at task level only Q_REQUIRE(QK_intNest_ == (uint8_t)0); // determine the priority of the highest-priority task ready to run uint8_t p = QK_readySet_.findMax(); #ifdef QK_NO_MUTEX if (p > QK_currPrio_) { // do we have a preemption? #else // QK priority-ceiling mutexes allowed if ((p > QK_currPrio_) && (p > QK_ceilingPrio_)) { #endif uint8_t pin = QK_currPrio_; // save the initial priority QActive *a; #ifdef QK_TLS // thread-local storage used? uint8_t pprev = pin; #endif #ifdef QK_EXT_SAVE // extended context-switch used? if (pin != (uint8_t)0) { // no extended context for the idle loop a = QF::active_[pin]; // the pointer to the preempted AO QK_EXT_SAVE(a); // save the extended context } #endif do { QEvent const *e; a = QF::active_[p]; // obtain the pointer to the AO QK_currPrio_ = p; // this becomes the current task priority #ifdef QK_TLS // thread-local storage used? if (p != pprev) { // are we changing threads? QK_TLS(a); // switch new thread-local storage pprev = p; } #endif QS_BEGIN_NOLOCK_(QS_QK_SCHEDULE, QS::aoObj_, a) QS_TIME_(); // timestamp QS_U8_(p); // the priority of the active object QS_U8_(pin); // the preempted priority QS_END_NOLOCK_() QK_INT_UNLOCK_(); // unlock the interrupts e = a->get_(); // get the next event for this active object a->dispatch(e); // dispatch e to the active object QF::gc(e); // garbage collect the event, if necessary QK_INT_LOCK_(); // determine the highest-priority AO ready to run p = QK_readySet_.findMax(); #ifdef QK_NO_MUTEX } while (p > pin); // is the new priority higher than initial? #else // QK priority-ceiling mutexes allowed } while ((p > pin) && (p > QK_ceilingPrio_)); #endif QK_currPrio_ = pin; // restore the initial priority #if defined(QK_TLS) || defined(QK_EXT_RESTORE) if (pin != (uint8_t)0) { // no extended context for the idle loop a = QF::active_[pin]; // the pointer to the preempted AO #ifdef QK_TLS // thread-local storage used? QK_TLS(a); // restore the original TLS #endif #ifdef QK_EXT_RESTORE // extended context-switch used? QK_EXT_RESTORE(a); // restore the extended context #endif } #endif } }
void QF_tickX_(uint_fast8_t const tickRate, void const * const sender) #endif { QTimeEvt *prev = &QF_timeEvtHead_[tickRate]; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0) QS_TEC_((QTimeEvtCtr)(++prev->ctr)); /* tick ctr */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() /* scan the linked-list of time events at this rate... */ for (;;) { QTimeEvt *t = prev->next; /* advance down the time evt. list */ /* end of the list? */ if (t == (QTimeEvt *)0) { /* any new time events armed since the last run of QF_tickX_()? */ if (QF_timeEvtHead_[tickRate].act != (void *)0) { /* sanity check */ Q_ASSERT_ID(110, prev != (QTimeEvt *)0); prev->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act; QF_timeEvtHead_[tickRate].act = (void *)0; t = prev->next; /* switch to the new list */ } else { break; /* all currently armed time evts. processed */ } } /* time event scheduled for removal? */ if (t->ctr == (QTimeEvtCtr)0) { prev->next = t->next; t->super.refCtr_ &= (uint8_t)0x7F; /* mark as unlinked */ /* do NOT advance the prev pointer */ QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */ /* prevent merging critical sections, see NOTE1 below */ QF_CRIT_EXIT_NOP(); } else { --t->ctr; /* is time event about to expire? */ if (t->ctr == (QTimeEvtCtr)0) { QMActive *act = (QMActive *)t->act; /* temp. for volatile */ /* periodic time evt? */ if (t->interval != (QTimeEvtCtr)0) { t->ctr = t->interval; /* rearm the time event */ prev = t; /* advance to this time event */ } /* one-shot time event: automatically disarm */ else { prev->next = t->next; t->super.refCtr_ &= (uint8_t)0x7F; /* mark as unlinked */ /* do NOT advance the prev pointer */ QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS_priv_.teObjFilter, t) QS_OBJ_(t); /* this time event object */ QS_OBJ_(act); /* the target AO */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS_priv_.teObjFilter, t) QS_TIME_(); /* timestamp */ QS_OBJ_(t); /* the time event object */ QS_SIG_(t->super.sig); /* signal of this time event */ QS_OBJ_(act); /* the target AO */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); /* exit critical section before posting */ /* QACTIVE_POST() asserts internally if the queue overflows */ QACTIVE_POST(act, &t->super, sender); } else { prev = t; /* advance to this time event */ QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */ /* prevent merging critical sections, see NOTE1 below */ QF_CRIT_EXIT_NOP(); } }