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