use core::ptr;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use super::{TaskHeader, TaskRef};
use crate::raw::util::SyncUnsafeCell;
pub(crate) struct RunQueueItem {
next: SyncUnsafeCell<Option<TaskRef>>,
}
impl RunQueueItem {
pub const fn new() -> Self {
Self {
next: SyncUnsafeCell::new(None),
}
}
}
pub(crate) struct RunQueue {
head: AtomicPtr<TaskHeader>,
}
impl RunQueue {
pub const fn new() -> Self {
Self {
head: AtomicPtr::new(ptr::null_mut()),
}
}
#[inline(always)]
pub(crate) unsafe fn enqueue(&self, task: TaskRef, _: super::state::Token) -> bool {
let mut was_empty = false;
self.head
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
was_empty = prev.is_null();
unsafe {
let prev = NonNull::new(prev).map(|ptr| TaskRef::from_ptr(ptr.as_ptr()));
task.header().run_queue_item.next.set(prev);
}
Some(task.as_ptr() as *mut _)
})
.ok();
was_empty
}
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
let ptr = self.head.swap(ptr::null_mut(), Ordering::AcqRel);
let mut next = unsafe { NonNull::new(ptr).map(|ptr| TaskRef::from_ptr(ptr.as_ptr())) };
while let Some(task) = next {
next = unsafe { task.header().run_queue_item.next.get() };
task.header().state.run_dequeue();
on_task(task);
}
}
}