Threads
A thread in Drone OS corresponds to a hardware interrupt. It is a sequence of fibers that managed independently by an interrupt controller. Threads can not be created on demand, but should be pre-defined for a particular project. Then any number of fibers can be attached dynamically to a particular thread.
Threads should be defined at src/thr.rs
using thr::nvic!
macro:
#![allow(unused)] fn main() { thr::nvic! { /// Thread-safe storage. thread => pub Thr {}; /// Thread-local storage. local => pub ThrLocal {}; /// Vector table. vtable => pub Vtable; /// Thread token set. index => pub Thrs; /// Threads initialization token. init => pub ThrsInit; threads => { exceptions => { /// All classes of faults. pub hard_fault; }; interrupts => { /// A thread for my task. 10: pub my_thread; }; }; } }
The macros will define THREADS
static array of Thr
objects. In this example
the array will contain three element: HARD_FAULT
, MY_THREAD
, and the
implicit RESET
thread data. Thrs
structure is also created here, which is a
zero-sized type, a set of tokens, through which one can manipulate the
threads. This set of token can be instantiated only once, usually at the very
beginning of the root task:
#![allow(unused)] fn main() { /// The root task handler. #[inline(never)] pub fn handler(reg: Regs, thr_init: ThrsInit) { let thr = thr::init(thr_init); // ... The rest of the handler ... } }
Here the thr
variable contains tokens for all defined threads. If you have
added fields to the Thr
definition, they are accessible through
thr.my_thread.to_thr()
. ThrLocal
is also stored inside Thr
, but accessible
only through the Thr::local()
associated function.
A thread can be called programmatically using implicit core::task::Waker
or
explicit thr.my_thread.trigger()
or directly by hardware peripherals. If the
thread, which was triggered, has a higher priority than the currently active
thread, the active thread will be preempted. If the thread has a lower priority,
it will run after all higher priority threads. Priorities can be changed on the
fly with thr.my_thread.set_priority(...)
method.
Fiber chain
The main thing a thread owns is a fiber chain. A fiber chain is essentially a
linked list of fibers. A fiber can be added to a thread chain dynamically using
thr.my_thread.add_fib(...)
, or other methods based on it. The add_fib
method
is atomic, i.e. fibers can be added to a particular thread from other threads.
When a thread is triggered, it runs the fibers in its fiber chain one-by-one in
LIFO order. In other words the most recently added fiber will be executed
first. A fiber can return fib::Yielded
result, which means the fiber is paused
but not completed; the thread will keep the fiber in place for the later run and
proceed with the next fiber in the chain. Or the fiber can return
fib::Complete
, in which case the thread removes the fiber from the chain, runs
its drop
destructor, and proceeds to the next fiber in the chain.