mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 22:54:52 +00:00
Make requested API changes
This commit is contained in:
parent
adb0c3e947
commit
401fac6ea9
@ -119,8 +119,6 @@ arch-spin = ["_arch"]
|
|||||||
|
|
||||||
## Enable the `name` field in task metadata.
|
## Enable the `name` field in task metadata.
|
||||||
metadata-name = ["embassy-executor-macros/metadata-name"]
|
metadata-name = ["embassy-executor-macros/metadata-name"]
|
||||||
## Enable the `deadline` field in task metadata.
|
|
||||||
metadata-deadline = []
|
|
||||||
|
|
||||||
#! ### Executor
|
#! ### Executor
|
||||||
|
|
||||||
@ -131,9 +129,13 @@ executor-interrupt = []
|
|||||||
## Enable tracing hooks
|
## Enable tracing hooks
|
||||||
trace = ["_any_trace"]
|
trace = ["_any_trace"]
|
||||||
## Enable support for rtos-trace framework
|
## Enable support for rtos-trace framework
|
||||||
rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"]
|
rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "embassy-time-driver"]
|
||||||
_any_trace = []
|
_any_trace = []
|
||||||
|
|
||||||
## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize
|
## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize
|
||||||
## tasks based on the remaining time before their deadline. Adds some overhead.
|
## tasks based on the remaining time before their deadline. Adds some overhead.
|
||||||
edf-scheduler = ["dep:embassy-time-driver", "metadata-deadline"]
|
scheduler-deadline = []
|
||||||
|
|
||||||
|
## Enable the embassy_time_driver dependency.
|
||||||
|
## This can unlock extra APIs, for example for the `sheduler-deadline`
|
||||||
|
embassy-time-driver = ["dep:embassy-time-driver"]
|
||||||
|
@ -7,12 +7,14 @@ use core::task::Poll;
|
|||||||
use critical_section::Mutex;
|
use critical_section::Mutex;
|
||||||
|
|
||||||
use crate::raw;
|
use crate::raw;
|
||||||
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
|
use crate::raw::Deadline;
|
||||||
|
|
||||||
/// Metadata associated with a task.
|
/// Metadata associated with a task.
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
#[cfg(feature = "metadata-name")]
|
#[cfg(feature = "metadata-name")]
|
||||||
name: Mutex<Cell<Option<&'static str>>>,
|
name: Mutex<Cell<Option<&'static str>>>,
|
||||||
#[cfg(feature = "metadata-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
deadline: raw::Deadline,
|
deadline: raw::Deadline,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +25,7 @@ impl Metadata {
|
|||||||
name: Mutex::new(Cell::new(None)),
|
name: Mutex::new(Cell::new(None)),
|
||||||
// NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
|
// NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
|
||||||
// will be lazily initalized in `initialize_impl`
|
// will be lazily initalized in `initialize_impl`
|
||||||
#[cfg(feature = "metadata-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
deadline: raw::Deadline::new_unset(),
|
deadline: raw::Deadline::new_unset(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,10 +61,62 @@ impl Metadata {
|
|||||||
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
|
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Earliest Deadline First scheduler Deadline. This field should not be accessed
|
/// Get this task's deadline.
|
||||||
/// outside the context of the task itself as it being polled by the executor.
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
#[cfg(feature = "metadata-deadline")]
|
|
||||||
pub fn deadline(&self) -> &raw::Deadline {
|
pub fn deadline(&self) -> &raw::Deadline {
|
||||||
&self.deadline
|
&self.deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set this task's deadline.
|
||||||
|
///
|
||||||
|
/// This method does NOT check whether the deadline has already passed.
|
||||||
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
|
pub fn set_deadline(&self, instant_ticks: u64) {
|
||||||
|
self.deadline.set(instant_ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove this task's deadline.
|
||||||
|
/// This brings it back to the defaul where it's not scheduled ahead of other tasks.
|
||||||
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
|
pub fn unset_deadline(&self) {
|
||||||
|
self.deadline.set(Deadline::UNSET_DEADLINE_TICKS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set this task's deadline `duration_ticks` in the future from when
|
||||||
|
/// this future is polled. This deadline is saturated to the max tick value.
|
||||||
|
///
|
||||||
|
/// Analogous to `Timer::after`.
|
||||||
|
#[cfg(all(feature = "scheduler-deadline", feature = "embassy-time-driver"))]
|
||||||
|
pub fn set_deadline_after(&self, duration_ticks: u64) {
|
||||||
|
let now = embassy_time_driver::now();
|
||||||
|
|
||||||
|
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
||||||
|
// it for now, we can probably make this wrapping_add for performance
|
||||||
|
// reasons later.
|
||||||
|
let deadline = now.saturating_add(duration_ticks);
|
||||||
|
|
||||||
|
self.set_deadline(deadline);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the this task's deadline `increment_ticks` from the previous deadline.
|
||||||
|
///
|
||||||
|
/// This deadline is saturated to the max tick value.
|
||||||
|
///
|
||||||
|
/// Note that by default (unless otherwise set), tasks start life with the deadline
|
||||||
|
/// not set, which means this method will have no effect.
|
||||||
|
///
|
||||||
|
/// Analogous to one increment of `Ticker::every().next()`.
|
||||||
|
///
|
||||||
|
/// Returns the deadline that was set.
|
||||||
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
|
pub fn increment_deadline(&self, duration_ticks: u64) {
|
||||||
|
let last = self.deadline().instant_ticks();
|
||||||
|
|
||||||
|
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
||||||
|
// it for now, we can probably make this wrapping_add for performance
|
||||||
|
// reasons later.
|
||||||
|
let deadline = last.saturating_add(duration_ticks);
|
||||||
|
|
||||||
|
self.set_deadline(deadline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
use core::future::{poll_fn, Future};
|
|
||||||
use core::sync::atomic::{AtomicU32, Ordering};
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
use core::task::Poll;
|
|
||||||
|
|
||||||
/// A type for interacting with the deadline of the current task
|
/// A type for interacting with the deadline of the current task
|
||||||
///
|
///
|
||||||
@ -49,111 +47,4 @@ impl Deadline {
|
|||||||
pub fn is_unset(&self) -> bool {
|
pub fn is_unset(&self) -> bool {
|
||||||
self.instant_ticks() == Self::UNSET_DEADLINE_TICKS
|
self.instant_ticks() == Self::UNSET_DEADLINE_TICKS
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the current task's deadline at exactly `instant_ticks`
|
|
||||||
///
|
|
||||||
/// This method is a future in order to access the currently executing task's
|
|
||||||
/// header which contains the deadline.
|
|
||||||
///
|
|
||||||
/// Analogous to `Timer::at`.
|
|
||||||
///
|
|
||||||
/// This method does NOT check whether the deadline has already passed.
|
|
||||||
#[must_use = "Setting deadline must be polled to be effective"]
|
|
||||||
pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
let task = super::task_from_waker(cx.waker());
|
|
||||||
task.header().metadata.deadline().set(instant_ticks);
|
|
||||||
Poll::Ready(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the current task's deadline `duration_ticks` in the future from when
|
|
||||||
/// this future is polled. This deadline is saturated to the max tick value.
|
|
||||||
///
|
|
||||||
/// This method is a future in order to access the currently executing task's
|
|
||||||
/// header which contains the deadline.
|
|
||||||
///
|
|
||||||
/// Analogous to `Timer::after`.
|
|
||||||
///
|
|
||||||
/// Returns the deadline that was set.
|
|
||||||
#[must_use = "Setting deadline must be polled to be effective"]
|
|
||||||
pub fn set_current_task_deadline_after(duration_ticks: u64) -> impl Future<Output = Deadline> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
let task = super::task_from_waker(cx.waker());
|
|
||||||
let now = embassy_time_driver::now();
|
|
||||||
|
|
||||||
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
|
||||||
// it for now, we can probably make this wrapping_add for performance
|
|
||||||
// reasons later.
|
|
||||||
let deadline = now.saturating_add(duration_ticks);
|
|
||||||
|
|
||||||
task.header().metadata.deadline().set(deadline);
|
|
||||||
|
|
||||||
Poll::Ready(Deadline::new(deadline))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the current task's deadline `increment_ticks` from the previous deadline.
|
|
||||||
///
|
|
||||||
/// This deadline is saturated to the max tick value.
|
|
||||||
///
|
|
||||||
/// Note that by default (unless otherwise set), tasks start life with the deadline
|
|
||||||
/// u64::MAX, which means this method will have no effect.
|
|
||||||
///
|
|
||||||
/// This method is a future in order to access the currently executing task's
|
|
||||||
/// header which contains the deadline
|
|
||||||
///
|
|
||||||
/// Analogous to one increment of `Ticker::every().next()`.
|
|
||||||
///
|
|
||||||
/// Returns the deadline that was set.
|
|
||||||
#[must_use = "Setting deadline must be polled to be effective"]
|
|
||||||
pub fn increment_current_task_deadline(increment_ticks: u64) -> impl Future<Output = Deadline> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
let task_header = super::task_from_waker(cx.waker()).header();
|
|
||||||
|
|
||||||
// Get the last value
|
|
||||||
let last = task_header.metadata.deadline().instant_ticks();
|
|
||||||
|
|
||||||
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
|
||||||
// it for now, we can probably make this wrapping_add for performance
|
|
||||||
// reasons later.
|
|
||||||
let deadline = last.saturating_add(increment_ticks);
|
|
||||||
|
|
||||||
// Store the new value
|
|
||||||
task_header.metadata.deadline().set(deadline);
|
|
||||||
|
|
||||||
Poll::Ready(Deadline::new(deadline))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the current task's deadline as a tick value.
|
|
||||||
///
|
|
||||||
/// This method is a future in order to access the currently executing task's
|
|
||||||
/// header which contains the deadline
|
|
||||||
pub fn get_current_task_deadline() -> impl Future<Output = Self> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
let task = super::task_from_waker(cx.waker());
|
|
||||||
|
|
||||||
let deadline = task.header().metadata.deadline().instant_ticks();
|
|
||||||
Poll::Ready(Self::new(deadline))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the current task's deadline, returning the previous value.
|
|
||||||
///
|
|
||||||
/// This sets the deadline to the default value of `u64::MAX`, meaning all
|
|
||||||
/// tasks with set deadlines will be scheduled BEFORE this task.
|
|
||||||
#[must_use = "Clearing deadline must be polled to be effective"]
|
|
||||||
pub fn clear_current_task_deadline() -> impl Future<Output = Self> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
let task_header = super::task_from_waker(cx.waker()).header();
|
|
||||||
|
|
||||||
// get the old value
|
|
||||||
let deadline = task_header.metadata.deadline().instant_ticks();
|
|
||||||
// Store the default value
|
|
||||||
task_header.metadata.deadline().set(Self::UNSET_DEADLINE_TICKS);
|
|
||||||
|
|
||||||
Poll::Ready(Self::new(deadline))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ pub(crate) mod util;
|
|||||||
#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
|
#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
|
||||||
mod waker;
|
mod waker;
|
||||||
|
|
||||||
#[cfg(feature = "metadata-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
mod deadline;
|
mod deadline;
|
||||||
|
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
@ -39,7 +39,7 @@ use core::sync::atomic::AtomicPtr;
|
|||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::Ordering;
|
||||||
use core::task::{Context, Poll, Waker};
|
use core::task::{Context, Poll, Waker};
|
||||||
|
|
||||||
#[cfg(feature = "metadata-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
pub use deadline::Deadline;
|
pub use deadline::Deadline;
|
||||||
use embassy_executor_timer_queue::TimerQueueItem;
|
use embassy_executor_timer_queue::TimerQueueItem;
|
||||||
#[cfg(feature = "arch-avr")]
|
#[cfg(feature = "arch-avr")]
|
||||||
@ -302,7 +302,7 @@ impl<F: Future + 'static> AvailableTask<F> {
|
|||||||
|
|
||||||
// By default, deadlines are set to the maximum value, so that any task WITH
|
// By default, deadlines are set to the maximum value, so that any task WITH
|
||||||
// a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
|
// a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
|
||||||
#[cfg(feature = "edf-scheduler")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
self.task
|
self.task
|
||||||
.raw
|
.raw
|
||||||
.metadata
|
.metadata
|
||||||
|
@ -2,7 +2,7 @@ use core::ptr::{addr_of_mut, NonNull};
|
|||||||
|
|
||||||
use cordyceps::sorted_list::Links;
|
use cordyceps::sorted_list::Links;
|
||||||
use cordyceps::Linked;
|
use cordyceps::Linked;
|
||||||
#[cfg(feature = "edf-scheduler")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
use cordyceps::SortedList;
|
use cordyceps::SortedList;
|
||||||
|
|
||||||
#[cfg(target_has_atomic = "ptr")]
|
#[cfg(target_has_atomic = "ptr")]
|
||||||
@ -83,7 +83,7 @@ impl RunQueue {
|
|||||||
/// Empty the queue, then call `on_task` for each task that was in the queue.
|
/// Empty the queue, then call `on_task` for each task that was in the queue.
|
||||||
/// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
|
/// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
|
||||||
/// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
|
/// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
|
||||||
#[cfg(not(feature = "edf-scheduler"))]
|
#[cfg(not(feature = "scheduler-deadline"))]
|
||||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||||
let taken = self.stack.take_all();
|
let taken = self.stack.take_all();
|
||||||
for taskref in taken {
|
for taskref in taken {
|
||||||
@ -106,7 +106,7 @@ impl RunQueue {
|
|||||||
///
|
///
|
||||||
/// This process will repeat until the local `sorted` queue AND the global
|
/// This process will repeat until the local `sorted` queue AND the global
|
||||||
/// runqueue are both empty, at which point this function will return.
|
/// runqueue are both empty, at which point this function will return.
|
||||||
#[cfg(feature = "edf-scheduler")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||||
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
|
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
|
||||||
lhs.metadata
|
lhs.metadata
|
||||||
|
Loading…
x
Reference in New Issue
Block a user