1 //! Abstraction over blocking and unblocking the current thread.
2 //!
3 //! Provides an abstraction over blocking the current thread. This is similar to
4 //! the park / unpark constructs provided by `std` but made generic. This allows
5 //! embedding custom functionality to perform when the thread is blocked.
6 //!
7 //! A blocked `Park` instance is unblocked by calling `unpark` on its
8 //! `Unpark` handle.
9 //!
10 //! The `ParkThread` struct implements `Park` using `thread::park` to put the
11 //! thread to sleep. The Tokio reactor also implements park, but uses
12 //! `mio::Poll` to block the thread instead.
13 //!
14 //! The `Park` trait is composable. A timer implementation might decorate a
15 //! `Park` implementation by checking if any timeouts have elapsed after the
16 //! inner `Park` implementation unblocks.
17 //!
18 //! # Model
19 //!
20 //! Conceptually, each `Park` instance has an associated token, which is
21 //! initially not present:
22 //!
23 //! * The `park` method blocks the current thread unless or until the token is
24 //!   available, at which point it atomically consumes the token.
25 //! * The `unpark` method atomically makes the token available if it wasn't
26 //!   already.
27 //!
28 //! Some things to note:
29 //!
30 //! * If `unpark` is called before `park`, the next call to `park` will
31 //!   **not** block the thread.
32 //! * **Spurious** wakeups are permitted, i.e., the `park` method may unblock
33 //!   even if `unpark` was not called.
34 //! * `park_timeout` does the same as `park` but allows specifying a maximum
35 //!   time to block the thread for.
36 
37 cfg_resource_drivers! {
38     mod either;
39     pub(crate) use self::either::Either;
40 }
41 
42 mod thread;
43 pub(crate) use self::thread::ParkThread;
44 
45 cfg_block_on! {
46     pub(crate) use self::thread::{CachedParkThread, ParkError};
47 }
48 
49 use std::sync::Arc;
50 use std::time::Duration;
51 
52 /// Block the current thread.
53 pub(crate) trait Park {
54     /// Unpark handle type for the `Park` implementation.
55     type Unpark: Unpark;
56 
57     /// Error returned by `park`
58     type Error;
59 
60     /// Gets a new `Unpark` handle associated with this `Park` instance.
unpark(&self) -> Self::Unpark61     fn unpark(&self) -> Self::Unpark;
62 
63     /// Blocks the current thread unless or until the token is available.
64     ///
65     /// A call to `park` does not guarantee that the thread will remain blocked
66     /// forever, and callers should be prepared for this possibility. This
67     /// function may wakeup spuriously for any reason.
68     ///
69     /// # Panics
70     ///
71     /// This function **should** not panic, but ultimately, panics are left as
72     /// an implementation detail. Refer to the documentation for the specific
73     /// `Park` implementation
park(&mut self) -> Result<(), Self::Error>74     fn park(&mut self) -> Result<(), Self::Error>;
75 
76     /// Parks the current thread for at most `duration`.
77     ///
78     /// This function is the same as `park` but allows specifying a maximum time
79     /// to block the thread for.
80     ///
81     /// Same as `park`, there is no guarantee that the thread will remain
82     /// blocked for any amount of time. Spurious wakeups are permitted for any
83     /// reason.
84     ///
85     /// # Panics
86     ///
87     /// This function **should** not panic, but ultimately, panics are left as
88     /// an implementation detail. Refer to the documentation for the specific
89     /// `Park` implementation
park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error>90     fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error>;
91 }
92 
93 /// Unblock a thread blocked by the associated `Park` instance.
94 pub(crate) trait Unpark: Sync + Send + 'static {
95     /// Unblocks a thread that is blocked by the associated `Park` handle.
96     ///
97     /// Calling `unpark` atomically makes available the unpark token, if it is
98     /// not already available.
99     ///
100     /// # Panics
101     ///
102     /// This function **should** not panic, but ultimately, panics are left as
103     /// an implementation detail. Refer to the documentation for the specific
104     /// `Unpark` implementation
unpark(&self)105     fn unpark(&self);
106 }
107 
108 impl Unpark for Box<dyn Unpark> {
unpark(&self)109     fn unpark(&self) {
110         (**self).unpark()
111     }
112 }
113 
114 impl Unpark for Arc<dyn Unpark> {
unpark(&self)115     fn unpark(&self) {
116         (**self).unpark()
117     }
118 }
119