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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
// Copyright (C) 2017-2018 Baidu, Inc. All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the // distribution. // * Neither the name of Baidu, Inc., nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //! Native threads. use sgx_types::{sgx_thread_t, sgx_thread_self}; use panicking; use sys_common::thread_info; use sync::{SgxMutex, SgxCondvar}; use core::sync::atomic::AtomicUsize; use core::sync::atomic::Ordering::SeqCst; use alloc::sync::Arc; #[macro_use] mod local; pub use self::local::{LocalKey, LocalKeyInner, AccessError}; /// /// The rsgx_thread_self function returns the unique thread identification. /// /// # Description /// /// The function is a simple wrap of get_thread_data() provided in the tRTS, /// which provides a trusted thread unique identifier. /// /// # Requirements /// /// Library: libsgx_tstdc.a /// /// # Return value /// /// The return value cannot be NULL and is always valid as long as it is invoked by a thread inside the enclave. /// pub fn rsgx_thread_self() -> sgx_thread_t { unsafe { sgx_thread_self() } } /// /// The rsgx_thread_equal function compares two thread identifiers. /// /// # Description /// /// The function compares two thread identifiers provided by sgx_thread_ /// self to determine if the IDs refer to the same trusted thread. /// /// # Requirements /// /// Library: libsgx_tstdc.a /// /// # Return value /// /// **true** /// /// The two thread IDs are equal. /// pub fn rsgx_thread_equal(a: sgx_thread_t, b: sgx_thread_t) -> bool { a == b } /// Gets a handle to the thread that invokes it. pub fn current() -> SgxThread { thread_info::current_thread().expect("use of thread::current() need TCS policy is Bound") } /// Determines whether the current thread is unwinding because of panic. /// /// A common use of this feature is to poison shared resources when writing /// unsafe code, by checking `panicking` when the `drop` is called. /// /// This is usually not needed when writing safe code, as [`SgxMutex`es][SgxMutex] /// already poison themselves when a thread panics while holding the lock. /// /// This can also be used in multithreaded applications, in order to send a /// message to other threads warning that a thread has panicked (e.g. for /// monitoring purposes). pub fn panicking() -> bool { panicking::panicking() } // constants for park/unpark const EMPTY: usize = 0; const PARKED: usize = 1; const NOTIFIED: usize = 2; /// Blocks unless or until the current thread's token is made available. /// /// A call to `park` does not guarantee that the thread will remain parked /// forever, and callers should be prepared for this possibility. /// /// # park and unpark /// /// Every thread is equipped with some basic low-level blocking support, via the /// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] /// method. [`park`] blocks the current thread, which can then be resumed from /// another thread by calling the [`unpark`] method on the blocked thread's /// handle. /// /// Conceptually, each [`Thread`] handle has an associated token, which is /// initially not present: /// /// * The [`thread::park`][`park`] function blocks the current thread unless or /// until the token is available for its thread handle, at which point it /// atomically consumes the token. It may also return *spuriously*, without /// consuming the token. [`thread::park_timeout`] does the same, but allows /// specifying a maximum time to block the thread for. /// /// * The [`unpark`] method on a [`Thread`] atomically makes the token available /// if it wasn't already. /// /// In other words, each [`Thread`] acts a bit like a spinlock that can be /// locked and unlocked using `park` and `unpark`. /// /// The API is typically used by acquiring a handle to the current thread, /// placing that handle in a shared data structure so that other threads can /// find it, and then `park`ing. When some desired condition is met, another /// thread calls [`unpark`] on the handle. /// /// The motivation for this design is twofold: /// /// * It avoids the need to allocate mutexes and condvars when building new /// synchronization primitives; the threads already provide basic /// blocking/signaling. /// /// * It can be implemented very efficiently on many platforms. /// pub fn park() { let thread = current(); // If we were previously notified then we consume this notification and // return quickly. if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { return } // Otherwise we need to coordinate going to sleep let mut m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} Err(NOTIFIED) => return, // notified after we locked Err(_) => panic!("inconsistent park state"), } loop { m = thread.inner.cvar.wait(m).unwrap(); match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { Ok(_) => return, // got a notification Err(_) => {} // spurious wakeup, go back to sleep } } } /// A unique identifier for a running thread. /// /// A `ThreadId` is an opaque object that has a unique value for each thread /// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's /// system-designated identifier. #[derive(Eq, PartialEq, Copy, Clone)] pub struct SgxThreadId { id: sgx_thread_t, } impl SgxThreadId { /// Generate a new unique thread ID. pub fn new() -> Self { SgxThreadId { id: rsgx_thread_self(), } } } /// The internal representation of a `Thread` handle struct Inner { id: SgxThreadId, // state for thread park/unpark state: AtomicUsize, lock: SgxMutex<()>, cvar: SgxCondvar, } /// A handle to a thread. /// #[derive(Clone)] pub struct SgxThread { inner: Arc<Inner>, } impl SgxThread { /// Used only internally to construct a thread object without spawning pub(crate) fn new() -> Self { SgxThread { inner: Arc::new(Inner { id: SgxThreadId::new(), state: AtomicUsize::new(EMPTY), lock: SgxMutex::new(()), cvar: SgxCondvar::new(), }) } } /// Gets the thread's unique identifier. pub fn id(&self) -> SgxThreadId { self.inner.id } /// Atomically makes the handle's token available if it is not already. /// /// Every thread is equipped with some basic low-level blocking support, via /// the [`park`][park] function and the `unpark()` method. These can be /// used as a more CPU-efficient implementation of a spinlock. /// pub fn unpark(&self) { loop { match self.inner.state.compare_exchange(EMPTY, NOTIFIED, SeqCst, SeqCst) { Ok(_) => return, // no one was waiting Err(NOTIFIED) => return, // already unparked Err(PARKED) => {} // gotta go wake someone up _ => panic!("inconsistent state in unpark"), } // Coordinate wakeup through the mutex and a condvar notification let _lock = self.inner.lock.lock().unwrap(); match self.inner.state.compare_exchange(PARKED, NOTIFIED, SeqCst, SeqCst) { Ok(_) => return self.inner.cvar.signal(), Err(NOTIFIED) => return, // a different thread unparked Err(EMPTY) => {} // parked thread went away, try again _ => panic!("inconsistent state in unpark"), } } } }