mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-30 15:34:33 +01:00
More work on new spawn/executor
This commit is contained in:
parent
b1cadd79ee
commit
ad2bf4e77c
8 changed files with 43 additions and 108 deletions
|
@ -28,6 +28,8 @@ rtic-monotonic = "1.0.0"
|
||||||
rtic-core = "1.0.0"
|
rtic-core = "1.0.0"
|
||||||
heapless = "0.7.7"
|
heapless = "0.7.7"
|
||||||
bare-metal = "1.0.0"
|
bare-metal = "1.0.0"
|
||||||
|
#portable-atomic = { version = "0.3.19" }
|
||||||
|
atomic-polyfill = "1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
version_check = "0.9"
|
version_check = "0.9"
|
||||||
|
|
|
@ -16,11 +16,10 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
type #type_name = impl core::future::Future + 'static;
|
type #type_name = impl core::future::Future;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
static #exec_name:
|
static #exec_name: rtic::export::executor::AsyncTaskExecutor<#type_name> =
|
||||||
rtic::RacyCell<rtic::export::executor::AsyncTaskExecutor<#type_name>> =
|
rtic::export::executor::AsyncTaskExecutor::new();
|
||||||
rtic::RacyCell::new(rtic::export::executor::AsyncTaskExecutor::new());
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,38 +46,13 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
let exec_name = util::internal_task_ident(name, "EXEC");
|
let exec_name = util::internal_task_ident(name, "EXEC");
|
||||||
// let task = &app.software_tasks[name];
|
// let task = &app.software_tasks[name];
|
||||||
// let cfgs = &task.cfgs;
|
// let cfgs = &task.cfgs;
|
||||||
let executor_run_ident = util::executor_run_ident(name);
|
|
||||||
|
|
||||||
let rq = util::rq_async_ident(name);
|
|
||||||
|
|
||||||
items.push(quote!(
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
static #rq: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false);
|
|
||||||
));
|
|
||||||
|
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
if !(&*#exec_name.get()).is_running() {
|
if #exec_name.check_and_clear_pending() {
|
||||||
// TODO Fix this to be compare and swap
|
#exec_name.poll(|| {
|
||||||
if #rq.load(core::sync::atomic::Ordering::Relaxed) {
|
#exec_name.set_pending();
|
||||||
#rq.store(false, core::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
(&mut *#exec_name.get_mut()).spawn(#name(#name::Context::new()));
|
|
||||||
#executor_run_ident.store(true, core::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if #executor_run_ident.load(core::sync::atomic::Ordering::Relaxed) {
|
|
||||||
#executor_run_ident.store(false, core::sync::atomic::Ordering::Relaxed);
|
|
||||||
if (&mut *#exec_name.get_mut()).poll(|| {
|
|
||||||
#executor_run_ident.store(true, core::sync::atomic::Ordering::Release);
|
|
||||||
#pend_interrupt
|
#pend_interrupt
|
||||||
}) && #rq.load(core::sync::atomic::Ordering::Relaxed) {
|
});
|
||||||
// If the ready queue is not empty and the executor finished, restart this
|
|
||||||
// dispatch to check if the executor should be restarted.
|
|
||||||
#pend_interrupt
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -96,12 +70,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
const PRIORITY: u8 = #level;
|
const PRIORITY: u8 = #level;
|
||||||
|
|
||||||
rtic::export::run(PRIORITY, || {
|
rtic::export::run(PRIORITY, || {
|
||||||
// Have the acquire/release semantics outside the checks to no overdo it
|
|
||||||
core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire);
|
|
||||||
|
|
||||||
#(#stmts)*
|
#(#stmts)*
|
||||||
|
|
||||||
core::sync::atomic::fence(core::sync::atomic::Ordering::Release);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
@ -110,12 +79,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
unsafe fn #dispatcher_name() -> ! {
|
unsafe fn #dispatcher_name() -> ! {
|
||||||
loop {
|
loop {
|
||||||
// Have the acquire/release semantics outside the checks to no overdo it
|
|
||||||
core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire);
|
|
||||||
|
|
||||||
#(#stmts)*
|
#(#stmts)*
|
||||||
|
|
||||||
core::sync::atomic::fence(core::sync::atomic::Ordering::Release);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
|
@ -98,6 +98,7 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
};
|
};
|
||||||
|
|
||||||
let internal_context_name = util::internal_task_ident(name, "Context");
|
let internal_context_name = util::internal_task_ident(name, "Context");
|
||||||
|
let exec_name = util::internal_task_ident(name, "EXEC");
|
||||||
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
|
@ -147,25 +148,25 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
let internal_spawn_ident = util::internal_task_ident(name, "spawn");
|
let internal_spawn_ident = util::internal_task_ident(name, "spawn");
|
||||||
|
|
||||||
// Spawn caller
|
// Spawn caller
|
||||||
let rq = util::rq_async_ident(name);
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
|
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
/// Spawns the task directly
|
/// Spawns the task directly
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn #internal_spawn_ident() -> Result<(), ()> {
|
pub fn #internal_spawn_ident() -> Result<(), ()> {
|
||||||
|
if #exec_name.try_reserve() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// TODO: Fix this to be compare and swap
|
// TODO: Add args here
|
||||||
if #rq.load(core::sync::atomic::Ordering::Acquire) {
|
#exec_name.spawn_unchecked(#name(#name::Context::new()));
|
||||||
Err(())
|
}
|
||||||
} else {
|
|
||||||
#rq.store(true, core::sync::atomic::Ordering::Release);
|
|
||||||
#pend_interrupt
|
#pend_interrupt
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
));
|
||||||
|
|
||||||
module_items.push(quote!(
|
module_items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::syntax::{ast::App, Context};
|
use crate::syntax::{ast::App, Context};
|
||||||
use crate::{
|
use crate::{
|
||||||
analyze::Analysis,
|
analyze::Analysis,
|
||||||
codegen::{local_resources_struct, module, shared_resources_struct, util},
|
codegen::{local_resources_struct, module, shared_resources_struct},
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -13,18 +13,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
|
|
||||||
// Any task
|
// Any task
|
||||||
for (name, task) in app.software_tasks.iter() {
|
for (name, task) in app.software_tasks.iter() {
|
||||||
let executor_ident = util::executor_run_ident(name);
|
|
||||||
mod_app.push(quote!(
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
static #executor_ident: core::sync::atomic::AtomicBool =
|
|
||||||
core::sync::atomic::AtomicBool::new(false);
|
|
||||||
));
|
|
||||||
|
|
||||||
// `${task}Resources`
|
|
||||||
|
|
||||||
// `${task}Locals`
|
|
||||||
if !task.args.local_resources.is_empty() {
|
if !task.args.local_resources.is_empty() {
|
||||||
let (item, constructor) =
|
let (item, constructor) =
|
||||||
local_resources_struct::codegen(Context::SoftwareTask(name), app);
|
local_resources_struct::codegen(Context::SoftwareTask(name), app);
|
||||||
|
|
|
@ -49,11 +49,6 @@ pub fn impl_mutex(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates an identifier for the `EXECUTOR_RUN` atomics (`async` API)
|
|
||||||
pub fn executor_run_ident(task: &Ident) -> Ident {
|
|
||||||
mark_internal_name(&format!("{task}_EXECUTOR_RUN"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interrupt_ident() -> Ident {
|
pub fn interrupt_ident() -> Ident {
|
||||||
let span = Span::call_site();
|
let span = Span::call_site();
|
||||||
Ident::new("interrupt", span)
|
Ident::new("interrupt", span)
|
||||||
|
@ -151,11 +146,6 @@ pub fn local_resources_ident(ctxt: Context, app: &App) -> Ident {
|
||||||
mark_internal_name(&s)
|
mark_internal_name(&s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates an identifier for a ready queue, async task version
|
|
||||||
pub fn rq_async_ident(async_task_name: &Ident) -> Ident {
|
|
||||||
mark_internal_name(&format!("ASYNC_TASK_{async_task_name}_RQ"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Suffixed identifier
|
/// Suffixed identifier
|
||||||
pub fn suffixed(name: &str) -> Ident {
|
pub fn suffixed(name: &str) -> Ident {
|
||||||
let span = Span::call_site();
|
let span = Span::call_site();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
pub use bare_metal::CriticalSection;
|
pub use bare_metal::CriticalSection;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
pub use cortex_m::{
|
pub use cortex_m::{
|
||||||
asm::nop,
|
asm::nop,
|
||||||
asm::wfi,
|
asm::wfi,
|
||||||
|
@ -7,6 +6,8 @@ pub use cortex_m::{
|
||||||
peripheral::{scb::SystemHandler, DWT, NVIC, SCB, SYST},
|
peripheral::{scb::SystemHandler, DWT, NVIC, SCB, SYST},
|
||||||
Peripherals,
|
Peripherals,
|
||||||
};
|
};
|
||||||
|
//pub use portable_atomic as atomic;
|
||||||
|
pub use atomic_polyfill as atomic;
|
||||||
|
|
||||||
pub mod executor;
|
pub mod executor;
|
||||||
|
|
||||||
|
@ -72,28 +73,6 @@ where
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Barrier {
|
|
||||||
inner: AtomicBool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Barrier {
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Barrier {
|
|
||||||
inner: AtomicBool::new(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release(&self) {
|
|
||||||
self.inner.store(true, Ordering::Release);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait(&self) {
|
|
||||||
while !self.inner.load(Ordering::Acquire) {
|
|
||||||
core::hint::spin_loop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Const helper to check architecture
|
/// Const helper to check architecture
|
||||||
pub const fn have_basepri() -> bool {
|
pub const fn have_basepri() -> bool {
|
||||||
#[cfg(have_basepri)]
|
#[cfg(have_basepri)]
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
use super::atomic::{AtomicBool, Ordering};
|
||||||
use core::{
|
use core::{
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
future::Future,
|
future::Future,
|
||||||
mem::{self, MaybeUninit},
|
mem::{self, MaybeUninit},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
|
||||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,9 +53,11 @@ impl<F: Future> AsyncTaskExecutor<F> {
|
||||||
self.running.load(Ordering::Relaxed)
|
self.running.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a waker has pended the executor.
|
/// Checks if a waker has pended the executor and simultaneously clears the flag.
|
||||||
pub fn is_pending(&self) -> bool {
|
pub fn check_and_clear_pending(&self) -> bool {
|
||||||
self.pending.load(Ordering::Relaxed)
|
self.pending
|
||||||
|
.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
|
||||||
|
.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by wakers to indicate that the executor needs to run.
|
// Used by wakers to indicate that the executor needs to run.
|
||||||
|
@ -80,6 +82,7 @@ impl<F: Future> AsyncTaskExecutor<F> {
|
||||||
debug_assert!(self.running.load(Ordering::Relaxed));
|
debug_assert!(self.running.load(Ordering::Relaxed));
|
||||||
|
|
||||||
self.task.get().write(MaybeUninit::new(future));
|
self.task.get().write(MaybeUninit::new(future));
|
||||||
|
self.set_pending();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Poll the future in the executor.
|
/// Poll the future in the executor.
|
||||||
|
|
|
@ -70,7 +70,15 @@ impl<'a> CargoCommand<'a> {
|
||||||
features,
|
features,
|
||||||
mode,
|
mode,
|
||||||
} => {
|
} => {
|
||||||
let mut args = vec!["+nightly", self.name(), "--examples", "--target", target];
|
let mut args = vec![
|
||||||
|
"+nightly",
|
||||||
|
self.name(),
|
||||||
|
"--examples",
|
||||||
|
"--target",
|
||||||
|
target,
|
||||||
|
"--features",
|
||||||
|
"test-critical-section",
|
||||||
|
];
|
||||||
|
|
||||||
if let Some(feature_name) = features {
|
if let Some(feature_name) = features {
|
||||||
args.extend_from_slice(&["--features", feature_name]);
|
args.extend_from_slice(&["--features", feature_name]);
|
||||||
|
|
Loading…
Reference in a new issue