| // Copyright (c) 2017 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::*; |
| use panicking; |
| use sys_common::thread_info; |
| use sync::{SgxMutex, SgxCondvar}; |
| use alloc::arc::Arc; |
| |
| #[macro_use] mod local; |
| pub use self::local::{LocalKey, LocalKeyState, 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() |
| } |
| |
| /// 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. |
| /// |
| /// * 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(); |
| let mut guard = thread.inner.lock.lock().unwrap(); |
| while !*guard { |
| guard = thread.inner.cvar.wait(guard).unwrap(); |
| } |
| *guard = false; |
| } |
| |
| /// 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, |
| lock: SgxMutex<bool>, |
| 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 fn new() -> Self { |
| SgxThread { |
| inner: Arc::new(Inner { |
| id: SgxThreadId::new(), |
| lock: SgxMutex::new(false), |
| 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. |
| pub fn unpark(&self) { |
| let mut guard = self.inner.lock.lock().unwrap(); |
| if !*guard { |
| *guard = true; |
| let _ = self.inner.cvar.signal(); |
| } |
| } |
| } |