use core::cell::UnsafeCell;
use core::fmt;
use core::future::Future;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
use std::sync::Arc;
use std::task::Wake;
use std::time::Duration;
use super::{Instant, clock};
use super::wheel::{TimerKey, Wheel};
use crate::rt::context;
use crate::rt::shard::{Shard, Shared};
use crate::sync::atomic_waker::AtomicWaker;
use crate::sync::internal::{AtomicBool, Ordering};
#[inline(always)]
pub fn sleep(duration: Duration) -> Sleep {
Sleep {
timer: Timer::after(duration),
}
}
pub fn sleep_until(deadline: impl Into<Instant>) -> Sleep {
Sleep {
timer: Timer::new(deadline.into()),
}
}
pub(super) fn far_future() -> Instant {
Instant::now() + Duration::from_secs(86_400 * 365 * 30)
}
#[must_use = "a sleep does nothing unless awaited"]
pub struct Sleep {
timer: Timer<Coarse>,
}
impl Sleep {
pub fn deadline(&self) -> Instant {
self.timer.deadline()
}
pub fn is_elapsed(&self) -> bool {
self.timer.is_elapsed()
}
pub fn reset(self: Pin<&mut Self>, deadline: impl Into<Instant>) {
self.get_mut().timer.reset(deadline.into());
}
}
impl Future for Sleep {
type Output = ();
#[inline(always)]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
self.get_mut().timer.poll(cx)
}
}
impl fmt::Debug for Sleep {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sleep")
.field("deadline", &self.deadline())
.field("elapsed", &self.is_elapsed())
.finish()
}
}
pub(crate) trait Grain {
const PRECISE: bool;
}
pub(crate) struct Coarse;
impl Grain for Coarse {
const PRECISE: bool = false;
}
pub(crate) struct Fine;
impl Grain for Fine {
const PRECISE: bool = true;
}
pub(super) struct Timer<G: Grain> {
deadline: Deadline,
state: ManuallyDrop<State>,
grain: PhantomData<G>,
}
#[derive(Clone, Copy)]
enum Deadline {
Nanos(u64),
Given(Instant),
}
enum State {
Idle,
Local { owner: Arc<Shared>, key: TimerKey },
Remote {
shard: Arc<Shared>,
cell: Arc<RemoteTimer>,
},
Done,
}
impl<G: Grain> Timer<G> {
pub(super) fn new(deadline: Instant) -> Self {
Self {
deadline: Deadline::Given(deadline),
state: ManuallyDrop::new(State::Idle),
grain: PhantomData,
}
}
#[inline(always)]
pub(super) fn after(duration: Duration) -> Self {
let span = duration
.as_secs()
.checked_mul(1_000_000_000)
.and_then(|whole| whole.checked_add(u64::from(duration.subsec_nanos())));
let now = clock::now_nanos();
match span.and_then(|span| now.checked_add(span)) {
Some(at) => Self {
deadline: Deadline::Nanos(at),
state: ManuallyDrop::new(State::Idle),
grain: PhantomData,
},
None => Self::new(far_future()),
}
}
pub(super) fn deadline(&self) -> Instant {
match self.deadline {
Deadline::Nanos(at) => Instant::from_std(clock::instant(at)),
Deadline::Given(at) => at,
}
}
#[inline]
fn nanos(&self) -> u64 {
match self.deadline {
Deadline::Nanos(at) => at,
Deadline::Given(at) => clock::nanos(at.into_std()),
}
}
pub(super) fn is_elapsed(&self) -> bool {
matches!(*self.state, State::Done) || clock::now_nanos() >= self.nanos()
}
pub(super) fn reset(&mut self, deadline: Instant) {
self.release();
self.deadline = Deadline::Given(deadline);
}
#[inline]
fn release(&mut self) {
match *self.state {
State::Idle => {}
State::Done => *self.state = State::Idle,
State::Local { .. } | State::Remote { .. } => self.release_armed(),
}
}
#[inline(never)]
fn release_armed(&mut self) {
match core::mem::replace(&mut *self.state, State::Idle) {
State::Local { owner, key } => {
let here = context::current(|current| match current {
Some(shard) if shard.is(&owner) => {
shard.wheel_of(G::PRECISE).borrow_mut().remove(key);
true
}
_ => false,
});
if !here {
owner.post_timer(TimerOp::Remove {
key,
precise: G::PRECISE,
});
}
}
State::Remote { shard, cell } => {
cell.cancelled.store(true, Ordering::SeqCst);
drop(cell.waker.take());
shard.post_timer(TimerOp::Cancel(cell));
}
State::Idle | State::Done => {}
}
}
#[inline(always)]
fn poll_local(&mut self, shard: &Shard, cx: &mut Context<'_>) -> Poll<()> {
if let State::Local { owner, key } = &*self.state
&& shard.is(owner)
{
let key = *key;
let mut wheel = shard.wheel_of(G::PRECISE).borrow_mut();
if wheel.is_fired(key) {
drop(wheel);
self.end_local();
return Poll::Ready(());
}
wheel.set_waker(key, cx.waker());
return Poll::Pending;
}
if let State::Remote { cell, .. } = &*self.state {
return poll_cell(cell, cx).map(|()| *self.state = State::Done);
}
self.release();
let at = self.nanos();
if clock::now_nanos() >= at {
*self.state = State::Done;
return Poll::Ready(());
}
let at = shard.time_of(G::PRECISE, at);
let mut wheel = shard.wheel_of(G::PRECISE).borrow_mut();
let key = wheel.insert(at, cx.waker());
if wheel.is_fired(key) {
drop(wheel);
*self.state = State::Done;
return Poll::Ready(());
}
drop(wheel);
*self.state = State::Local {
owner: Arc::clone(&shard.shared),
key,
};
Poll::Pending
}
fn poll_remote(&mut self, cx: &mut Context<'_>) -> Poll<()> {
if let State::Remote { cell, .. } = &*self.state {
return poll_cell(cell, cx).map(|()| *self.state = State::Done);
}
self.release();
let at = self.nanos();
if clock::now_nanos() >= at {
*self.state = State::Done;
return Poll::Ready(());
}
let cell = Arc::new(RemoteTimer {
fired: AtomicBool::new(false),
cancelled: AtomicBool::new(false),
orphaned: AtomicBool::new(false),
precise: G::PRECISE,
waker: AtomicWaker::new(),
key: UnsafeCell::new(None),
});
cell.waker.register(cx.waker());
let shard = crate::rt::runtime::service_shard();
shard.post_timer(TimerOp::Insert {
at,
cell: Arc::clone(&cell),
});
*self.state = State::Remote { shard, cell };
Poll::Pending
}
#[inline(always)]
fn end_local(&mut self) {
if let State::Local { owner, .. } = core::mem::replace(&mut *self.state, State::Done) {
drop(owner);
}
}
#[inline(always)]
pub(super) fn poll(&mut self, cx: &mut Context<'_>) -> Poll<()> {
if let State::Local { owner, key } = &*self.state
&& let Some(shard) = context::running_inside(context::local())
&& shard.is(owner)
&& shard.wheel_of(G::PRECISE).borrow().is_fired(*key)
{
self.end_local();
return Poll::Ready(());
}
self.poll_any(cx)
}
#[inline(never)]
fn poll_any(&mut self, cx: &mut Context<'_>) -> Poll<()> {
if let State::Done = *self.state {
return Poll::Ready(());
}
if let State::Remote { cell, .. } = &*self.state
&& cell.orphaned.load(Ordering::Acquire)
{
*self.state = State::Idle;
}
if let Some(shard) = context::running_inside(context::local()) {
return self.poll_local(shard, cx);
}
context::current(|current| match current {
Some(shard) => self.poll_local(shard, cx),
None => self.poll_remote(cx),
})
}
}
impl<G: Grain> Drop for Timer<G> {
fn drop(&mut self) {
if matches!(*self.state, State::Local { .. } | State::Remote { .. }) {
self.release_armed();
}
}
}
fn poll_cell(cell: &RemoteTimer, cx: &mut Context<'_>) -> Poll<()> {
if cell.fired.load(Ordering::Acquire) {
return Poll::Ready(());
}
cell.waker.register(cx.waker());
if cell.fired.load(Ordering::Acquire) {
Poll::Ready(())
} else {
Poll::Pending
}
}
pub(crate) struct RemoteTimer {
fired: AtomicBool,
cancelled: AtomicBool,
orphaned: AtomicBool,
precise: bool,
waker: AtomicWaker,
key: UnsafeCell<Option<TimerKey>>,
}
unsafe impl Send for RemoteTimer {}
unsafe impl Sync for RemoteTimer {}
impl RemoteTimer {
fn fire(&self) {
unsafe { *self.key.get() = None };
self.fired.store(true, Ordering::Release);
self.waker.wake();
}
pub(crate) fn orphan(&self) {
if self.fired.load(Ordering::Acquire) || self.cancelled.load(Ordering::SeqCst) {
return;
}
self.orphaned.store(true, Ordering::Release);
self.waker.wake();
}
}
struct Armed(Arc<RemoteTimer>);
impl Wake for Armed {
fn wake(self: Arc<Self>) {
self.0.fire();
}
fn wake_by_ref(self: &Arc<Self>) {
self.0.fire();
}
}
impl Drop for Armed {
fn drop(&mut self) {
self.0.orphan();
}
}
pub(crate) enum TimerOp {
Insert { at: u64, cell: Arc<RemoteTimer> },
Remove { key: TimerKey, precise: bool },
Cancel(Arc<RemoteTimer>),
}
impl TimerOp {
pub(crate) fn needs_wake(&self) -> bool {
matches!(self, Self::Insert { .. })
}
pub(crate) fn orphan(self) {
if let Self::Insert { cell, .. } = self {
cell.orphan();
}
}
pub(crate) fn apply(self, shard: &Shard, wheel: &mut Wheel) {
match self {
Self::Insert { at, cell } => {
if cell.cancelled.load(Ordering::SeqCst) {
return;
}
let waker = Waker::from(Arc::new(Armed(Arc::clone(&cell))));
let at = shard.time_of(cell.precise, at);
let fired = if cell.precise {
arm(&mut shard.wheel_of(true).borrow_mut(), at, &waker)
} else {
arm(wheel, at, &waker)
};
match fired {
None => {
cell.fired.store(true, Ordering::Release);
cell.waker.wake();
}
Some(key) => unsafe { *cell.key.get() = Some(key) },
}
}
Self::Remove {
key,
precise: false,
} => wheel.remove(key),
Self::Remove { key, precise: true } => shard.wheel_of(true).borrow_mut().remove(key),
Self::Cancel(cell) => {
if let Some(key) = unsafe { (*cell.key.get()).take() } {
if cell.precise {
shard.wheel_of(true).borrow_mut().remove(key);
} else {
wheel.remove(key);
}
}
}
}
}
}
fn arm(wheel: &mut Wheel, at: u64, waker: &Waker) -> Option<TimerKey> {
let key = wheel.insert(at, waker);
(!wheel.is_fired(key)).then_some(key)
}