[En-Nut-Discussion] RTOS Comparison

Harald Kipp harald.kipp at egnite.de
Mon Mar 22 14:23:46 CET 2010


Hi Nathan,

Nathan Moore wrote:

> If I recall correctly the entire timer list is walked every time the
> scheduler is called.

Which code do you mean? AFAIK, the timer list _is_ a sorted list, at
least since version4, may be earlier.

The related function is NutTimerProcessElapsed(). The loop is

while (nutTimerList && ticks_new) {
}

ticks_new contains the number of ticks elapsed since the last context
switch. If the ticks_left counter of the timer on top is larger, is
reduced by ticks_new and loop is exited. Otherwise the next timer is
processed until the summed up ticks_left counters reach ticks_new.

In other words, only the first and all elapsed timers are processed.


> Every time an even was posted and a thread was waiting the
> thread would be taken off the top of the eventqueue ( O(1) operation) pushed
> onto this stack ( O(1) operation).  This would be the same in ISRs and in
> applications.
> NutEventPost( void * event) {
>     NutEnterCritical();
>     NutPostEventFromISR(event, -1); // The second param is what to put
> on the event queue if it is empty
>     NutExitCritical();
> }
> NutEventPostNext( void * event) {
>     NutEnterCritical();
>     NutPostEventFromISR(event, NULL);
>     NutExitCritical();
> }
> NutPostEventFromISR is just a pop from the event waiting queue and a push
> to a stack.

In general I support your idea of a separate thread stack. Not sure yet,
how it would behave in detail. Wouldn't this significantly increase
interrupt latency, when compared to the current implementation?

#define NutEventPostFromIrq(qp)     \
{                                   \
    if (*qp == 0) {                 \
        *qp = SIGNALED;             \
    }                               \
    else if (*qp != SIGNALED) {     \
        NUTTHREADINFO *tp = (NUTTHREADINFO *)(*qp);    \
        tp->td_qpec++;              \
    }                               \
}

On ARM this requires a few cycles only:

 ; Load the queue pointer
 ldr     r2, qp

 ; Load the first entry
 ldr     r3, [r2, #0]

 ; Compare with NULL
 cmp     r3, #0

 ; If NULL, set to SIGNALED and exit
 mvneq   r3, #0
 streq   r3, [r2, #0]
 bxeq    lr

 ; Otherwise compare with SIGNALED
 cmn     r3, #1

 ; If not equal, increment the qpec counter
 ldrne   r2, [r3, #8]
 addne   r2, r2, #1
 strne   r2, [r3, #8]

 ; exit
 bx      lr

Michael tested context switching, which is not that important for a
cooperative system like Nut/OS. But interrupt latency is most important,
because interrupts are the real-time component in Nut/OS.

Anyway, I'm sure it could be done better, preferably without increasing
interrupt latency. And you are definitely right, that walking through
the list of all threads to look for previous events is not a good
solution. Even if Michael didn't test any dependencies on the total
number of running threads (hint! hint!).

Harald



More information about the En-Nut-Discussion mailing list