dope_core/driver/schedule/clock/timer/
mod.rs1use std::{mem, task, time};
2
3use o3::mem::{Lease, Return};
4
5use crate::{
6 driver,
7 driver::schedule::{
8 clock,
9 ready::{wake, wake::resident::slot},
10 },
11};
12
13pub mod heap;
14
15pub(in crate::driver) struct Tag;
16
17#[derive(Debug, Clone, Copy, Eq, PartialEq)]
19pub enum Exhausted {
20 Slots,
21}
22
23#[derive(Clone, Copy)]
25#[repr(transparent)]
26pub struct Timer<'d> {
27 pub(in crate::driver) driver: driver::Reference<'d>,
28}
29
30impl<'d> Timer<'d> {
31 pub(in crate::driver) const fn new(driver: driver::Reference<'d>) -> Self {
32 Self { driver }
33 }
34
35 pub fn earliest(self) -> Option<clock::Deadline<'d>> {
36 self.command(|cmd| cmd.peek().copied())
37 .map(|at| self.driver.clock().deadline_at(at))
38 }
39
40 pub fn try_alarm(self) -> Result<Alarm<'d>, Exhausted> {
41 let slot = self
42 .command(|mut cmd| {
43 let vacancy = cmd.vacancy()?;
44 Some(vacancy.lease(slot::Slot::default()))
45 })
46 .ok_or(Exhausted::Slots)?;
47 Ok(Alarm::new(Access(self), slot))
48 }
49}
50
51const _: () = {
52 assert!(mem::size_of::<Timer<'static>>() == mem::size_of::<usize>());
53 assert!(mem::align_of::<Timer<'static>>() == mem::align_of::<usize>());
54};
55
56#[derive(Clone, Copy)]
57#[repr(transparent)]
58pub(super) struct Access<'d>(Timer<'d>);
59
60type Command<'turn, 'd> = heap::Min<'turn, 'd, time::Instant, slot::Slot, Tag>;
62
63pub struct Alarm<'d> {
66 lease: Lease<Access<'d>>,
67}
68
69#[must_use = "an armed alarm must be polled or cancelled"]
71#[repr(transparent)]
72pub struct Armed<'a, 'd> {
73 alarm: &'a mut Alarm<'d>,
74}
75
76#[must_use]
78pub enum Poll<'a, 'd> {
79 Pending(Armed<'a, 'd>),
80 Ready,
81}
82
83impl<'d> Command<'_, 'd> {
84 fn set_target(&mut self, slot: &heap::Lease<'d, Tag>, wake: &wake::Waker<'d>) {
85 self.resident(slot).set(*wake.key());
86 }
87
88 fn arm_alarm(
89 &mut self,
90 slot: &heap::Lease<'d, Tag>,
91 due: time::Instant,
92 wake: &wake::Waker<'d>,
93 ) {
94 self.set_target(slot, wake);
95 self.set(slot, due);
96 }
97
98 fn clear_alarm(&mut self, slot: &heap::Lease<'d, Tag>) {
99 self.clear(slot);
100 self.resident(slot).clear();
101 }
102}
103
104impl<'d> Timer<'d> {
105 fn has_alarm(self, slot: &heap::Lease<'d, Tag>) -> bool {
106 self.command(|cmd| cmd.state(slot) != heap::State::Idle)
107 }
108
109 fn arm(self, slot: &heap::Lease<'d, Tag>, due: time::Instant, target: wake::Waker<'d>) {
110 self.command(|mut cmd| cmd.arm_alarm(slot, due, &target));
111 }
112
113 fn arm_and_poll(
114 self,
115 slot: &heap::Lease<'d, Tag>,
116 due: time::Instant,
117 now: time::Instant,
118 target: wake::Waker<'d>,
119 ) -> task::Poll<()> {
120 self.command(|mut cmd| {
121 if due <= now {
122 cmd.clear_alarm(slot);
123 task::Poll::Ready(())
124 } else {
125 cmd.arm_alarm(slot, due, &target);
126 task::Poll::Pending
127 }
128 })
129 }
130
131 fn poll(
132 self,
133 slot: &heap::Lease<'d, Tag>,
134 now: time::Instant,
135 target: wake::Waker<'d>,
136 ) -> task::Poll<()> {
137 self.command(|mut cmd| {
138 let state = cmd.state(slot);
139 let due =
140 state == heap::State::Fired || cmd.priority(slot).is_some_and(|due| *due <= now);
141 if due {
142 cmd.clear_alarm(slot);
143 task::Poll::Ready(())
144 } else if state == heap::State::Armed {
145 cmd.set_target(slot, &target);
146 task::Poll::Pending
147 } else {
148 task::Poll::Pending
149 }
150 })
151 }
152
153 fn clear(self, slot: &heap::Lease<'d, Tag>) {
154 self.command(|mut cmd| cmd.clear_alarm(slot));
155 }
156
157 pub(in crate::driver) fn expire_one(self, now: clock::Moment<'d>) -> Option<()> {
158 self.command(|mut cmd| {
159 let min = cmd.minimum()?;
160 if *min.priority() > now.into_raw() {
161 return None;
162 }
163 let fired = min.fire();
164 fired.resident().wake_once(self.driver);
165 Some(())
166 })
167 }
168
169 fn command<T>(self, op: impl for<'turn> FnOnce(Command<'turn, 'd>) -> T) -> T {
170 let shared = self.driver.shared;
171 unsafe { shared.context().timer().loan(op) }
174 }
175}
176
177impl<'d> Alarm<'d> {
178 const fn new(access: Access<'d>, slot: heap::Lease<'d, Tag>) -> Self {
179 Self {
180 lease: Lease::new(access, slot),
181 }
182 }
183
184 pub fn is_armed(&self) -> bool {
185 self.lease.sink().0.has_alarm(self.slot())
186 }
187
188 pub fn arm(&self, due: clock::Deadline<'d>, target: wake::Waker<'d>) {
189 self.lease.sink().0.arm(self.slot(), due.into_raw(), target);
190 }
191
192 pub fn arm_and_poll(
194 &self,
195 due: clock::Deadline<'d>,
196 now: clock::Moment<'d>,
197 target: wake::Waker<'d>,
198 ) -> task::Poll<()> {
199 self.lease
200 .sink()
201 .0
202 .arm_and_poll(self.slot(), due.into_raw(), now.into_raw(), target)
203 }
204
205 pub fn arm_owned<'a>(
207 &'a mut self,
208 due: clock::Deadline<'d>,
209 now: clock::Moment<'d>,
210 target: wake::Waker<'d>,
211 ) -> Poll<'a, 'd> {
212 if self.arm_and_poll(due, now, target).is_pending() {
213 Poll::Pending(Armed { alarm: self })
214 } else {
215 Poll::Ready
216 }
217 }
218
219 pub fn poll(&self, now: clock::Moment<'d>, target: wake::Waker<'d>) -> task::Poll<()> {
220 self.lease
221 .sink()
222 .0
223 .poll(self.slot(), now.into_raw(), target)
224 }
225
226 pub fn clear(&self) {
227 self.lease.sink().0.clear(self.slot());
228 }
229
230 fn slot(&self) -> &heap::Lease<'d, Tag> {
231 self.lease.item()
232 }
233}
234
235impl<'a, 'd> Armed<'a, 'd> {
236 pub fn poll(self, now: clock::Moment<'d>, target: wake::Waker<'d>) -> Poll<'a, 'd> {
238 if self.alarm.poll(now, target).is_pending() {
239 Poll::Pending(self)
240 } else {
241 Poll::Ready
242 }
243 }
244
245 pub fn cancel(self) {
247 self.alarm.clear();
248 }
249}
250
251impl<'d> Return for Access<'d> {
252 type Item = heap::Lease<'d, Tag>;
253
254 fn return_item(self, slot: Self::Item) {
255 self.0.command(|mut cmd| {
256 cmd.release(slot);
257 });
258 }
259}
260
261const _: () = {
262 assert!(mem::size_of::<heap::Lease<'static, Tag>>() == mem::size_of::<u32>());
263 assert!(mem::align_of::<heap::Lease<'static, Tag>>() == mem::align_of::<u32>());
264 assert!(mem::size_of::<Access<'static>>() == mem::size_of::<usize>());
265 assert!(mem::size_of::<Command<'static, 'static>>() == mem::size_of::<usize>());
266 assert!(mem::size_of::<Alarm<'static>>() == 2 * mem::size_of::<usize>());
267 assert!(mem::align_of::<Alarm<'static>>() == mem::align_of::<usize>());
268 assert!(mem::size_of::<Armed<'static, 'static>>() == mem::size_of::<usize>());
269 assert!(mem::size_of::<Option<Armed<'static, 'static>>>() == mem::size_of::<usize>());
270 assert!(mem::size_of::<Poll<'static, 'static>>() == mem::size_of::<usize>());
271};