parking_lot_core/thread_parker/mod.rs
1use std::time::Instant;
2
3/// Trait for the platform thread parker implementation.
4///
5/// The unsafe methods form a protocol and implementations may rely on the
6/// parker remaining at a stable address once it has been used. In particular,
7/// the Unix implementation contains initialized pthread mutexes and condition
8/// variables which must not be moved. Calling an unsafe method after moving the
9/// parker from the address at which a previous unsafe method was called is
10/// undefined behavior.
11///
12/// The protocol also transfers ownership of the surrounding `ThreadData`
13/// between the parked thread and the parking lot. Writes performed by an
14/// unparker before `unpark_lock` must be visible after `park` returns or after
15/// `park_until` returns true.
16pub trait ThreadParkerT {
17 type UnparkHandle: UnparkHandleT;
18
19 const IS_CHEAP_TO_CONSTRUCT: bool;
20
21 fn new() -> Self;
22
23 /// Prepares the parker. This must be called while the local thread still
24 /// owns the `ThreadData`, before adding it to the queue.
25 unsafe fn prepare_park(&self);
26
27 /// Checks if the park timed out. This should be called while holding the
28 /// queue lock after `park_until` has returned false.
29 unsafe fn timed_out(&self) -> bool;
30
31 /// Parks the thread until it is unparked. This must be called after the
32 /// `ThreadData` has been added to the queue and the queue has been unlocked.
33 /// Returning transfers ownership of the `ThreadData` back to the local
34 /// thread and acquires the writes that preceded `unpark_lock`.
35 unsafe fn park(&self);
36
37 /// Parks the thread until it is unparked or the timeout is reached. This
38 /// must be called after the `ThreadData` has been added to the queue and the
39 /// queue has been unlocked. Returning true transfers ownership of the
40 /// `ThreadData` back to the local thread and acquires the writes that
41 /// preceded `unpark_lock`. Returning false does not transfer ownership: the
42 /// caller must resolve the timeout while holding the queue lock.
43 ///
44 /// The timeout is the earliest point at which this method may return false,
45 /// but scheduling and platform-specific behavior may delay the return.
46 unsafe fn park_until(&self, timeout: Instant) -> bool;
47
48 /// Prepares to unpark a thread after removing its `ThreadData` from its
49 /// queue and writing its result fields.
50 ///
51 /// The caller must exclusively own the target `ThreadData`, which must
52 /// remain valid and parked until this method is called.
53 ///
54 /// The returned handle must be consumed by a call to
55 /// [`UnparkHandleT::unpark`].
56 ///
57 /// After this returns, the caller must not access the target `ThreadData`:
58 /// the target may immediately observe the unpark and destroy it, even while
59 /// the queue remains locked. The returned handle must nevertheless remain
60 /// safe to pass to `unpark`. Implementations may either keep the parker
61 /// alive or make such a late `unpark` harmless.
62 unsafe fn unpark_lock(&self) -> Self::UnparkHandle;
63}
64
65/// Handle for a thread whose unpark has been committed. Every handle returned
66/// by [`ThreadParkerT::unpark_lock`] must be consumed by a call to
67/// [`UnparkHandleT::unpark`]. Any potentially expensive wake operation is
68/// delayed until then.
69pub trait UnparkHandleT {
70 /// Wakes up the parked thread. This should be called after the queue lock is
71 /// released to avoid blocking the queue for too long.
72 ///
73 /// This method is unsafe for the same reason as the unsafe methods in
74 /// `ThreadParkerT`.
75 unsafe fn unpark(self);
76}
77
78cfg_select! {
79 any(target_os = "linux", target_os = "android") => {
80 #[path = "linux.rs"]
81 mod imp;
82 }
83 unix => {
84 #[path = "unix.rs"]
85 mod imp;
86 }
87 windows => {
88 #[path = "windows/mod.rs"]
89 mod imp;
90 }
91 target_os = "redox" => {
92 #[path = "redox.rs"]
93 mod imp;
94 }
95 all(target_env = "sgx", target_vendor = "fortanix") => {
96 #[path = "sgx.rs"]
97 mod imp;
98 }
99 all(
100 feature = "nightly",
101 target_family = "wasm",
102 target_feature = "atomics"
103 ) => {
104 #[path = "wasm_atomic.rs"]
105 mod imp;
106 }
107 target_os = "wasi" => {
108 // WASI provides pthreads with or without the atomics extension. This
109 // also works on stable, where target_feature = "atomics" is not set.
110 // Keep the intrinsic backend above preferred when it is available.
111 #[path = "unix.rs"]
112 mod imp;
113 }
114 target_family = "wasm" => {
115 #[path = "wasm.rs"]
116 mod imp;
117 }
118 _ => {
119 #[path = "generic.rs"]
120 mod imp;
121 }
122}
123
124pub use self::imp::{ThreadParker, thread_yield};