[−][src]Module clint::handler
Call closures from interrupt handlers.
Motivation
Existing solutions for interrupt handlers typically revolve around
wrapping resources needed by the handler in an Option
, wrapped
in a RefCell
wrapped in an Mutex
, incurring some run-time
overhead every time the resource is required in the interrupt
handler, in addition to a fair amount of boilerplate. This module
attempts to leverage Rust's borrow checker and move semantics to
allow interrupt handlers to directly use their resources with a
minimum of overhead.
To accomplish this, we use a closure which is called by an
interrupt handler. Because the closure has access to its
environment, we can use move
, references, and mutable references
to ensure that variables are available as necessary to the
interrupt handler, while leveraging the borrow checker to ensure
safety at compile time. The only overhead is what it takes to call
the closure itself.
Safety
While this module endeavors to use Rust's safety guarantees to allow for use of resources inside interrupt handlers, due to expected use-cases, closure semantics, and how interrupt handlers are invoked from hardware, certain operations cannot be done safely at this level.
Notably, for the handler to be useful when called from interrupt
context, it needs to be stored in a static mut
variable. This
means that the closure you supply it must also be effectively
static
or replaced with a longer-lived closure before it goes
out of scope. Handler::default_handler()
is provided for this
purpose.
Additionally, replacement of an interrupt handler's closure may
race with the calling of the interrupt handler's closure (i.e.,
Handler.replace()
may happen concurrently with
Handler.call()
). You need to avoid this situation however is
appropriate for your code. The expected usage would be replacing
the handler`s closure once, while interrupts are disabled, thus
preventing the simultaneous replace/call problem. As this module
makes no assumptions about the environment in which it will be
used, this cannot be done for you.
Examples
This example for an ARM Cortex-M system demonstrates safe usage by
only replacing the closure for SYSTICK_HANDLER
inside a critical
section obtained by cortex_m::interrupt::free()
, and shows how
it is called via the SysTick()
function, which is called
directly from hardware.
use clint::Handler; use cortex_m_rt::exception; static mut SYSTICK_HANDLER: Handler = Handler::new(); fn main() { // NB: `closure` is in the lexical scope of `main`, and thus // cannot go out of scope. let closure = || { // Your interrupt handling code. }; // Replace the handler for SysTick with closure while interrupts are // disabled. cortex_m::interrupt::free(|_| { unsafe { SYSTICK_HANDLER.replace(&closure) }; }); loop { // Your main loop. } } #[exception] fn SysTick() { unsafe { SYSTICK_HANDLER.call() }; }
Structs
Handler |