wasm_timer/timer/global/
desktop.rs

1use std::future::Future;
2use std::io;
3use std::mem::{self, ManuallyDrop};
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::Arc;
6use std::task::{Context, RawWaker, RawWakerVTable, Waker};
7use std::thread;
8use std::thread::Thread;
9use std::time::Instant;
10
11use pin_utils::pin_mut;
12
13use crate::{Timer, TimerHandle};
14
15pub struct HelperThread {
16    thread: Option<thread::JoinHandle<()>>,
17    timer: TimerHandle,
18    done: Arc<AtomicBool>,
19}
20
21impl HelperThread {
22    pub fn new() -> io::Result<HelperThread> {
23        let timer = Timer::new();
24        let timer_handle = timer.handle();
25        let done = Arc::new(AtomicBool::new(false));
26        let done2 = done.clone();
27        let thread = thread::Builder::new().spawn(move || run(timer, done2))?;
28
29        Ok(HelperThread {
30            thread: Some(thread),
31            done,
32            timer: timer_handle,
33        })
34    }
35
36    pub fn handle(&self) -> TimerHandle {
37        self.timer.clone()
38    }
39
40    pub fn forget(mut self) {
41        self.thread.take();
42    }
43}
44
45impl Drop for HelperThread {
46    fn drop(&mut self) {
47        let thread = match self.thread.take() {
48            Some(thread) => thread,
49            None => return,
50        };
51        self.done.store(true, Ordering::SeqCst);
52        thread.thread().unpark();
53        drop(thread.join());
54    }
55}
56
57fn run(timer: Timer, done: Arc<AtomicBool>) {
58    let mut waker = current_thread_waker();
59    let mut cx = Context::from_waker(&mut waker);
60
61    pin_mut!(timer);
62    while !done.load(Ordering::SeqCst) {
63        drop(timer.as_mut().poll(&mut cx));
64
65        timer.advance();
66        match timer.next_event() {
67            // Ok, block for the specified time
68            Some(when) => {
69                let now = Instant::now();
70                if now < when {
71                    thread::park_timeout(when - now)
72                } else {
73                    // .. continue...
74                }
75            }
76
77            // Just wait for one of our futures to wake up
78            None => thread::park(),
79        }
80    }
81}
82
83static VTABLE: RawWakerVTable = RawWakerVTable::new(raw_clone, raw_wake, raw_wake_by_ref, raw_drop);
84
85fn raw_clone(ptr: *const ()) -> RawWaker {
86    let me = ManuallyDrop::new(unsafe { Arc::from_raw(ptr as *const Thread) });
87    mem::forget(me.clone());
88    RawWaker::new(ptr, &VTABLE)
89}
90
91fn raw_wake(ptr: *const ()) {
92    unsafe { Arc::from_raw(ptr as *const Thread) }.unpark()
93}
94
95fn raw_wake_by_ref(ptr: *const ()) {
96    ManuallyDrop::new(unsafe { Arc::from_raw(ptr as *const Thread) }).unpark()
97}
98
99fn raw_drop(ptr: *const ()) {
100    unsafe { Arc::from_raw(ptr as *const Thread) };
101}
102
103fn current_thread_waker() -> Waker {
104    let thread = Arc::new(thread::current());
105    unsafe { Waker::from_raw(raw_clone(Arc::into_raw(thread) as *const ())) }
106}