wasm_timer/timer/global/
desktop.rs1use 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 Some(when) => {
69 let now = Instant::now();
70 if now < when {
71 thread::park_timeout(when - now)
72 } else {
73 }
75 }
76
77 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}