use core::ptr::{NonNull, addr_of_mut};
use cordyceps::Linked;
#[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))]
use cordyceps::SortedList;
use cordyceps::sorted_list::Links;
#[cfg(target_has_atomic = "ptr")]
type TransferStack<T> = cordyceps::TransferStack<T>;
#[cfg(not(target_has_atomic = "ptr"))]
type TransferStack<T> = MutexTransferStack<T>;
use super::{TaskHeader, TaskRef};
pub(crate) type RunQueueItem = Links<TaskHeader>;
unsafe impl Linked<Links<TaskHeader>> for TaskHeader {
type Handle = TaskRef;
fn into_ptr(r: TaskRef) -> NonNull<TaskHeader> {
r.ptr
}
unsafe fn from_ptr(ptr: NonNull<TaskHeader>) -> TaskRef {
TaskRef { ptr }
}
unsafe fn links(ptr: NonNull<TaskHeader>) -> NonNull<Links<TaskHeader>> {
let ptr: *mut TaskHeader = ptr.as_ptr();
NonNull::new_unchecked(addr_of_mut!((*ptr).run_queue_item))
}
}
pub(crate) struct RunQueue {
stack: TransferStack<TaskHeader>,
}
impl RunQueue {
pub const fn new() -> Self {
Self {
stack: TransferStack::new(),
}
}
#[inline(always)]
pub(crate) unsafe fn enqueue(&self, task: TaskRef, _tok: super::state::Token) -> bool {
self.stack.push_was_empty(
task,
#[cfg(not(target_has_atomic = "ptr"))]
_tok,
)
}
#[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 {
run_dequeue(&taskref);
on_task(taskref);
}
}
#[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| {
#[cfg(feature = "scheduler-priority")]
{
let lp = lhs.metadata.priority();
let rp = rhs.metadata.priority();
if lp != rp {
return lp.cmp(&rp).reverse();
}
}
#[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 {
let taken = self.stack.take_all();
sorted.extend(taken);
let Some(taskref) = sorted.pop_front() else {
return;
};
run_dequeue(&taskref);
on_task(taskref);
}
}
}
#[cfg(target_has_atomic = "ptr")]
#[inline(always)]
fn run_dequeue(taskref: &TaskRef) {
taskref.header().state.run_dequeue();
}
#[cfg(not(target_has_atomic = "ptr"))]
#[inline(always)]
fn run_dequeue(taskref: &TaskRef) {
critical_section::with(|cs| {
taskref.header().state.run_dequeue(cs);
})
}
#[cfg(not(target_has_atomic = "ptr"))]
struct MutexTransferStack<T: Linked<cordyceps::stack::Links<T>>> {
inner: critical_section::Mutex<core::cell::UnsafeCell<cordyceps::Stack<T>>>,
}
#[cfg(not(target_has_atomic = "ptr"))]
impl<T: Linked<cordyceps::stack::Links<T>>> MutexTransferStack<T> {
const fn new() -> Self {
Self {
inner: critical_section::Mutex::new(core::cell::UnsafeCell::new(cordyceps::Stack::new())),
}
}
fn push_was_empty(&self, item: T::Handle, token: super::state::Token) -> bool {
let inner = unsafe { &mut *self.inner.borrow(token).get() };
let is_empty = inner.is_empty();
inner.push(item);
is_empty
}
fn take_all(&self) -> cordyceps::Stack<T> {
critical_section::with(|cs| {
let inner = unsafe { &mut *self.inner.borrow(cs).get() };
inner.take_all()
})
}
}