embassy/time: make optional via Cargo feature

This commit is contained in:
Dario Nieuwenhuis 2021-07-12 03:29:09 +02:00
parent 94bd4eb7d5
commit 35a76c364a
9 changed files with 52 additions and 33 deletions

View File

@ -21,7 +21,7 @@ nrf52840 = ["nrf52840-pac"]
[dependencies] [dependencies]
embassy = { version = "0.1.0", path = "../embassy" } embassy = { version = "0.1.0", path = "../embassy", features = ["time-tick-32768hz"] }
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]} embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]}
embassy-extras = {version = "0.1.0", path = "../embassy-extras" } embassy-extras = {version = "0.1.0", path = "../embassy-extras" }

View File

@ -12,7 +12,7 @@ defmt-warn = [ ]
defmt-error = [ ] defmt-error = [ ]
[dependencies] [dependencies]
embassy = { version = "0.1.0", path = "../embassy" } embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] }
embassy-extras = {version = "0.1.0", path = "../embassy-extras" } embassy-extras = {version = "0.1.0", path = "../embassy-extras" }
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]}

View File

@ -5,6 +5,6 @@ authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
embassy = { version = "0.1.0", path = "../embassy", features = ["std"] } embassy = { version = "0.1.0", path = "../embassy", features = ["std", "time-tick-32768hz"] }
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["std"]} embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["std"]}
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -6,7 +6,7 @@ edition = "2018"
resolver = "2" resolver = "2"
[dependencies] [dependencies]
embassy = { version = "0.1.0", path = "../embassy" } embassy = { version = "0.1.0", path = "../embassy", features = ["time-tick-32768hz"] }
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] }
embassy-extras = {version = "0.1.0", path = "../embassy-extras" } embassy-extras = {version = "0.1.0", path = "../embassy-extras" }
embassy-traits = {version = "0.1.0", path = "../embassy-traits" } embassy-traits = {version = "0.1.0", path = "../embassy-traits" }

View File

@ -5,11 +5,13 @@ authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
edition = "2018" edition = "2018"
[features] [features]
default = ["tick-32768hz"] default = []
std = ["futures/std", "embassy-traits/std"] std = ["futures/std", "embassy-traits/std"]
tick-32768hz = []
tick-1000hz = [] time = []
tick-1mhz = [] time-tick-32768hz = ["time"]
time-tick-1000hz = ["time"]
time-tick-1mhz = ["time"]
defmt-trace = [] defmt-trace = []
defmt-debug = [] defmt-debug = []

View File

@ -4,12 +4,12 @@ use core::{mem, ptr};
pub mod raw; pub mod raw;
mod run_queue; mod run_queue;
#[cfg(feature = "time")]
mod timer_queue; mod timer_queue;
mod util; mod util;
mod waker; mod waker;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::time::Alarm;
#[must_use = "Calling a task function does nothing on its own. You must pass the returned SpawnToken to Executor::spawn()"] #[must_use = "Calling a task function does nothing on its own. You must pass the returned SpawnToken to Executor::spawn()"]
pub struct SpawnToken<F> { pub struct SpawnToken<F> {
@ -116,7 +116,8 @@ impl Executor {
} }
} }
pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) { #[cfg(feature = "time")]
pub fn set_alarm(&mut self, alarm: &'static dyn crate::time::Alarm) {
self.inner.set_alarm(alarm); self.inner.set_alarm(alarm);
} }
@ -160,7 +161,8 @@ impl<I: Interrupt> InterruptExecutor<I> {
} }
} }
pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) { #[cfg(feature = "time")]
pub fn set_alarm(&mut self, alarm: &'static dyn crate::time::Alarm) {
self.inner.set_alarm(alarm); self.inner.set_alarm(alarm);
} }

View File

