1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::Mutex;
use std::task::Waker;
pub(super) struct TimerRegistration {
waker: Mutex<Option<Waker>>,
cancelled: AtomicBool,
/// `true` while a heap entry for this registration is resident in the
/// driver's timer heap. Written only while the driver's state mutex is
/// held (`schedule` sets it, entry removal clears it), which serializes
/// all accesses; the field is atomic only because the registration lives
/// in a shared `Arc`, so `Relaxed` ordering suffices.
in_heap: AtomicBool,
}
impl TimerRegistration {
pub(super) fn new(waker: Waker) -> Arc<Self> {
Arc::new(Self {
waker: Mutex::new(Some(waker)),
cancelled: AtomicBool::new(false),
in_heap: AtomicBool::new(false),
})
}
pub(super) fn replace_waker(&self, waker: &Waker) {
let mut stored = self.waker.lock().unwrap();
match stored.as_ref() {
Some(current) if current.will_wake(waker) => {}
_ => *stored = Some(waker.clone()),
}
}
/// Mark the registration cancelled. Returns `true` if this call performed
/// the cancellation (i.e. it was not already cancelled), so the driver
/// counts each dead heap entry exactly once.
pub(super) fn cancel(&self) -> bool {
!self.cancelled.swap(true, Ordering::AcqRel)
}
pub(super) fn is_cancelled(&self) -> bool {
self.cancelled.load(Ordering::Acquire)
}
/// See `in_heap` field docs: called only under the driver state mutex.
pub(super) fn mark_in_heap(&self) {
self.in_heap.store(true, Ordering::Relaxed);
}
/// See `in_heap` field docs: called only under the driver state mutex.
pub(super) fn clear_in_heap(&self) {
self.in_heap.store(false, Ordering::Relaxed);
}
/// See `in_heap` field docs: read only under the driver state mutex.
pub(super) fn is_in_heap(&self) -> bool {
self.in_heap.load(Ordering::Relaxed)
}
pub(super) fn wake(&self) {
if let Some(waker) = self.waker.lock().unwrap().take() {
waker.wake();
}
}
}