executor: fix unsoundness in InterruptExecutor::start.
The initial closure is not actually called in the interrupt, so this is illegally sending non-Send futures to the interrupt. Remove the closure, and return a SendSpawner instead.
This commit is contained in:
parent
52ed08cf95
commit
b27feb0619
@ -1,7 +1,7 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use super::{raw, Spawner};
|
use super::{raw, SendSpawner, Spawner};
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{Interrupt, InterruptExt};
|
||||||
|
|
||||||
/// Thread mode executor, using WFE/SEV.
|
/// Thread mode executor, using WFE/SEV.
|
||||||
@ -107,13 +107,13 @@ impl<I: Interrupt> InterruptExecutor<I> {
|
|||||||
|
|
||||||
/// Start the executor.
|
/// Start the executor.
|
||||||
///
|
///
|
||||||
/// The `init` closure is called from interrupt mode, with a [`Spawner`] that spawns tasks on
|
/// This initializes the executor, configures and enables the interrupt, and returns.
|
||||||
/// this executor. Use it to spawn the initial task(s). After `init` returns,
|
/// The executor keeps running in the background through the interrupt.
|
||||||
/// the interrupt is configured so that the executor starts running the tasks.
|
|
||||||
/// Once the executor is started, `start` returns.
|
|
||||||
///
|
///
|
||||||
/// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
|
/// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
|
||||||
/// for example by passing it as an argument to the initial tasks.
|
/// is returned instead of a [`Spawner`] because the executor effectively runs in a
|
||||||
|
/// different "thread" (the interrupt), so spawning tasks on it is effectively
|
||||||
|
/// sending them.
|
||||||
///
|
///
|
||||||
/// This function requires `&'static mut self`. This means you have to store the
|
/// This function requires `&'static mut self`. This means you have to store the
|
||||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||||
@ -122,16 +122,16 @@ impl<I: Interrupt> InterruptExecutor<I> {
|
|||||||
/// - a [Forever](crate::util::Forever) (safe)
|
/// - a [Forever](crate::util::Forever) (safe)
|
||||||
/// - a `static mut` (unsafe)
|
/// - a `static mut` (unsafe)
|
||||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||||
pub fn start(&'static mut self, init: impl FnOnce(Spawner) + Send) {
|
pub fn start(&'static mut self) -> SendSpawner {
|
||||||
self.irq.disable();
|
self.irq.disable();
|
||||||
|
|
||||||
init(self.inner.spawner());
|
|
||||||
|
|
||||||
self.irq.set_handler(|ctx| unsafe {
|
self.irq.set_handler(|ctx| unsafe {
|
||||||
let executor = &*(ctx as *const raw::Executor);
|
let executor = &*(ctx as *const raw::Executor);
|
||||||
executor.poll();
|
executor.poll();
|
||||||
});
|
});
|
||||||
self.irq.set_handler_context(&self.inner as *const _ as _);
|
self.irq.set_handler_context(&self.inner as *const _ as _);
|
||||||
self.irq.enable();
|
self.irq.enable();
|
||||||
|
|
||||||
|
self.inner.spawner().make_send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,17 +124,15 @@ fn main() -> ! {
|
|||||||
let irq = interrupt::take!(SWI1_EGU1);
|
let irq = interrupt::take!(SWI1_EGU1);
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
irq.set_priority(interrupt::Priority::P6);
|
||||||
let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
|
let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
|
||||||
executor.start(|spawner| {
|
let spawner = executor.start();
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
});
|
|
||||||
|
|
||||||
// Medium-priority executor: SWI0_EGU0, priority level 7
|
// Medium-priority executor: SWI0_EGU0, priority level 7
|
||||||
let irq = interrupt::take!(SWI0_EGU0);
|
let irq = interrupt::take!(SWI0_EGU0);
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
irq.set_priority(interrupt::Priority::P7);
|
||||||
let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
|
let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
|
||||||
executor.start(|spawner| {
|
let spawner = executor.start();
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
});
|
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// Low priority executor: runs in thread mode, using WFE/SEV
|
||||||
let executor = EXECUTOR_LOW.put(Executor::new());
|
let executor = EXECUTOR_LOW.put(Executor::new());
|
||||||
|
@ -124,17 +124,15 @@ fn main() -> ! {
|
|||||||
let irq = interrupt::take!(UART4);
|
let irq = interrupt::take!(UART4);
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
irq.set_priority(interrupt::Priority::P6);
|
||||||
let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
|
let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
|
||||||
executor.start(|spawner| {
|
let spawner = executor.start();
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
});
|
|
||||||
|
|
||||||
// Medium-priority executor: SWI0_EGU0, priority level 7
|
// Medium-priority executor: SWI0_EGU0, priority level 7
|
||||||
let irq = interrupt::take!(UART5);
|
let irq = interrupt::take!(UART5);
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
irq.set_priority(interrupt::Priority::P7);
|
||||||
let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
|
let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
|
||||||
executor.start(|spawner| {
|
let spawner = executor.start();
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
});
|
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// Low priority executor: runs in thread mode, using WFE/SEV
|
||||||
let executor = EXECUTOR_LOW.put(Executor::new());
|
let executor = EXECUTOR_LOW.put(Executor::new());
|
||||||
|
@ -124,17 +124,15 @@ fn main() -> ! {
|
|||||||
let irq = interrupt::take!(UART4);
|
let irq = interrupt::take!(UART4);
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
irq.set_priority(interrupt::Priority::P6);
|
||||||
let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
|
let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
|
||||||
executor.start(|spawner| {
|
let spawner = executor.start();
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
});
|
|
||||||
|
|
||||||
// Medium-priority executor: SWI0_EGU0, priority level 7
|
// Medium-priority executor: SWI0_EGU0, priority level 7
|
||||||
let irq = interrupt::take!(UART5);
|
let irq = interrupt::take!(UART5);
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
irq.set_priority(interrupt::Priority::P7);
|
||||||
let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
|
let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
|
||||||
executor.start(|spawner| {
|
let spawner = executor.start();
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
});
|
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// Low priority executor: runs in thread mode, using WFE/SEV
|
||||||
let executor = EXECUTOR_LOW.put(Executor::new());
|
let executor = EXECUTOR_LOW.put(Executor::new());
|
||||||
|
Loading…
Reference in New Issue
Block a user