@ -1,18 +1,20 @@
use atomic_polyfill::{AtomicU32, Ordering}; use atomic_polyfill::{AtomicU32, Ordering};
use core::cell::Cell; use core::cell::Cell;
use core::cmp::min;
use core::future::Future; use core::future::Future;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::pin::Pin; use core::pin::Pin;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll};
use core::{mem, ptr}; use core::{mem, ptr};
use super::run_queue::{RunQueue, RunQueueItem}; use super::run_queue::{RunQueue, RunQueueItem};
use super::timer_queue::{TimerQueue, TimerQueueItem};
use super::util::UninitCell; use super::util::UninitCell;
use super::waker; use super::waker;
use super::SpawnToken; use super::SpawnToken;
#[cfg(feature = "time")]
use super::timer_queue::{TimerQueue, TimerQueueItem};
#[cfg(feature = "time")]
use crate::time::{Alarm, Instant}; use crate::time::{Alarm, Instant};
/// Task is spawned (has a future) /// Task is spawned (has a future)
@ -20,26 +22,33 @@ pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
/// Task is in the executor run queue /// Task is in the executor run queue
pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
/// Task is in the executor timer queue /// Task is in the executor timer queue
#[cfg(feature = "time")]
pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
pub struct TaskHeader { pub struct TaskHeader {
pub(crate) state: AtomicU32, pub(crate) state: AtomicU32,
pub(crate) run_queue_item: RunQueueItem, pub(crate) run_queue_item: RunQueueItem,
pub(crate) expires_at: Cell<Instant>,
pub(crate) timer_queue_item: TimerQueueItem,
pub(crate) executor: Cell<*const Executor>, // Valid if state != 0 pub(crate) executor: Cell<*const Executor>, // Valid if state != 0
pub(crate) poll_fn: UninitCell<unsafe fn(NonNull<TaskHeader>)>, // Valid if STATE_SPAWNED pub(crate) poll_fn: UninitCell<unsafe fn(NonNull<TaskHeader>)>, // Valid if STATE_SPAWNED
#[cfg(feature = "time")]
pub(crate) expires_at: Cell<Instant>,
#[cfg(feature = "time")]
pub(crate) timer_queue_item: TimerQueueItem,
} }
impl TaskHeader { impl TaskHeader {
pub(crate) const fn new() -> Self { pub(crate) const fn new() -> Self {
Self { Self {
state: AtomicU32::new(0), state: AtomicU32::new(0),
expires_at: Cell::new(Instant::from_ticks(0)),
run_queue_item: RunQueueItem::new(), run_queue_item: RunQueueItem::new(),
timer_queue_item: TimerQueueItem::new(),
executor: Cell::new(ptr::null()), executor: Cell::new(ptr::null()),
poll_fn: UninitCell::uninit(), poll_fn: UninitCell::uninit(),
#[cfg(feature = "time")]
expires_at: Cell::new(Instant::from_ticks(0)),
#[cfg(feature = "time")]
timer_queue_item: TimerQueueItem::new(),
} }
} }
@ -154,9 +163,12 @@ unsafe impl<F: Future + 'static> Sync for Task<F> {}
pub struct Executor { pub struct Executor {
run_queue: RunQueue, run_queue: RunQueue,
timer_queue: TimerQueue,
signal_fn: fn(*mut ()), signal_fn: fn(*mut ()),
signal_ctx: *mut (), signal_ctx: *mut (),
#[cfg(feature = "time")]
timer_queue: TimerQueue,
#[cfg(feature = "time")]
alarm: Option<&'static dyn Alarm>, alarm: Option<&'static dyn Alarm>,
} }
@ -164,13 +176,17 @@ impl Executor {
pub const fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { pub const fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
Self { Self {
run_queue: RunQueue::new(), run_queue: RunQueue::new(),
timer_queue: TimerQueue::new(),
signal_fn, signal_fn,
signal_ctx, signal_ctx,
#[cfg(feature = "time")]
timer_queue: TimerQueue::new(),
#[cfg(feature = "time")]
alarm: None, alarm: None,
} }
} }
#[cfg(feature = "time")]
pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) { pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) {
self.alarm = Some(alarm); self.alarm = Some(alarm);
} }
@ -192,6 +208,7 @@ impl Executor {
} }
pub unsafe fn run_queued(&'static self) { pub unsafe fn run_queued(&'static self) {
#[cfg(feature = "time")]
if self.alarm.is_some() { if self.alarm.is_some() {
self.timer_queue.dequeue_expired(Instant::now(), |p| { self.timer_queue.dequeue_expired(Instant::now(), |p| {
p.as_ref().enqueue(); p.as_ref().enqueue();
@ -200,6 +217,8 @@ impl Executor {
self.run_queue.dequeue_all(|p| { self.run_queue.dequeue_all(|p| {
let task = p.as_ref(); let task = p.as_ref();
#[cfg(feature = "time")]
task.expires_at.set(Instant::MAX); task.expires_at.set(Instant::MAX);
let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel);
@ -216,11 +235,13 @@ impl Executor {
task.poll_fn.read()(p as _); task.poll_fn.read()(p as _);
// Enqueue or update into timer_queue // Enqueue or update into timer_queue
#[cfg(feature = "time")]
self.timer_queue.update(p); self.timer_queue.update(p);
}); });
// If this is in the past, set_alarm will immediately trigger the alarm, // If this is in the past, set_alarm will immediately trigger the alarm,
// which will make the wfe immediately return so we do another loop iteration. // which will make the wfe immediately return so we do another loop iteration.
#[cfg(feature = "time")]
if let Some(alarm) = self.alarm { if let Some(alarm) = self.alarm {
let next_expiration = self.timer_queue.next_expiration(); let next_expiration = self.timer_queue.next_expiration();
alarm.set_callback(self.signal_fn, self.signal_ctx); alarm.set_callback(self.signal_fn, self.signal_ctx);
@ -242,9 +263,10 @@ pub unsafe fn wake_task(task: NonNull<TaskHeader>) {
task.as_ref().enqueue(); task.as_ref().enqueue();
} }
pub(crate) unsafe fn register_timer(at: Instant, waker: &Waker) { #[cfg(feature = "time")]
pub(crate) unsafe fn register_timer(at: Instant, waker: &core::task::Waker) {
let task = waker::task_from_waker(waker); let task = waker::task_from_waker(waker);
let task = task.as_ref(); let task = task.as_ref();
let expires_at = task.expires_at.get(); let expires_at = task.expires_at.get();
task.expires_at.set(min(expires_at, at)); task.expires_at.set(expires_at.min(at));
} }

View File

@ -14,6 +14,7 @@ pub(crate) mod fmt;
pub mod executor; pub mod executor;
pub mod interrupt; pub mod interrupt;
pub mod io; pub mod io;
#[cfg(feature = "time")]
pub mod time; pub mod time;
pub mod util; pub mod util;

View File

@ -13,21 +13,13 @@ pub use instant::Instant;
pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; pub use timer::{with_timeout, Ticker, TimeoutError, Timer};
pub use traits::*; pub use traits::*;
#[cfg(any( #[cfg(feature = "time-tick-1000hz")]
all(feature = "tick-32768hz", feature = "tick-1000hz"),
all(feature = "tick-32768hz", feature = "tick-1mhz"),
))]
compile_error!(
"Disable default-features to be able to use a tick rate other than the default (32768 Hz)"
);
#[cfg(feature = "tick-1000hz")]
pub const TICKS_PER_SECOND: u64 = 1_000; pub const TICKS_PER_SECOND: u64 = 1_000;
#[cfg(feature = "tick-32768hz")] #[cfg(feature = "time-tick-32768hz")]
pub const TICKS_PER_SECOND: u64 = 32_768; pub const TICKS_PER_SECOND: u64 = 32_768;
#[cfg(feature = "tick-1mhz")] #[cfg(feature = "time-tick-1mhz")]
pub const TICKS_PER_SECOND: u64 = 1_000_000; pub const TICKS_PER_SECOND: u64 = 1_000_000;
static mut CLOCK: Option<&'static dyn Clock> = None; static mut CLOCK: Option<&'static dyn Clock> = None;