-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add `condvar.rs` implementation which more or less copies from [rust source](https://github.com/rust-lang/rust.git) at [606c3907](rust-lang/rust@606c390)
- Loading branch information
1 parent
454435e
commit 1863475
Showing
4 changed files
with
231 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
// Copyright (c) The Rust Foundation | ||
// Copyright (c) 2023 The MobileCoin Foundation | ||
|
||
//! condvar.rs implementation more or less copied from | ||
//! [rust source](https://github.com/rust-lang/rust.git) at | ||
//! [606c3907](https://github.com/rust-lang/rust/commit/606c3907251397a42e23d3e60de31be9d32525d5) | ||
//! | ||
//! Differences: | ||
//! - The imports were changed to work with the `mc-sgx` crates. | ||
//! - The stable attributes have been removed | ||
//! - The unstable attributes have been removed | ||
//! - Items that are crate only were converted from `pub` to `pub(crate)` | ||
//! - Removed examples that were not possible in an SGX enclave have been omitted | ||
//! - Ran `cargo fmt` | ||
//! - Removed unnecessary unsafe blocks | ||
//! - Removed timeout since there isn't a secure timer in SGX enclaves | ||
use crate::sys::locks as sys; | ||
use crate::{mutex, LockResult, MutexGuard, PoisonError}; | ||
use core::fmt; | ||
|
||
/// A Condition Variable | ||
/// | ||
/// Condition variables represent the ability to block a thread such that it | ||
/// consumes no CPU time while waiting for an event to occur. Condition | ||
/// variables are typically associated with a boolean predicate (a condition) | ||
/// and a mutex. The predicate is always verified inside of the mutex before | ||
/// determining that a thread must block. | ||
/// | ||
/// Functions in this module will block the current **thread** of execution. | ||
/// Note that any attempt to use multiple mutexes on the same condition | ||
/// variable may result in a runtime panic. | ||
pub struct Condvar { | ||
inner: sys::Condvar, | ||
} | ||
|
||
impl Condvar { | ||
/// Creates a new condition variable which is ready to be waited on and | ||
/// notified. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use mc_sgx_sync::Condvar; | ||
/// | ||
/// let condvar = Condvar::new(); | ||
/// ``` | ||
#[must_use] | ||
pub const fn new() -> Condvar { | ||
Condvar { | ||
inner: sys::Condvar::new(), | ||
} | ||
} | ||
|
||
/// Blocks the current thread until this condition variable receives a | ||
/// notification. | ||
/// | ||
/// This function will atomically unlock the mutex specified (represented by | ||
/// `guard`) and block the current thread. This means that any calls | ||
/// to [`notify_one`] or [`notify_all`] which happen logically after the | ||
/// mutex is unlocked are candidates to wake this thread up. When this | ||
/// function call returns, the lock specified will have been re-acquired. | ||
/// | ||
/// Note that this function is susceptible to spurious wakeups. Condition | ||
/// variables normally have a boolean predicate associated with them, and | ||
/// the predicate must always be checked each time this function returns to | ||
/// protect against spurious wakeups. | ||
/// | ||
/// # Errors | ||
/// | ||
/// This function will return an error if the mutex being waited on is | ||
/// poisoned when this thread re-acquires the lock. For more information, | ||
/// see information about [poisoning] on the [`Mutex`] type. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This function may [`panic!`] if it is used with more than one mutex | ||
/// over time. | ||
/// | ||
/// [`notify_one`]: Self::notify_one | ||
/// [`notify_all`]: Self::notify_all | ||
/// [poisoning]: super::Mutex#poisoning | ||
/// [`Mutex`]: super::Mutex | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use mc_sgx_sync::{Mutex, Condvar}; | ||
/// | ||
/// let pair = (Mutex::new(false), Condvar::new()); | ||
/// | ||
/// // Wait for the thread to start up. | ||
/// let (lock, cvar) = &*pair; | ||
/// let mut started = lock.lock().unwrap(); | ||
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait. | ||
/// while !*started { | ||
/// started = cvar.wait(started).unwrap(); | ||
/// } | ||
/// ``` | ||
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> { | ||
let poisoned = { | ||
let lock = mutex::guard_lock(&guard); | ||
self.inner.wait(lock); | ||
mutex::guard_poison(&guard).get() | ||
}; | ||
if poisoned { | ||
Err(PoisonError::new(guard)) | ||
} else { | ||
Ok(guard) | ||
} | ||
} | ||
|
||
/// Blocks the current thread until this condition variable receives a | ||
/// notification and the provided condition is false. | ||
/// | ||
/// This function will atomically unlock the mutex specified (represented by | ||
/// `guard`) and block the current thread. This means that any calls | ||
/// to [`notify_one`] or [`notify_all`] which happen logically after the | ||
/// mutex is unlocked are candidates to wake this thread up. When this | ||
/// function call returns, the lock specified will have been re-acquired. | ||
/// | ||
/// # Errors | ||
/// | ||
/// This function will return an error if the mutex being waited on is | ||
/// poisoned when this thread re-acquires the lock. For more information, | ||
/// see information about [poisoning] on the [`Mutex`] type. | ||
/// | ||
/// [`notify_one`]: Self::notify_one | ||
/// [`notify_all`]: Self::notify_all | ||
/// [poisoning]: super::Mutex#poisoning | ||
/// [`Mutex`]: super::Mutex | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use mc_sgx_sync::{Mutex, Condvar}; | ||
/// | ||
/// let pair = (Mutex::new(true), Condvar::new()); | ||
/// | ||
/// // Wait for the thread to start up. | ||
/// let (lock, cvar) = &*pair; | ||
/// // As long as the value inside the `Mutex<bool>` is `true`, we wait. | ||
/// let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap(); | ||
/// ``` | ||
pub fn wait_while<'a, T, F>( | ||
&self, | ||
mut guard: MutexGuard<'a, T>, | ||
mut condition: F, | ||
) -> LockResult<MutexGuard<'a, T>> | ||
where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
while condition(&mut *guard) { | ||
guard = self.wait(guard)?; | ||
} | ||
Ok(guard) | ||
} | ||
|
||
/// Wakes up one blocked thread on this condvar. | ||
/// | ||
/// If there is a blocked thread on this condition variable, then it will | ||
/// be woken up from its call to [`wait`]. Calls to `notify_one` are not | ||
/// buffered in any way. | ||
/// | ||
/// To wake up all threads, see [`notify_all`]. | ||
/// | ||
/// [`wait`]: Self::wait | ||
/// [`notify_all`]: Self::notify_all | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use mc_sgx_sync::{Mutex, Condvar}; | ||
/// | ||
/// let pair = (Mutex::new(false), Condvar::new()); | ||
/// | ||
/// let (lock, cvar) = &*pair; | ||
/// // We notify the condvar that the value has changed. | ||
/// { | ||
/// let mut started = lock.lock().unwrap(); | ||
/// *started = true; | ||
/// cvar.notify_one(); | ||
/// } | ||
/// ``` | ||
pub fn notify_one(&self) { | ||
self.inner.notify_one() | ||
} | ||
|
||
/// Wakes up all blocked threads on this condvar. | ||
/// | ||
/// This method will ensure that any current waiters on the condition | ||
/// variable are awoken. Calls to `notify_all()` are not buffered in any | ||
/// way. | ||
/// | ||
/// To wake up only one thread, see [`notify_one`]. | ||
/// | ||
/// [`notify_one`]: Self::notify_one | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use mc_sgx_sync::{Mutex, Condvar}; | ||
/// | ||
/// let pair = (Mutex::new(false), Condvar::new()); | ||
/// | ||
/// { | ||
/// let mut started = lock.lock().unwrap(); | ||
/// *started = true; | ||
/// // We notify the condvar that the value has changed. | ||
/// cvar.notify_all(); | ||
/// } | ||
/// ``` | ||
pub fn notify_all(&self) { | ||
self.inner.notify_all() | ||
} | ||
} | ||
|
||
impl fmt::Debug for Condvar { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("Condvar").finish_non_exhaustive() | ||
} | ||
} | ||
|
||
impl Default for Condvar { | ||
/// Creates a `Condvar` which is ready to be waited on and notified. | ||
fn default() -> Condvar { | ||
Condvar::new() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,5 @@ | |
mod condvar; | ||
mod mutex; | ||
|
||
pub(crate) use condvar::Condvar; | ||
pub(crate) use mutex::Mutex; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters