[][src]Crate clint

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