Beispiel #1
0
/* 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;
}
Beispiel #2
0
/*..........................................................................*/
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 {
Beispiel #3
0
/* 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
}
Beispiel #4
0
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 {
Beispiel #5
0
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);
}
Beispiel #6
0
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;
}
Beispiel #7
0
/*..........................................................................*/
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_()
    }
Beispiel #8
0
/*..........................................................................*/
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;
}
Beispiel #10
0
/*..........................................................................*/
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;
}
Beispiel #11
0
/*..........................................................................*/
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;
}
Beispiel #12
0
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_();
}
Beispiel #13
0
/*..........................................................................*/
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_();
}
Beispiel #14
0
/*..........................................................................*/
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;
}
Beispiel #15
0
//............................................................................
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_();
}
Beispiel #16
0
/*..........................................................................*/
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();
}
Beispiel #17
0
//............................................................................
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));
        }
    }
}
Beispiel #18
0
/**
* \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_();
}
Beispiel #19
0
/*..........................................................................*/
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_();
}
Beispiel #20
0
//............................................................................
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
        }
    }
Beispiel #21
0
/*..........................................................................*/
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_();
}
Beispiel #22
0
/*..........................................................................*/
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_();
}
Beispiel #23
0
/*..........................................................................*/
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;
}
Beispiel #24
0
//****************************************************************************
/// @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_();
}
Beispiel #25
0
/*..........................................................................*/
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_();
}
Beispiel #26
0
/*..........................................................................*/
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_();
}
Beispiel #27
0
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
        }
    }
}
Beispiel #28
0
/**
* \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
}
Beispiel #29
0
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
    }
}
Beispiel #30
0
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();
            }
        }