|
1 |
| -//! Interrupt / Exception context |
| 1 | +//! Interrupt / Exception context local data |
| 2 | +//! |
| 3 | +//! The main use case is safely adding state to exception / interrupt handlers. |
| 4 | +//! |
| 5 | +//! This is done in two stages, first you define a token that will appear in the |
| 6 | +//! interrupt handler signature; each handler will have its unique token. This |
| 7 | +//! token must be zero sized type because interrupt handlers' real signature is |
| 8 | +//! `fn()` and it must also implement the `Context` trait. You must also make |
| 9 | +//! sure that the token can't be constructed outside of the crate where it's |
| 10 | +//! defined. |
| 11 | +//! |
| 12 | +//! ``` |
| 13 | +//! // This must be in a library crate |
| 14 | +//! /// Token unique to the TIM7 interrupt handler |
| 15 | +//! pub struct Tim7 { _0: () } |
| 16 | +//! |
| 17 | +//! unsafe impl Context for Tim7 {} |
| 18 | +//! ``` |
| 19 | +//! |
| 20 | +//! Then in the application one can pin data to the interrupt handler using |
| 21 | +//! `Local`. |
| 22 | +//! |
| 23 | +//! ``` |
| 24 | +//! // omitted: how to put this handler in the vector table |
| 25 | +//! extern "C" fn tim7(ctxt: Tim7) { |
| 26 | +//! static STATE: Local<Cell<bool>, Tim7> = Local::new(Cell::new(false)); |
| 27 | +//! |
| 28 | +//! let state = STATE.borrow(&ctxt); |
| 29 | +//! |
| 30 | +//! // toggle state |
| 31 | +//! state.set(!state.get()); |
| 32 | +//! |
| 33 | +//! if state.get() { |
| 34 | +//! // something |
| 35 | +//! } else { |
| 36 | +//! // something else |
| 37 | +//! } |
| 38 | +//! } |
| 39 | +//! ``` |
| 40 | +//! |
| 41 | +//! Note that due to the uniqueness of tokens, other handlers won't be able to |
| 42 | +//! access context local data. (Given that you got the signatures right) |
| 43 | +//! |
| 44 | +//! ``` |
| 45 | +//! static TIM3_DATA: Local<Cell<bool>, Tim3> |
| 46 | +//! |
| 47 | +//! extern "C" fn tim3(ctxt: Tim3) { |
| 48 | +//! let data = TIM3_DATA.borrow(&ctxt); |
| 49 | +//! } |
| 50 | +//! |
| 51 | +//! extern "C" fn tim4(ctxt: Tim4) { |
| 52 | +//! //let data = TIM3_DATA.borrow(&ctxt); |
| 53 | +//! // ^ wouldn't work |
| 54 | +//! } |
| 55 | +//! ``` |
| 56 | +//! |
| 57 | +//! To have the application use these tokenized function signatures, you can |
| 58 | +//! define, in a library, a `Handlers` struct that represents the vector table: |
| 59 | +//! |
| 60 | +//! ``` |
| 61 | +//! #[repr(C)] |
| 62 | +//! pub struct Handlers { |
| 63 | +//! tim1: extern "C" fn(Tim1), |
| 64 | +//! tim2: extern "C" fn(Tim2), |
| 65 | +//! tim3: extern "C" fn(Tim3), |
| 66 | +//! tim4: extern "C" fn(Tim4), |
| 67 | +//! .. |
| 68 | +//! } |
| 69 | +//! |
| 70 | +//! pub const DEFAULT_HANDLERS: Handlers = Handlers { |
| 71 | +//! tim1: default_handler, |
| 72 | +//! tim2: default_handler, |
| 73 | +//! tim3: default_handler, |
| 74 | +//! tim4: default_handler, |
| 75 | +//! .. |
| 76 | +//! } |
| 77 | +//! ``` |
| 78 | +//! |
| 79 | +//! Then have the user use that `struct` to register the interrupt handlers: |
| 80 | +//! |
| 81 | +//! ``` |
| 82 | +//! extern "C" fn tim3(ctxt: Tim3) { .. } |
| 83 | +//! |
| 84 | +//! // override the TIM3 interrupt handler |
| 85 | +//! #[no_mangle] |
| 86 | +//! static _INTERRUPTS: Handlers = Handlers { |
| 87 | +//! tim3: tim3, ..DEFAULT_HANDLERS |
| 88 | +//! }; |
| 89 | +//! ``` |
| 90 | +//! |
| 91 | +//! This pattern is implemented for exceptions in this crate. See |
| 92 | +//! `exception::Handlers` and `exception::DEFAULT_HANDLERS`. |
2 | 93 |
|
3 | 94 | use core::marker::PhantomData;
|
4 | 95 | use core::cell::UnsafeCell;
|
|
0 commit comments