mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-26 20:00:27 +00:00
Merge pull request #4652 from embassy-rs/executor-priority
executor: add priority scheduler.
This commit is contained in:
commit
49a7770c19
6
ci.sh
6
ci.sh
@ -38,6 +38,12 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
|
||||||
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,executor-thread,embassy-time-driver \
|
||||||
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,executor-thread,embassy-time-driver,scheduler-priority \
|
||||||
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,executor-thread,embassy-time-driver,scheduler-priority,scheduler-deadline \
|
||||||
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,executor-thread,embassy-time-driver,scheduler-deadline \
|
||||||
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,executor-thread,scheduler-priority,scheduler-deadline \
|
||||||
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,executor-thread,scheduler-deadline \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features arch-cortex-ar,executor-thread \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features arch-cortex-ar,executor-thread \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabi --features arch-cortex-ar,executor-thread \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabi --features arch-cortex-ar,executor-thread \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \
|
||||||
|
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added new metadata API for tasks.
|
- Added new metadata API for tasks.
|
||||||
- Main task automatically gets a name of `main` when the `metadata-name` feature is enabled.
|
- Main task automatically gets a name of `main` when the `metadata-name` feature is enabled.
|
||||||
- Upgraded rtos-trace
|
- Upgraded rtos-trace
|
||||||
|
- Added optional "highest priority" scheduling
|
||||||
- Added optional "earliest deadline first" EDF scheduling
|
- Added optional "earliest deadline first" EDF scheduling
|
||||||
|
|
||||||
## 0.9.1 - 2025-08-31
|
## 0.9.1 - 2025-08-31
|
||||||
|
@ -24,7 +24,12 @@ build = [
|
|||||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread"]},
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread"]},
|
||||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt"]},
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt"]},
|
||||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"]},
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"]},
|
||||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-deadline", "embassy-time-driver"]},
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver"]},
|
||||||
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-priority"]},
|
||||||
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-priority", "scheduler-deadline"]},
|
||||||
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-deadline"]},
|
||||||
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-priority", "scheduler-deadline"]},
|
||||||
|
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-deadline"]},
|
||||||
{target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
|
{target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
|
||||||
{target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
|
{target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
|
||||||
{target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]},
|
{target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]},
|
||||||
@ -36,7 +41,7 @@ build = [
|
|||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
|
||||||
features = ["defmt", "scheduler-deadline"]
|
features = ["defmt", "scheduler-deadline", "scheduler-priority"]
|
||||||
flavors = [
|
flavors = [
|
||||||
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
|
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
|
||||||
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
|
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
|
||||||
@ -47,7 +52,7 @@ flavors = [
|
|||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
default-target = "thumbv7em-none-eabi"
|
default-target = "thumbv7em-none-eabi"
|
||||||
targets = ["thumbv7em-none-eabi"]
|
targets = ["thumbv7em-none-eabi"]
|
||||||
features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt", "scheduler-deadline", "embassy-time-driver"]
|
features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt", "scheduler-deadline", "scheduler-priority", "embassy-time-driver"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = { version = "1.0.1", optional = true }
|
defmt = { version = "1.0.1", optional = true }
|
||||||
@ -136,6 +141,9 @@ _any_trace = []
|
|||||||
## tasks based on the remaining time before their deadline. Adds some overhead.
|
## tasks based on the remaining time before their deadline. Adds some overhead.
|
||||||
scheduler-deadline = []
|
scheduler-deadline = []
|
||||||
|
|
||||||
|
## Enable "Highest Priority First" Scheduler. Adds some overhead.
|
||||||
|
scheduler-priority = []
|
||||||
|
|
||||||
## Enable the embassy_time_driver dependency.
|
## Enable the embassy_time_driver dependency.
|
||||||
## This can unlock extra APIs, for example for the `sheduler-deadline`
|
## This can unlock extra APIs, for example for the `sheduler-deadline`
|
||||||
embassy-time-driver = ["dep:embassy-time-driver"]
|
embassy-time-driver = ["dep:embassy-time-driver"]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#[cfg(feature = "metadata-name")]
|
#[cfg(feature = "metadata-name")]
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::future::{poll_fn, Future};
|
use core::future::{poll_fn, Future};
|
||||||
|
#[cfg(feature = "scheduler-priority")]
|
||||||
|
use core::sync::atomic::{AtomicU8, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
#[cfg(feature = "metadata-name")]
|
#[cfg(feature = "metadata-name")]
|
||||||
@ -14,6 +16,8 @@ use crate::raw::Deadline;
|
|||||||
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 = "scheduler-priority")]
|
||||||
|
priority: AtomicU8,
|
||||||
#[cfg(feature = "scheduler-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
deadline: raw::Deadline,
|
deadline: raw::Deadline,
|
||||||
}
|
}
|
||||||
@ -23,6 +27,8 @@ impl Metadata {
|
|||||||
Self {
|
Self {
|
||||||
#[cfg(feature = "metadata-name")]
|
#[cfg(feature = "metadata-name")]
|
||||||
name: Mutex::new(Cell::new(None)),
|
name: Mutex::new(Cell::new(None)),
|
||||||
|
#[cfg(feature = "scheduler-priority")]
|
||||||
|
priority: AtomicU8::new(0),
|
||||||
// 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 = "scheduler-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
@ -33,6 +39,14 @@ impl Metadata {
|
|||||||
pub(crate) fn reset(&self) {
|
pub(crate) fn reset(&self) {
|
||||||
#[cfg(feature = "metadata-name")]
|
#[cfg(feature = "metadata-name")]
|
||||||
critical_section::with(|cs| self.name.borrow(cs).set(None));
|
critical_section::with(|cs| self.name.borrow(cs).set(None));
|
||||||
|
|
||||||
|
#[cfg(feature = "scheduler-priority")]
|
||||||
|
self.set_priority(0);
|
||||||
|
|
||||||
|
// 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 = "scheduler-deadline")]
|
||||||
|
self.unset_deadline();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the metadata for the current task.
|
/// Get the metadata for the current task.
|
||||||
@ -61,6 +75,18 @@ impl Metadata {
|
|||||||
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
|
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this task's priority.
|
||||||
|
#[cfg(feature = "scheduler-priority")]
|
||||||
|
pub fn priority(&self) -> u8 {
|
||||||
|
self.priority.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set this task's priority.
|
||||||
|
#[cfg(feature = "scheduler-priority")]
|
||||||
|
pub fn set_priority(&self, priority: u8) {
|
||||||
|
self.priority.store(priority, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get this task's deadline.
|
/// Get this task's deadline.
|
||||||
#[cfg(feature = "scheduler-deadline")]
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
pub fn deadline(&self) -> u64 {
|
pub fn deadline(&self) -> u64 {
|
||||||
|
@ -300,11 +300,6 @@ impl<F: Future + 'static> AvailableTask<F> {
|
|||||||
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
||||||
self.task.future.write_in_place(future);
|
self.task.future.write_in_place(future);
|
||||||
|
|
||||||
// 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 = "scheduler-deadline")]
|
|
||||||
self.task.raw.metadata.unset_deadline();
|
|
||||||
|
|
||||||
let task = TaskRef::new(self.task);
|
let task = TaskRef::new(self.task);
|
||||||
|
|
||||||
SpawnToken::new(task)
|
SpawnToken::new(task)
|
||||||
|
@ -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 = "scheduler-deadline")]
|
#[cfg(any(feature = "scheduler-priority", 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 = "scheduler-deadline"))]
|
#[cfg(not(any(feature = "scheduler-priority", 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,10 +106,29 @@ 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 = "scheduler-deadline")]
|
#[cfg(any(feature = "scheduler-priority", 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 =
|
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
|
||||||
SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| lhs.metadata.deadline().cmp(&rhs.metadata.deadline()));
|
// compare by priority first
|
||||||
|
#[cfg(feature = "scheduler-priority")]
|
||||||
|
{
|
||||||
|
let lp = lhs.metadata.priority();
|
||||||
|
let rp = rhs.metadata.priority();
|
||||||
|
if lp != rp {
|
||||||
|
return lp.cmp(&rp).reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// compare deadlines in case of tie.
|
||||||
|
#[cfg(feature = "scheduler-deadline")]
|
||||||
|
{
|
||||||
|
let ld = lhs.metadata.deadline();
|
||||||
|
let rd = rhs.metadata.deadline();
|
||||||
|
if ld != rd {
|
||||||
|
return ld.cmp(&rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core::cmp::Ordering::Equal
|
||||||
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// For each loop, grab any newly pended items
|
// For each loop, grab any newly pended items
|
||||||
|
Loading…
x
Reference in New Issue
Block a user