Merge pull request #4652 from embassy-rs/executor-priority

executor: add priority scheduler.
This commit is contained in:
Dario Nieuwenhuis 2025-09-11 18:30:50 +02:00 committed by GitHub
commit 49a7770c19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 68 additions and 13 deletions

6
ci.sh
View File

@ -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-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 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 \

View File

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added new metadata API for tasks.
- Main task automatically gets a name of `main` when the `metadata-name` feature is enabled.
- Upgraded rtos-trace
- Added optional "highest priority" scheduling
- Added optional "earliest deadline first" EDF scheduling
## 0.9.1 - 2025-08-31

View File

@ -24,7 +24,12 @@ build = [
{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", "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 = "armv7r-none-eabi", 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]
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/"
features = ["defmt", "scheduler-deadline"]
features = ["defmt", "scheduler-deadline", "scheduler-priority"]
flavors = [
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
@ -47,7 +52,7 @@ flavors = [
[package.metadata.docs.rs]
default-target = "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]
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.
scheduler-deadline = []
## Enable "Highest Priority First" Scheduler. Adds some overhead.
scheduler-priority = []
## Enable the embassy_time_driver dependency.
## This can unlock extra APIs, for example for the `sheduler-deadline`
embassy-time-driver = ["dep:embassy-time-driver"]

View File

@ -1,6 +1,8 @@
#[cfg(feature = "metadata-name")]
use core::cell::Cell;
use core::future::{poll_fn, Future};
#[cfg(feature = "scheduler-priority")]
use core::sync::atomic::{AtomicU8, Ordering};
use core::task::Poll;
#[cfg(feature = "metadata-name")]
@ -14,6 +16,8 @@ use crate::raw::Deadline;
pub struct Metadata {
#[cfg(feature = "metadata-name")]
name: Mutex<Cell<Option<&'static str>>>,
#[cfg(feature = "scheduler-priority")]
priority: AtomicU8,
#[cfg(feature = "scheduler-deadline")]
deadline: raw::Deadline,
}
@ -23,6 +27,8 @@ impl Metadata {
Self {
#[cfg(feature = "metadata-name")]
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
// will be lazily initalized in `initialize_impl`
#[cfg(feature = "scheduler-deadline")]
@ -33,6 +39,14 @@ impl Metadata {
pub(crate) fn reset(&self) {
#[cfg(feature = "metadata-name")]
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.
@ -61,6 +75,18 @@ impl Metadata {
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.
#[cfg(feature = "scheduler-deadline")]
pub fn deadline(&self) -> u64 {

View File

@ -300,11 +300,6 @@ impl<F: Future + 'static> AvailableTask<F> {
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
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);
SpawnToken::new(task)

View File

@ -2,7 +2,7 @@ use core::ptr::{addr_of_mut, NonNull};
use cordyceps::sorted_list::Links;
use cordyceps::Linked;
#[cfg(feature = "scheduler-deadline")]
#[cfg(any(feature = "scheduler-priority", 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 = "scheduler-deadline"))]
#[cfg(not(any(feature = "scheduler-priority", 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,10 +106,29 @@ 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 = "scheduler-deadline")]
#[cfg(any(feature = "scheduler-priority", 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.deadline().cmp(&rhs.metadata.deadline()));
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
// 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 {
// For each loop, grab any newly pended items