> IMHO, either you run the scheduler with a fast Tick (perhaps 1ms or faster) and use the Scheduler for everything. Or do as you propose and run the scheduler to take care of the "soft" real time tasks like the user interface, serial ports with hardware buffers, or other relatively slow processes.
Or you write your scheduler so that it's smart enough not to task
switch except when needed. A lot of older operating systems used a mix
of
- Simple priority queues (often with a basic 'get dumped in the lowest
priority if you use a whole timeslice)
- Interrupt handlers not task switches used whenever possible to
reduce switching cost
- When swapping so you always run a swapped in task a bit before it
can get swapped out even if there are higher priority candidates who
are swapped - so you always make progress
Fuzix also pulls an extra trick in that it doesn't actually task
switch when there is no runnable task but sits in the current task
until the point something is runnable and if that one thing is the old
task (usual case by far) then it just carries on running it. In a
typical usage case of single user running say Zork, there will be 2 or
3 context switches between shell starting the game and exiting it an
hour later 8)
An RTOS is a bit different because you can only do so much in
interrupt context because of the need to handle priority inversions.
Z80 is horrible for this because of the register count, although
reserving the alt registers for the actual irq paths helps a bit. On
the plus side you don't have to play zero page allocation games like
the 6502.
>> But you have me thinking. Maybe NMI should not be used for the scheduler as this could interrupt other lower level interrupts and switch tasks at the wrong time. So maybe the scheduler is the lowest priority interrupt. Then it can only run when no other interrupts are being processed. It would be safer, I think, to only switch tasks when things are relatively quiet. That way, there is nothing real-time about the scheduler. What do you think?
Scheduler is usually for a non-RTOS the lowest priority. If you have
an interrupt controller you don't want to lose serial characters to a
task switch. With the Z80 you are usually stuck with a single real
priority unlike say 8085.
> One of the useful things might be the handling of context save and restore, which you'll need no matter what. There is a little bit of bit trickery to get the correct interrupt enable status stored in the context, irrespective of whether you're restoring state from normal operations, or from within an interrupt. Normally you just read the i register (in a CMOS Z80) and restore based on the Odd/Even bit, but from within an interrupt you need to fake a set interrupt enable bit.
It's usually quicker to just track your interrupt state in software.
That also allows for a bunch of other optimizations, and works on the
NMOS parts as well. Be warned several compilers have supposed
"interrupt" support but don't understand NMOS parts. Trying to do
clever stuff with the I register gets really messy as if you support
any kind of interrupt nesting.
Alan