]>
Commit | Line | Data |
---|---|---|
e1599b0c XL |
1 | use cfg_if::cfg_if; |
2 | use std::time::Instant; | |
3 | ||
4 | /// Trait for the platform thread parker implementation. | |
5 | /// | |
6 | /// All unsafe methods are unsafe because the Unix thread parker is based on | |
7 | /// pthread mutexes and condvars. Those primitives must not be moved and used | |
8 | /// from any other memory address than the one they were located at when they | |
9 | /// were initialized. As such, it's UB to call any unsafe method on | |
10 | /// `ThreadParkerT` if the implementing instance has moved since the last | |
11 | /// call to any of the unsafe methods. | |
12 | pub trait ThreadParkerT { | |
13 | type UnparkHandle: UnparkHandleT; | |
14 | ||
15 | const IS_CHEAP_TO_CONSTRUCT: bool; | |
16 | ||
17 | fn new() -> Self; | |
18 | ||
19 | /// Prepares the parker. This should be called before adding it to the queue. | |
20 | unsafe fn prepare_park(&self); | |
21 | ||
22 | /// Checks if the park timed out. This should be called while holding the | |
23 | /// queue lock after park_until has returned false. | |
24 | unsafe fn timed_out(&self) -> bool; | |
25 | ||
26 | /// Parks the thread until it is unparked. This should be called after it has | |
27 | /// been added to the queue, after unlocking the queue. | |
28 | unsafe fn park(&self); | |
29 | ||
30 | /// Parks the thread until it is unparked or the timeout is reached. This | |
31 | /// should be called after it has been added to the queue, after unlocking | |
32 | /// the queue. Returns true if we were unparked and false if we timed out. | |
33 | unsafe fn park_until(&self, timeout: Instant) -> bool; | |
34 | ||
35 | /// Locks the parker to prevent the target thread from exiting. This is | |
36 | /// necessary to ensure that thread-local ThreadData objects remain valid. | |
37 | /// This should be called while holding the queue lock. | |
38 | unsafe fn unpark_lock(&self) -> Self::UnparkHandle; | |
39 | } | |
40 | ||
41 | /// Handle for a thread that is about to be unparked. We need to mark the thread | |
42 | /// as unparked while holding the queue lock, but we delay the actual unparking | |
43 | /// until after the queue lock is released. | |
44 | pub trait UnparkHandleT { | |
45 | /// Wakes up the parked thread. This should be called after the queue lock is | |
46 | /// released to avoid blocking the queue for too long. | |
47 | /// | |
48 | /// This method is unsafe for the same reason as the unsafe methods in | |
49 | /// `ThreadParkerT`. | |
50 | #[inline] | |
51 | unsafe fn unpark(self); | |
52 | } | |
53 | ||
54 | cfg_if! { | |
55 | if #[cfg(all(has_sized_atomics, any(target_os = "linux", target_os = "android")))] { | |
56 | #[path = "linux.rs"] | |
57 | mod imp; | |
58 | } else if #[cfg(unix)] { | |
59 | #[path = "unix.rs"] | |
60 | mod imp; | |
61 | } else if #[cfg(windows)] { | |
62 | #[path = "windows/mod.rs"] | |
63 | mod imp; | |
64 | } else if #[cfg(all(has_sized_atomics, target_os = "redox"))] { | |
65 | #[path = "redox.rs"] | |
66 | mod imp; | |
67 | } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] { | |
68 | #[path = "sgx.rs"] | |
69 | mod imp; | |
70 | } else if #[cfg(all( | |
71 | feature = "nightly", | |
72 | target_arch = "wasm32", | |
73 | target_feature = "atomics" | |
74 | ))] { | |
75 | #[path = "wasm_atomic.rs"] | |
76 | mod imp; | |
77 | } else if #[cfg(target_arch = "wasm32")] { | |
78 | #[path = "wasm.rs"] | |
79 | mod imp; | |
80 | } else if #[cfg(all(feature = "nightly", target_os = "cloudabi"))] { | |
81 | #[path = "cloudabi.rs"] | |
82 | mod imp; | |
83 | } else { | |
84 | #[path = "generic.rs"] | |
85 | mod imp; | |
86 | } | |
87 | } | |
88 | ||
89 | pub use self::imp::{thread_yield, ThreadParker, UnparkHandle}; |