Skip to main content

cartel_core/
deadline.rs

1use std::{cell, mem, pin, task};
2
3use dope::core::driver::schedule::clock::timer;
4use dope_fiber::context;
5use o3::base::time::Positive;
6
7/// The bounded operation phase in which an absolute request deadline elapsed.
8#[derive(Clone, Copy, Eq, PartialEq, Debug)]
9pub enum RequestPhase {
10    Admission,
11    Response,
12    Settlement,
13    Lease,
14    Contention,
15}
16
17#[derive(Clone, Copy, Eq, PartialEq, Debug)]
18pub struct Elapsed {
19    phase: RequestPhase,
20}
21
22impl Elapsed {
23    pub const fn new(phase: RequestPhase) -> Self {
24        Self { phase }
25    }
26
27    pub const fn phase(self) -> RequestPhase {
28        self.phase
29    }
30}
31
32/// Copyable authority to create deadlines tied to one exact driver lifetime.
33#[derive(Clone, Copy)]
34pub struct Source<'d> {
35    timer: timer::Timer<'d>,
36    window: Positive,
37}
38
39impl<'d> Source<'d> {
40    pub const fn new(timer: timer::Timer<'d>, window: Positive) -> Self {
41        Self { timer, window }
42    }
43
44    pub fn guard(self) -> Result<Guard<'d>, timer::Exhausted> {
45        Ok(Guard {
46            alarm: self.timer.try_alarm()?,
47            window: self.window,
48            state: cell::Cell::new(GuardState::Fresh),
49        })
50    }
51
52    pub const fn into_parts(self) -> (timer::Timer<'d>, Positive) {
53        (self.timer, self.window)
54    }
55}
56
57/// One first-poll-anchored absolute deadline. Phase changes never rearm it.
58pub struct Guard<'d> {
59    alarm: timer::Alarm<'d>,
60    window: Positive,
61    state: cell::Cell<GuardState>,
62}
63
64#[derive(Clone, Copy)]
65#[repr(u8)]
66enum GuardState {
67    Fresh,
68    Armed,
69    Elapsed,
70    Complete,
71}
72
73impl<'d> Guard<'d> {
74    pub fn poll_expired(
75        self: pin::Pin<&mut Self>,
76        mut ctx: pin::Pin<&mut context::Context<'_, 'd>>,
77        phase: RequestPhase,
78    ) -> task::Poll<Elapsed> {
79        let this = self.get_mut();
80        match this.state.get() {
81            GuardState::Elapsed => return task::Poll::Ready(Elapsed::new(phase)),
82            GuardState::Complete => return task::Poll::Pending,
83            GuardState::Fresh => {
84                let wake = ctx.as_ref().completion();
85                let now = ctx.as_mut().driver().driver_ref().clock().now();
86                let due = now.clamp_add(this.window);
87                this.state.set(GuardState::Armed);
88                this.alarm.arm(due, wake);
89                return task::Poll::Pending;
90            }
91            GuardState::Armed => {}
92        }
93        let wake = ctx.as_ref().completion();
94        let now = ctx.as_mut().driver().driver_ref().clock().now();
95        if this.alarm.poll(now, wake).is_ready() {
96            this.state.set(GuardState::Elapsed);
97            task::Poll::Ready(Elapsed::new(phase))
98        } else {
99            task::Poll::Pending
100        }
101    }
102
103    pub fn complete(&self) {
104        self.alarm.clear();
105        self.state.set(GuardState::Complete);
106    }
107}
108
109const _: () = {
110    assert!(mem::size_of::<GuardState>() == 1);
111    assert!(mem::size_of::<cell::Cell<GuardState>>() == mem::size_of::<GuardState>());
112    assert!(mem::align_of::<cell::Cell<GuardState>>() == mem::align_of::<GuardState>());
113};