2021-03-18 00:38:27 +01:00
|
|
|
use atomic_polyfill::Ordering;
|
2020-12-26 23:44:53 +01:00
|
|
|
use core::cell::Cell;
|
2021-02-02 05:14:52 +01:00
|
|
|
use core::cmp::min;
|
|
|
|
use core::ptr;
|
|
|
|
use core::ptr::NonNull;
|
2020-12-26 23:44:53 +01:00
|
|
|
|
2021-03-18 00:20:02 +01:00
|
|
|
use super::raw::{TaskHeader, STATE_TIMER_QUEUED};
|
2020-12-26 23:44:53 +01:00
|
|
|
use crate::time::Instant;
|
|
|
|
|
|
|
|
pub(crate) struct TimerQueueItem {
|
2021-03-18 00:20:02 +01:00
|
|
|
next: Cell<*mut TaskHeader>,
|
2020-12-26 23:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TimerQueueItem {
|
|
|
|
pub const fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
next: Cell::new(ptr::null_mut()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct TimerQueue {
|
2021-03-18 00:20:02 +01:00
|
|
|
head: Cell<*mut TaskHeader>,
|
2020-12-26 23:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TimerQueue {
|
|
|
|
pub const fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
head: Cell::new(ptr::null_mut()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 00:20:02 +01:00
|
|
|
pub(crate) unsafe fn update(&self, p: NonNull<TaskHeader>) {
|
2021-02-02 05:14:52 +01:00
|
|
|
let task = p.as_ref();
|
|
|
|
if task.expires_at.get() != Instant::MAX {
|
|
|
|
let old_state = task.state.fetch_or(STATE_TIMER_QUEUED, Ordering::AcqRel);
|
2020-12-26 23:44:53 +01:00
|
|
|
let is_new = old_state & STATE_TIMER_QUEUED == 0;
|
|
|
|
|
|
|
|
if is_new {
|
2021-02-02 05:14:52 +01:00
|
|
|
task.timer_queue_item.next.set(self.head.get());
|
|
|
|
self.head.set(p.as_ptr());
|
2020-12-26 23:44:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) unsafe fn next_expiration(&self) -> Instant {
|
|
|
|
let mut res = Instant::MAX;
|
|
|
|
self.retain(|p| {
|
2021-02-02 05:14:52 +01:00
|
|
|
let task = p.as_ref();
|
|
|
|
let expires = task.expires_at.get();
|
2020-12-26 23:44:53 +01:00
|
|
|
res = min(res, expires);
|
|
|
|
expires != Instant::MAX
|
|
|
|
});
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2021-03-18 00:20:02 +01:00
|
|
|
pub(crate) unsafe fn dequeue_expired(
|
|
|
|
&self,
|
|
|
|
now: Instant,
|
|
|
|
on_task: impl Fn(NonNull<TaskHeader>),
|
|
|
|
) {
|
2020-12-26 23:44:53 +01:00
|
|
|
self.retain(|p| {
|
2021-02-02 05:14:52 +01:00
|
|
|
let task = p.as_ref();
|
|
|
|
if task.expires_at.get() <= now {
|
2020-12-26 23:44:53 +01:00
|
|
|
on_task(p);
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-03-18 00:20:02 +01:00
|
|
|
pub(crate) unsafe fn retain(&self, mut f: impl FnMut(NonNull<TaskHeader>) -> bool) {
|
2020-12-26 23:44:53 +01:00
|
|
|
let mut prev = &self.head;
|
|
|
|
while !prev.get().is_null() {
|
2021-02-02 05:14:52 +01:00
|
|
|
let p = NonNull::new_unchecked(prev.get());
|
|
|
|
let task = &*p.as_ptr();
|
2020-12-26 23:44:53 +01:00
|
|
|
if f(p) {
|
|
|
|
// Skip to next
|
2021-02-02 05:14:52 +01:00
|
|
|
prev = &task.timer_queue_item.next;
|
2020-12-26 23:44:53 +01:00
|
|
|
} else {
|
|
|
|
// Remove it
|
2021-02-02 05:14:52 +01:00
|
|
|
prev.set(task.timer_queue_item.next.get());
|
|
|
|
task.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::AcqRel);
|
2020-12-26 23:44:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|