async idle working

This commit is contained in:
Emil Fresk 2022-08-03 11:17:29 +02:00
parent 4a349653b4
commit 561bef45e7
3 changed files with 121 additions and 4 deletions

51
examples/async-idle.rs Normal file
View file

@ -0,0 +1,51 @@
#![no_main]
#![no_std]
#![feature(type_alias_impl_trait)]
use panic_semihosting as _;
// NOTES:
//
// - Async tasks cannot have `#[lock_free]` resources, as they can interleve and each async
// task can have a mutable reference stored.
// - Spawning an async task equates to it being polled once.
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
mod app {
use cortex_m_semihosting::{debug, hprintln};
use systick_monotonic::*;
#[shared]
struct Shared {}
#[local]
struct Local {}
#[monotonic(binds = SysTick, default = true)]
type MyMono = Systick<100>;
#[init]
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
hprintln!("init").unwrap();
(
Shared {},
Local {},
init::Monotonics(Systick::new(cx.core.SYST, 12_000_000)),
)
}
#[idle]
async fn idle(_: idle::Context) -> ! {
hprintln!("idle");
for i in 0..2 {
monotonics::delay(100.millis()).await;
hprintln!("async delay {}").ok();
}
debug::exit(debug::EXIT_SUCCESS);
loop {}
}
}

View file

@ -63,10 +63,15 @@ pub fn codegen(
let attrs = &idle.attrs; let attrs = &idle.attrs;
let context = &idle.context; let context = &idle.context;
let stmts = &idle.stmts; let stmts = &idle.stmts;
let async_ = if idle.is_async {
quote!(async)
} else {
quote!()
};
let user_idle = Some(quote!( let user_idle = Some(quote!(
#(#attrs)* #(#attrs)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn #name(#context: #name::Context) -> ! { #async_ fn #name(#context: #name::Context) -> ! {
use rtic::Mutex as _; use rtic::Mutex as _;
use rtic::mutex::prelude::*; use rtic::mutex::prelude::*;
@ -74,9 +79,16 @@ pub fn codegen(
} }
)); ));
let call_idle = quote!(#name( let call_idle = if idle.is_async {
quote!(
let idle_task = #name(#name::Context::new(&rtic::export::Priority::new(0)));
rtic::export::idle_executor::IdleExecutor::new(idle_task).run();
)
} else {
quote!(#name(
#name::Context::new(&rtic::export::Priority::new(0)) #name::Context::new(&rtic::export::Priority::new(0))
)); ))
};
(mod_app, root_idle, user_idle, call_idle) (mod_app, root_idle, user_idle, call_idle)
} else { } else {

View file

@ -21,6 +21,60 @@ pub use heapless::BinaryHeap;
pub use heapless::Vec; pub use heapless::Vec;
pub use rtic_monotonic as monotonic; pub use rtic_monotonic as monotonic;
pub mod idle_executor {
use core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};
fn no_op(_: *const ()) {}
fn no_op_clone(_: *const ()) -> RawWaker {
noop_raw_waker()
}
static IDLE_WAKER_TABLE: RawWakerVTable = RawWakerVTable::new(no_op_clone, no_op, no_op, no_op);
#[inline]
fn noop_raw_waker() -> RawWaker {
RawWaker::new(core::ptr::null(), &IDLE_WAKER_TABLE)
}
pub struct IdleExecutor<T>
where
T: Future,
{
idle: T,
}
impl<T> IdleExecutor<T>
where
T: Future,
{
#[inline(always)]
pub fn new(idle: T) -> Self {
Self { idle }
}
#[inline(always)]
pub fn run(&mut self) -> ! {
let w = unsafe { Waker::from_raw(noop_raw_waker()) };
let mut ctxt = Context::from_waker(&w);
loop {
match unsafe { Pin::new_unchecked(&mut self.idle) }.poll(&mut ctxt) {
Poll::Pending => {
// All ok!
}
Poll::Ready(_) => {
// The idle executor will never return
unreachable!()
}
}
}
}
}
}
pub mod executor { pub mod executor {
use core::{ use core::{
future::Future, future::Future,