-
Notifications
You must be signed in to change notification settings - Fork 2
Multi Threading
This documents my thoughts at the time of writing, probably superseded.
Some SWIs (and commands?) enable interrupts because they take so long (font rendering, for example, even variable manipulation).
Interrupt handlers can call SWIs from IRQ32 mode. They should always be quick ones, but who knows?
If a task is pre-empted during in SVC32 mode, and another task scheduled and calls a SWI, it will use the SVC stack with the original task's workspace still there.
Restoring the former before the latter completes would corrupt the stack.
Therefore, tasks running in SVC32 mode, that is to say blocked while running SWIs or commands, will have to be resumed in reverse order, last one first.
This suggests that there will have to be separate queues for blocked tasks, like the irq task is now.
Another possibility would be to block SWIs until the interrupted Task is finished, using a transient callback to re-start the attempted SWI instruction when the Task drops back to USR32 mode? Might be easier to implement but means the interrupts are effectively disabled for the duration of a possibly very long SWI. I will not do this.
Task *running_with_interrupts_disabled; // List provided by HAL on IRQ
Task *running_interrupt_tasks; // Between "interrupt is off" and "wait for interrupt"
Task *interrupted_in_svc32; // Resumed LIFO, to protect SVC stack
Task *user_not_sharable; // Tasks that own some resource on this core
Task *user_sharable; // May be transferred to another core (having flushed cache by ASID)
Tasks that call OS_ThreadOp to sleep, claim a lock, etc. count as usr_tasks.
User tasks can be shared among cores, unless they own a core-specific resource.
loop
WaitForInterrupt
... turn off interrupt from hardware (interrupts are disabled)
InterruptIsOff
... high priority handling of interrupt (interrupts are enabled)
end loop
When an interrupt occurs, the kernel asks the HAL to provide the number of the most important current interrupt.
It will execute, with interrupts disabled, the Interrupt Task associated with that interrupt from after its call to WaitForInterrupt, then pause it and ask for another Interrupt Task when "InterruptIsOff" (or "WaitForInterrupt") is called. When the HAL indicates there are no more outstanding interrupts, the kernel will re-enable interrupts again.
This may sound inefficient, but it has certain advantages.
- the HAL could detect the same interrupt more than once, if another interrupt handler takes too long to complete.
- the HAL could disable low priority interrupts in hardware until a higher priority one comes in
- a trivial HAL can simply define a single interrupt and interrupt thread
A TaskSlot encapsulates an Application memory area and contains at least one Task.
In addition to memory, it holds the environment for the program, the open files, sockets, etc., the graphics context, if necessary. [more?]
In multi-core systems, if there is only one Task associated with the TaskSlot, the Application memory is mapped local to the core. Once a second Task is created, the memory will be mapped as shared, so that the Tasks can run in parallel.