mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-28 12:50:37 +00:00
Dependency enablement trickery
This commit is contained in:
parent
ba0426f767
commit
ed2e51bfa4
@ -46,7 +46,7 @@ flavors = [
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "thumbv7em-none-eabi"
|
||||
targets = ["thumbv7em-none-eabi"]
|
||||
features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]
|
||||
features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt", "drs-scheduler"]
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "1.0.1", optional = true }
|
||||
@ -76,13 +76,17 @@ js-sys = { version = "0.3", optional = true }
|
||||
# arch-avr dependencies
|
||||
avr-device = { version = "0.7.0", optional = true }
|
||||
|
||||
[dependencies.cordyceps]
|
||||
# note: targeting v0.3.3, to be released when
|
||||
# Note: this is ONLY a dependency when the target has atomics, this is
|
||||
# used for `run_queue_atomics`. We need to be conditional because
|
||||
# cordyceps *requires* the use of atomics, so we pull it in when
|
||||
# `run_queue_atomics` would be enabled, and NOT when `run_queue_critical_section`
|
||||
# would be enabled.
|
||||
[target.'cfg(target_has_atomic="ptr")'.dependencies.cordyceps]
|
||||
# TODO: targeting v0.3.3, to be released when
|
||||
# https://github.com/hawkw/mycelium/pull/520 is merged
|
||||
version = "0.3"
|
||||
git = "https://github.com/hawkw/mycelium"
|
||||
rev = "9649db0525b9972b95937d83d52d3f51cc486281"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies]
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
@ -133,5 +137,7 @@ trace = ["_any_trace"]
|
||||
rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"]
|
||||
_any_trace = []
|
||||
|
||||
## Enable "Deadline Rank Scheduler"
|
||||
drs-scheduler = ["dep:cordyceps", "dep:embassy-time-driver"]
|
||||
## Enable "Deadline Rank Sorted" Scheduler, using soft-realtime "deadlines" to prioritize
|
||||
## tasks based on the remaining time before their deadline. Adds some overhead. Requires
|
||||
## hardware atomic support
|
||||
drs-scheduler = ["dep:embassy-time-driver"]
|
||||
|
@ -2,6 +2,8 @@ use core::future::{poll_fn, Future};
|
||||
use core::task::Poll;
|
||||
|
||||
/// A type for interacting with the deadline of the current task
|
||||
///
|
||||
/// Requires the `drs-scheduler` feature
|
||||
pub struct Deadline {
|
||||
/// Deadline value in ticks, same time base and ticks as `embassy-time`
|
||||
pub instant_ticks: u64,
|
||||
|
@ -101,14 +101,14 @@ extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static
|
||||
/// - 5: Task is dequeued. The task's future is not polled, because exiting the task replaces its `poll_fn`.
|
||||
/// - 6: A task is waken when it is not spawned - `wake_task -> State::run_enqueue`
|
||||
pub(crate) struct TaskHeader {
|
||||
pub(crate) state: State,
|
||||
pub(crate) run_queue_item: RunQueueItem,
|
||||
|
||||
#[cfg(feature = "drs-scheduler")]
|
||||
/// Deadline Rank Scheduler Deadline. This field should not be accessed outside the context of
|
||||
/// the task itself as it being polled by the executor.
|
||||
#[cfg(feature = "drs-scheduler")]
|
||||
pub(crate) deadline: SyncUnsafeCell<u64>,
|
||||
|
||||
pub(crate) state: State,
|
||||
pub(crate) executor: AtomicPtr<SyncExecutor>,
|
||||
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
|
||||
|
||||
@ -211,10 +211,12 @@ impl<F: Future + 'static> TaskStorage<F> {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
raw: TaskHeader {
|
||||
state: State::new(),
|
||||
run_queue_item: RunQueueItem::new(),
|
||||
// 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 = "drs-scheduler")]
|
||||
deadline: SyncUnsafeCell::new(0u64),
|
||||
state: State::new(),
|
||||
executor: AtomicPtr::new(core::ptr::null_mut()),
|
||||
// Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
|
||||
poll_fn: SyncUnsafeCell::new(None),
|
||||
@ -311,7 +313,8 @@ impl<F: Future + 'static> AvailableTask<F> {
|
||||
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
||||
self.task.future.write_in_place(future);
|
||||
|
||||
// TODO(AJM): Some other way of setting this? Just a placeholder
|
||||
// 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 = "drs-scheduler")]
|
||||
self.task.raw.deadline.set(u64::MAX);
|
||||
|
||||
|
@ -66,6 +66,8 @@ impl RunQueue {
|
||||
self.stack.push_was_empty(task)
|
||||
}
|
||||
|
||||
/// # Standard atomic 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.
|
||||
@ -78,9 +80,20 @@ 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.
|
||||
/// # Deadline Ranked Sorted Scheduler
|
||||
///
|
||||
/// This algorithm will loop until all enqueued tasks are processed.
|
||||
///
|
||||
/// Before polling a task, all currently enqueued tasks will be popped from the
|
||||
/// runqueue, and will be added to the working `sorted` list, a linked-list that
|
||||
/// sorts tasks by their deadline, with nearest deadline items in the front, and
|
||||
/// furthest deadline items in the back.
|
||||
///
|
||||
/// After popping and sorting all pending tasks, the SOONEST task will be popped
|
||||
/// from the front of the queue, and polled by calling `on_task` on it.
|
||||
///
|
||||
/// 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 = "drs-scheduler")]
|
||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||
// SAFETY: `deadline` can only be set through the `Deadline` interface, which
|
||||
|
Loading…
x
Reference in New Issue
Block a user