[En-Nut-Discussion] RFC: Nut/OS Tasks

Harald Kipp harald.kipp at egnite.de
Tue Jul 14 12:23:06 CEST 2009


Nathan Moore wrote:

>> To schedule a task
>>
>>  int NutTaskSchedule(prio, function, param, delay);
>>
>> must be called. This will create a task structure, which is added to a
>> priority queue.
...
> *If an IRQ fires while a thread is in NutHeapAlloc and the ISR wants to
> create a task which
> requires a memory allocation of its own....

The first thing that comes into mind is to make heap allocation
re-entrant. But as Nut/OS makes extensive use of the heap, this may
result in a noticeable performance drop. Furthermore, it's somehow
contrary to the cooperative nature of the system and the related advantages.

Another attempt would be to limit the number of tasks, either system
wide or per interrupt. This would allow to pre-allocate the required
structures. Again, this contradicts to the dynamic structure of the
system, which typically doesn't enforce other limits as far as enough
memory is available.

My favorite idea is to register tasks upfront:

 HANDLE task_x = NutRegisterTask(function, prio, delay);

This can be used to pre-allocate the structure. (HANDLE is an awful
type, I know. It just serves as a placeholder here.) The interrupt
handler may then call

 int NutTaskSchedule(task_x, param);

which should be executed as fast as possible. Optional routines like
NutTaskSetPriority, NutTaskGetHandle(function) etc. may offer more
flexibility. However, to maintain deterministic interrupt response
times, it is essential, that routines called from interrupt context will
not enter any loops. Therefore we need some kind of handle, index or
similar to refer to the registered entry.


> Things that are currently
> implemented
> as threads could be done by stringing together a series of simple tasks.
>  Memory
> allocation would be used a lot more, but it opens up the opportunity for new
> and interesting
> things to be done.

Definitely. In a way this may be finally used like an event driven OS.

As far as time allows, I'm concurrently working on a Nut/OS GUI. The
ability to register tasks would definitely simplify the GUI design.


>> We may later think about a second task queue for low priority tasks,
>> executed from NutIdle.
> 
> 
> As long as they can't sleep.  Under the current thread model the thread
> queue must
> not ever truly become empty.

You are right. I overlooked the obvious, NutIdle is not a good candidate.


>> We may also add a very high priority task queue, which is executed
>> immediately after returning from interrupt. This would follow the
>> suggestions of Duane Ellis, splitting interrupt routines into two parts
>> (similar to Unix/Linux kernels). However, as Duane explained, these
>> tasks must not call blocking functions.
> 
> 
> This could just get "scheduled" by playing around with the interrupt return,
> which
> would be fast, but would also require asm() for every processor/compiler
> combo.
> It would also borrow stack space and current thread context from whatever
> thread
> was running when the IRQ fired.

Depends on how it is used. If you look to the AVR UART drivers, they to
a lot of interrupt processing. Executing part of it after returning from
interrupt will not use significantly more thread stack space than now.

But in general I agree. (Ab-)using user thread stack space on interrupts
results in wasting memory: Right now we determine thread stack sizes by
trial and error and adding a safety margin.

As usual, many thanks for your valuable input.


Harald




More information about the En-Nut-Discussion mailing list