diff --git a/.github/ci/test.sh b/.github/ci/test.sh index af0f21c2a..e48d6e65b 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -15,6 +15,8 @@ export CARGO_NET_GIT_FETCH_WITH_CLI=true hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json +MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly + cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml cargo test --manifest-path ./embassy-hal-internal/Cargo.toml diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 54ea1a548..f0e85a2c8 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -68,3 +68,6 @@ cortex-m = { version = "0.7.6", optional = true } # arch-wasm dependencies wasm-bindgen = { version = "0.2.82", optional = true } js-sys = { version = "0.3", optional = true } + +[dev-dependencies] +critical-section = { version = "1.1", features = ["std"] } diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs new file mode 100644 index 000000000..0dbd391e8 --- /dev/null +++ b/embassy-executor/tests/test.rs @@ -0,0 +1,137 @@ +#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] + +use std::boxed::Box; +use std::future::poll_fn; +use std::sync::{Arc, Mutex}; +use std::task::Poll; + +use embassy_executor::raw::Executor; +use embassy_executor::task; + +#[export_name = "__pender"] +fn __pender(context: *mut ()) { + unsafe { + let trace = &*(context as *const Trace); + trace.push("pend"); + } +} + +#[derive(Clone)] +struct Trace { + trace: Arc>>, +} + +impl Trace { + fn new() -> Self { + Self { + trace: Arc::new(Mutex::new(Vec::new())), + } + } + fn push(&self, value: &'static str) { + self.trace.lock().unwrap().push(value) + } + + fn get(&self) -> Vec<&'static str> { + self.trace.lock().unwrap().clone() + } +} + +fn setup() -> (&'static Executor, Trace) { + let trace = Trace::new(); + let context = Box::leak(Box::new(trace.clone())) as *mut _ as *mut (); + let executor = &*Box::leak(Box::new(Executor::new(context))); + (executor, trace) +} + +#[test] +fn executor_noop() { + let (executor, trace) = setup(); + unsafe { executor.poll() }; + assert!(trace.get().is_empty()) +} + +#[test] +fn executor_task() { + #[task] + async fn task1(trace: Trace) { + trace.push("poll task1") + } + + let (executor, trace) = setup(); + executor.spawner().spawn(task1(trace.clone())).unwrap(); + + unsafe { executor.poll() }; + unsafe { executor.poll() }; + + assert_eq!( + trace.get(), + &[ + "pend", // spawning a task pends the executor + "poll task1", // poll only once. + ] + ) +} + +#[test] +fn executor_task_self_wake() { + #[task] + async fn task1(trace: Trace) { + poll_fn(|cx| { + trace.push("poll task1"); + cx.waker().wake_by_ref(); + Poll::Pending + }) + .await + } + + let (executor, trace) = setup(); + executor.spawner().spawn(task1(trace.clone())).unwrap(); + + unsafe { executor.poll() }; + unsafe { executor.poll() }; + + assert_eq!( + trace.get(), + &[ + "pend", // spawning a task pends the executor + "poll task1", // + "pend", // task self-wakes + "poll task1", // + "pend", // task self-wakes + ] + ) +} + +#[test] +fn executor_task_self_wake_twice() { + #[task] + async fn task1(trace: Trace) { + poll_fn(|cx| { + trace.push("poll task1"); + cx.waker().wake_by_ref(); + trace.push("poll task1 wake 2"); + cx.waker().wake_by_ref(); + Poll::Pending + }) + .await + } + + let (executor, trace) = setup(); + executor.spawner().spawn(task1(trace.clone())).unwrap(); + + unsafe { executor.poll() }; + unsafe { executor.poll() }; + + assert_eq!( + trace.get(), + &[ + "pend", // spawning a task pends the executor + "poll task1", // + "pend", // task self-wakes + "poll task1 wake 2", // task self-wakes again, shouldn't pend + "poll task1", // + "pend", // task self-wakes + "poll task1 wake 2", // task self-wakes again, shouldn't pend + ] + ) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 419c31085..11f53ee4a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,7 +2,7 @@ # https://rust-lang.github.io/rustup-components-history [toolchain] channel = "nightly-2023-11-01" -components = [ "rust-src", "rustfmt", "llvm-tools" ] +components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi",