     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
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79

    //! Generic support for building blocking abstractions.

    use crate::mem;
    use crate::sync::atomic::{AtomicBool, Ordering};
    use crate::sync::Arc;
    use crate::thread::{self, Thread};
    use crate::time::Instant;

    struct Inner {
        thread: Thread,
        woken: AtomicBool,
    }

    unsafe impl Send for Inner {}
    unsafe impl Sync for Inner {}

    #[derive(Clone)]
    pub struct SignalToken {
        inner: Arc<Inner>,
    }

    pub struct WaitToken {
        inner: Arc<Inner>,
    }

    impl !Send for WaitToken {}

    impl !Sync for WaitToken {}

    pub fn tokens() -> (WaitToken, SignalToken) {
        let inner = Arc::new(Inner { thread: thread::current(), woken: AtomicBool::new(false) });
        let wait_token = WaitToken { inner: inner.clone() };
        let signal_token = SignalToken { inner };
        (wait_token, signal_token)
    }

    impl SignalToken {
        pub fn signal(&self) -> bool {
            let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
            if wake {
                self.inner.thread.unpark();
            }
            wake
        }

        /// Converts to an unsafe usize value. Useful for storing in a pipe's state
        /// flag.
        #[inline]
        pub unsafe fn cast_to_usize(self) -> usize {
            mem::transmute(self.inner)
        }

        /// Converts from an unsafe usize value. Useful for retrieving a pipe's state
        /// flag.
        #[inline]
        pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken {
            SignalToken { inner: mem::transmute(signal_ptr) }
        }
    }

    impl WaitToken {
        pub fn wait(self) {
            while !self.inner.woken.load(Ordering::SeqCst) {
                thread::park()
            }
        }

        /// Returns `true` if we wake up normally.
        pub fn wait_max_until(self, end: Instant) -> bool {
            while !self.inner.woken.load(Ordering::SeqCst) {
                let now = Instant::now();
                if now >= end {
                    return false;
                }
                thread::park_timeout(end - now)
            }
            true
        }
    }