mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 06:40:32 +00:00
Change deadline to use internal atomics
This commit is contained in:
parent
b5c9e72100
commit
3f606b28f3
@ -1,15 +1,41 @@
|
|||||||
use core::future::{poll_fn, Future};
|
use core::future::{poll_fn, Future};
|
||||||
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
use core::task::Poll;
|
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
|
||||||
///
|
///
|
||||||
/// Requires the `edf-scheduler` feature
|
/// Requires the `edf-scheduler` feature
|
||||||
pub struct Deadline {
|
pub struct Deadline {
|
||||||
/// Deadline value in ticks, same time base and ticks as `embassy-time`
|
instant_ticks_hi: AtomicU32,
|
||||||
pub instant_ticks: u64,
|
instant_ticks_lo: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deadline {
|
impl Deadline {
|
||||||
|
pub(crate) const fn new(instant_ticks: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
instant_ticks_hi: AtomicU32::new((instant_ticks >> 32) as u32),
|
||||||
|
instant_ticks_lo: AtomicU32::new(instant_ticks as u32),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const fn new_unset() -> Self {
|
||||||
|
Self::new(Self::UNSET_DEADLINE_TICKS)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set(&self, instant_ticks: u64) {
|
||||||
|
self.instant_ticks_hi
|
||||||
|
.store((instant_ticks >> 32) as u32, Ordering::Relaxed);
|
||||||
|
self.instant_ticks_lo.store(instant_ticks as u32, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deadline value in ticks, same time base and ticks as `embassy-time`
|
||||||
|
pub fn instant_ticks(&self) -> u64 {
|
||||||
|
let hi = self.instant_ticks_hi.load(Ordering::Relaxed) as u64;
|
||||||
|
let lo = self.instant_ticks_lo.load(Ordering::Relaxed) as u64;
|
||||||
|
|
||||||
|
(hi << 32) | lo
|
||||||
|
}
|
||||||
|
|
||||||
/// Sentinel value representing an "unset" deadline, which has lower priority
|
/// Sentinel value representing an "unset" deadline, which has lower priority
|
||||||
/// than any other set deadline value
|
/// than any other set deadline value
|
||||||
pub const UNSET_DEADLINE_TICKS: u64 = u64::MAX;
|
pub const UNSET_DEADLINE_TICKS: u64 = u64::MAX;
|
||||||
@ -17,7 +43,7 @@ impl Deadline {
|
|||||||
/// Does the given Deadline represent an "unset" deadline?
|
/// Does the given Deadline represent an "unset" deadline?
|
||||||
#[inline]
|
#[inline]
|
||||||
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`
|
/// Set the current task's deadline at exactly `instant_ticks`
|
||||||
@ -32,11 +58,7 @@ impl Deadline {
|
|||||||
pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> {
|
pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let task = super::task_from_waker(cx.waker());
|
let task = super::task_from_waker(cx.waker());
|
||||||
// SAFETY: A task can only modify its own deadline, while the task is being
|
task.header().deadline.set(instant_ticks);
|
||||||
// polled, meaning that there cannot be concurrent access to the deadline.
|
|
||||||
unsafe {
|
|
||||||
task.header().deadline.set(instant_ticks);
|
|
||||||
}
|
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -61,14 +83,9 @@ impl Deadline {
|
|||||||
// reasons later.
|
// reasons later.
|
||||||
let deadline = now.saturating_add(duration_ticks);
|
let deadline = now.saturating_add(duration_ticks);
|
||||||
|
|
||||||
// SAFETY: A task can only modify its own deadline, while the task is being
|
task.header().deadline.set(deadline);
|
||||||
// polled, meaning that there cannot be concurrent access to the deadline.
|
|
||||||
unsafe {
|
Poll::Ready(Deadline::new(deadline))
|
||||||
task.header().deadline.set(deadline);
|
|
||||||
}
|
|
||||||
Poll::Ready(Deadline {
|
|
||||||
instant_ticks: deadline,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,24 +107,18 @@ impl Deadline {
|
|||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let task = super::task_from_waker(cx.waker());
|
let task = super::task_from_waker(cx.waker());
|
||||||
|
|
||||||
// SAFETY: A task can only modify its own deadline, while the task is being
|
// Get the last value
|
||||||
// polled, meaning that there cannot be concurrent access to the deadline.
|
let last = task.header().deadline.instant_ticks();
|
||||||
unsafe {
|
|
||||||
// Get the last value
|
|
||||||
let last = task.header().deadline.get();
|
|
||||||
|
|
||||||
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
||||||
// it for now, we can probably make this wrapping_add for performance
|
// it for now, we can probably make this wrapping_add for performance
|
||||||
// reasons later.
|
// reasons later.
|
||||||
let deadline = last.saturating_add(increment_ticks);
|
let deadline = last.saturating_add(increment_ticks);
|
||||||
|
|
||||||
// Store the new value
|
// Store the new value
|
||||||
task.header().deadline.set(deadline);
|
task.header().deadline.set(deadline);
|
||||||
|
|
||||||
Poll::Ready(Deadline {
|
Poll::Ready(Deadline::new(deadline))
|
||||||
instant_ticks: deadline,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,12 +130,8 @@ impl Deadline {
|
|||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let task = super::task_from_waker(cx.waker());
|
let task = super::task_from_waker(cx.waker());
|
||||||
|
|
||||||
// SAFETY: A task can only modify its own deadline, while the task is being
|
let deadline = task.header().deadline.instant_ticks();
|
||||||
// polled, meaning that there cannot be concurrent access to the deadline.
|
Poll::Ready(Self::new(deadline))
|
||||||
let deadline = unsafe { task.header().deadline.get() };
|
|
||||||
Poll::Ready(Self {
|
|
||||||
instant_ticks: deadline,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,20 +144,12 @@ impl Deadline {
|
|||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let task = super::task_from_waker(cx.waker());
|
let task = super::task_from_waker(cx.waker());
|
||||||
|
|
||||||
// SAFETY: A task can only modify its own deadline, while the task is being
|
// get the old value
|
||||||
// polled, meaning that there cannot be concurrent access to the deadline.
|
let deadline = task.header().deadline.instant_ticks();
|
||||||
let deadline = unsafe {
|
// Store the default value
|
||||||
// get the old value
|
task.header().deadline.set(Self::UNSET_DEADLINE_TICKS);
|
||||||
let d = task.header().deadline.get();
|
|
||||||
// Store the default value
|
|
||||||
task.header().deadline.set(Self::UNSET_DEADLINE_TICKS);
|
|
||||||
// return the old value
|
|
||||||
d
|
|
||||||
};
|
|
||||||
|
|
||||||
Poll::Ready(Self {
|
Poll::Ready(Self::new(deadline))
|
||||||
instant_ticks: deadline,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ pub(crate) struct TaskHeader {
|
|||||||
/// Earliest Deadline First scheduler Deadline. This field should not be accessed
|
/// 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.
|
/// outside the context of the task itself as it being polled by the executor.
|
||||||
#[cfg(feature = "edf-scheduler")]
|
#[cfg(feature = "edf-scheduler")]
|
||||||
pub(crate) deadline: SyncUnsafeCell<u64>,
|
pub(crate) deadline: Deadline,
|
||||||
|
|
||||||
pub(crate) executor: AtomicPtr<SyncExecutor>,
|
pub(crate) executor: AtomicPtr<SyncExecutor>,
|
||||||
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
|
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
|
||||||
@ -215,7 +215,7 @@ impl<F: Future + 'static> TaskStorage<F> {
|
|||||||
// 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 = "edf-scheduler")]
|
#[cfg(feature = "edf-scheduler")]
|
||||||
deadline: SyncUnsafeCell::new(0u64),
|
deadline: Deadline::new_unset(),
|
||||||
executor: AtomicPtr::new(core::ptr::null_mut()),
|
executor: AtomicPtr::new(core::ptr::null_mut()),
|
||||||
// Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
|
// Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
|
||||||
poll_fn: SyncUnsafeCell::new(None),
|
poll_fn: SyncUnsafeCell::new(None),
|
||||||
|
@ -108,11 +108,9 @@ impl RunQueue {
|
|||||||
/// 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 = "edf-scheduler")]
|
||||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||||
// SAFETY: `deadline` can only be set through the `Deadline` interface, which
|
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
|
||||||
// only allows access to this value while the given task is being polled.
|
lhs.deadline.instant_ticks().cmp(&rhs.deadline.instant_ticks())
|
||||||
// This acts as mutual exclusion for access.
|
});
|
||||||
let mut sorted =
|
|
||||||
SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| unsafe { lhs.deadline.get().cmp(&rhs.deadline.get()) });
|
|
||||||
|
|
||||||
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