Andrea sent in a third version, which had minor tweaks to the general architecture. After this really nice work, it was time to get together and review all the patches and look for other implementations.
The latest patch (version 4) brings many changes to the general architecture. I'll just report Andrea's email here, as he has already done a great job explaining the differences between v3 and v4.
Context switch redesign: voluntary preemption context switch is considered as a function call (only the callee-save registers are saved / restored); kernel preemption context switch must be interrupt safe: all the registers (minus the callee-save registers) are saved inside an interrupt entry point - IRQ_ENTRY() - and restored at the end of an interrupt exit point - IRQ_EXIT(). Last one must also take care of switching from interrupt-context mode to user-context mode and call the voluntary preemption context switch (as it happened in a normal user-context).
In this way context switch always happens from user-context (and BTW for this reason the same routines of the cooperative scheduler can be used). Only when strictly needed (kernel preemption on interrupt/signal) all the registers are saved/restored and the stack of a process is never corrupted by different user/irq contextes.
TODO: arch-dependent interrupt context switch routines must be implemented, and IRQ_ENTRY / IRQ_EXIT markers must be added to all (as many as possible) interrupt service routines. For now, IRQ_ENTRY/IRQ_EXIT have been added only to the timer ISR.
preemption redesign: preemption is explicitly regulated inside the any interrupt service routine (IRQ_EXIT). Each task obtains a time quantum when scheduled on the CPU and its quantum is decremented at each clock tick. When the quantum expires the handler proc_preempt() checks if the preemption is enabled and in this case proc_schedule() is called, that possibly replaces the current running thread with a different one. Preemption may also happen when a higher priority task is added to the ready list.
process priority: a high-priority process can preempt a low-priority process immediately (it will be descheduled and replaced in the interrupt exit point). Processes running at the same priority can be descheduled when they expire the time quantum. So, actually this is a preemptible round-robin scheduler for the tasks that runs at the same priority.
sleep() aka timer_delayTicks() fallbacks to a busy wait if called when preemption is disabled (even when CONFIG_KERN_SIGNALS is enabled)
idle directly calls proc_switch() instead of proc_yield() (in this way we can remove some CurrentProcess != idle_proc checks in some core scheduler routines)
You can find this patch in mailing list archives. It runs correctly on PC, so you can test it with the demo.
We have set up a development branch on SVN, you can download it from the developer's website. The current task is implementing the ISR context switching code for each supported CPU.
See you next time!