      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
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116

    //! Abstraction over blocking and unblocking the current thread.
    //!
    //! Provides an abstraction over blocking the current thread. This is similar to
    //! the park / unpark constructs provided by `std` but made generic. This allows
    //! embedding custom functionality to perform when the thread is blocked.
    //!
    //! A blocked `Park` instance is unblocked by calling `unpark` on its
    //! `Unpark` handle.
    //!
    //! The `ParkThread` struct implements `Park` using `thread::park` to put the
    //! thread to sleep. The Tokio reactor also implements park, but uses
    //! `mio::Poll` to block the thread instead.
    //!
    //! The `Park` trait is composable. A timer implementation might decorate a
    //! `Park` implementation by checking if any timeouts have elapsed after the
    //! inner `Park` implementation unblocks.
    //!
    //! # Model
    //!
    //! Conceptually, each `Park` instance has an associated token, which is
    //! initially not present:
    //!
    //! * The `park` method blocks the current thread unless or until the token is
    //!   available, at which point it atomically consumes the token.
    //! * The `unpark` method atomically makes the token available if it wasn't
    //!   already.
    //!
    //! Some things to note:
    //!
    //! * If `unpark` is called before `park`, the next call to `park` will
    //!   **not** block the thread.
    //! * **Spurious** wakeups are permitted, i.e., the `park` method may unblock
    //!   even if `unpark` was not called.
    //! * `park_timeout` does the same as `park` but allows specifying a maximum
    //!   time to block the thread for.

    cfg_rt! {
        pub(crate) mod either;
    }

    #[cfg(any(feature = "rt", feature = "sync"))]
    pub(crate) mod thread;

    use std::sync::Arc;
    use std::time::Duration;

    /// Block the current thread.
    pub(crate) trait Park {
        /// Unpark handle type for the `Park` implementation.
        type Unpark: Unpark;

        /// Error returned by `park`
        type Error;

        /// Gets a new `Unpark` handle associated with this `Park` instance.
        fn unpark(&self) -> Self::Unpark;

        /// Blocks the current thread unless or until the token is available.
        ///
        /// A call to `park` does not guarantee that the thread will remain blocked
        /// forever, and callers should be prepared for this possibility. This
        /// function may wakeup spuriously for any reason.
        ///
        /// # Panics
        ///
        /// This function **should** not panic, but ultimately, panics are left as
        /// an implementation detail. Refer to the documentation for the specific
        /// `Park` implementation
        fn park(&mut self) -> Result<(), Self::Error>;

        /// Parks the current thread for at most `duration`.
        ///
        /// This function is the same as `park` but allows specifying a maximum time
        /// to block the thread for.
        ///
        /// Same as `park`, there is no guarantee that the thread will remain
        /// blocked for any amount of time. Spurious wakeups are permitted for any
        /// reason.
        ///
        /// # Panics
        ///
        /// This function **should** not panic, but ultimately, panics are left as
        /// an implementation detail. Refer to the documentation for the specific
        /// `Park` implementation
        fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error>;

        /// Release all resources holded by the parker for proper leak-free shutdown
        fn shutdown(&mut self);
    }

    /// Unblock a thread blocked by the associated `Park` instance.
    pub(crate) trait Unpark: Sync + Send + 'static {
        /// Unblocks a thread that is blocked by the associated `Park` handle.
        ///
        /// Calling `unpark` atomically makes available the unpark token, if it is
        /// not already available.
        ///
        /// # Panics
        ///
        /// This function **should** not panic, but ultimately, panics are left as
        /// an implementation detail. Refer to the documentation for the specific
        /// `Unpark` implementation
        fn unpark(&self);
    }

    impl Unpark for Box<dyn Unpark> {
        fn unpark(&self) {
            (**self).unpark()
        }
    }

    impl Unpark for Arc<dyn Unpark> {
        fn unpark(&self) {
            (**self).unpark()
        }
    }