mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 14:44:32 +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.
|
||||
metadata-name = ["embassy-executor-macros/metadata-name"]
|
||||
## Enable the `deadline` field in task metadata.
|
||||
metadata-deadline = []
|
||||
|
||||
#! ### Executor
|
||||
|
||||
@ -131,9 +129,13 @@ executor-interrupt = []
|
||||
## Enable tracing hooks
|
||||
trace = ["_any_trace"]
|
||||
## 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 = []
|
||||
|
||||
## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize
|
||||
## 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 crate::raw;
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
use crate::raw::Deadline;
|
||||
|
||||
/// Metadata associated with a task.
|
||||
pub struct Metadata {
|
||||
#[cfg(feature = "metadata-name")]
|
||||
name: Mutex<Cell<Option<&'static str>>>,
|
||||
#[cfg(feature = "metadata-deadline")]
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
deadline: raw::Deadline,
|
||||
}
|
||||
|
||||
@ -23,7 +25,7 @@ impl Metadata {
|
||||
name: Mutex::new(Cell::new(None)),
|
||||
// NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
|
||||
// will be lazily initalized in `initialize_impl`
|
||||
#[cfg(feature = "metadata-deadline")]
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
deadline: raw::Deadline::new_unset(),
|
||||
}
|
||||
}
|
||||
@ -59,10 +61,62 @@ impl Metadata {
|
||||
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
|
||||
}
|
||||
|
||||
/// Earliest Deadline First scheduler Deadline. This field should not be accessed
|
||||
/// outside the context of the task itself as it being polled by the executor.
|
||||
#[cfg(feature = "metadata-deadline")]
|
||||
/// Get this task's deadline.
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub fn deadline(&self) -> &raw::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::task::Poll;
|
||||
|
||||
/// A type for interacting with the deadline of the current task
|
||||
///
|
||||
@ -49,111 +47,4 @@ impl Deadline {
|
||||
pub fn is_unset(&self) -> bool {
|
||||
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")]
|
||||
mod waker;
|
||||
|
||||
#[cfg(feature = "metadata-deadline")]
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
mod deadline;
|
||||
|
||||
use core::future::Future;
|
||||
@ -39,7 +39,7 @@ use core::sync::atomic::AtomicPtr;
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::task::{Context, Poll, Waker};
|
||||
|
||||
#[cfg(feature = "metadata-deadline")]
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub use deadline::Deadline;
|
||||
use embassy_executor_timer_queue::TimerQueueItem;
|
||||
#[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
|
||||
// a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
|
||||
#[cfg(feature = "edf-scheduler")]
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
self.task
|
||||
.raw
|
||||
.metadata
|
||||
|
@ -2,7 +2,7 @@ use core::ptr::{addr_of_mut, NonNull};
|
||||
|
||||
use cordyceps::sorted_list::Links;
|
||||
use cordyceps::Linked;
|
||||
#[cfg(feature = "edf-scheduler")]
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
use cordyceps::SortedList;
|
||||
|
||||
#[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.
|
||||
/// 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.
|
||||
#[cfg(not(feature = "edf-scheduler"))]
|
||||
#[cfg(not(feature = "scheduler-deadline"))]
|
||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||
let taken = self.stack.take_all();
|
||||
for taskref in taken {
|
||||
@ -106,7 +106,7 @@ impl RunQueue {
|
||||
///
|
||||
/// This process will repeat until the local `sorted` queue AND the global
|
||||
/// 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)) {
|
||||
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
|
||||
lhs.metadata
|
||||
|
Loading…
x
Reference in New Issue
Block a user