virtual_mio/
waker.rs

1#![allow(dead_code, unused)]
2use std::{
3    sync::{Arc, Condvar, Mutex},
4    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
5};
6
7use futures::Future;
8
9pub struct InlineWaker {
10    lock: Mutex<()>,
11    condvar: Condvar,
12}
13impl InlineWaker {
14    pub fn new() -> Arc<Self> {
15        Arc::new(Self {
16            lock: Mutex::new(()),
17            condvar: Condvar::new(),
18        })
19    }
20
21    fn wake_now(&self) {
22        // Note: This guard should be there to prevent race conditions however in the
23        // browser it causes a lock up - some strange browser issue. What I suspect
24        // is that the Condvar::wait call is not releasing the mutex lock
25        #[cfg(not(feature = "js"))]
26        let _guard = self.lock.lock().unwrap();
27
28        self.condvar.notify_all();
29    }
30
31    pub fn as_waker(self: &Arc<Self>) -> Waker {
32        let s: *const Self = Arc::into_raw(Arc::clone(self));
33        let raw_waker = RawWaker::new(s as *const (), &VTABLE);
34        unsafe { Waker::from_raw(raw_waker) }
35    }
36
37    #[cfg(not(feature = "js"))]
38    pub fn block_on<'a, A>(task: impl Future<Output = A> + 'a) -> A {
39        futures::executor::block_on(task)
40    }
41
42    #[cfg(feature = "js")]
43    pub fn block_on<'a, A>(task: impl Future<Output = A> + 'a) -> A {
44        // Create the waker
45        let inline_waker = Self::new();
46        let waker = inline_waker.as_waker();
47        let mut cx = Context::from_waker(&waker);
48
49        // We loop waiting for the waker to be woken, then we poll again
50        let mut task = Box::pin(task);
51        loop {
52            let lock = inline_waker.lock.lock().unwrap();
53            match task.as_mut().poll(&mut cx) {
54                Poll::Pending => {
55                    inline_waker.condvar.wait(lock).ok();
56                }
57                Poll::Ready(ret) => {
58                    return ret;
59                }
60            }
61        }
62    }
63}
64
65fn inline_waker_wake(s: &InlineWaker) {
66    let waker_arc = unsafe { Arc::from_raw(s) };
67    waker_arc.wake_now();
68}
69
70fn inline_waker_clone(s: &InlineWaker) -> RawWaker {
71    let arc = unsafe { Arc::from_raw(s) };
72    std::mem::forget(arc.clone());
73    RawWaker::new(Arc::into_raw(arc) as *const (), &VTABLE)
74}
75
76const VTABLE: RawWakerVTable = unsafe {
77    RawWakerVTable::new(
78        |s| inline_waker_clone(&*(s as *const InlineWaker)), // clone
79        |s| inline_waker_wake(&*(s as *const InlineWaker)),  // wake
80        |s| (*(s as *const InlineWaker)).wake_now(), // wake by ref (don't decrease refcount)
81        |s| drop(Arc::from_raw(s as *const InlineWaker)), // decrease refcount
82    )
83};