-
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.
- Loading branch information
1 parent
1863475
commit 13b668d
Showing
3 changed files
with
118 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
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 |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
|
||
mod condvar; | ||
mod mutex; | ||
mod rwlock; | ||
|
||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright (c) 2023 The MobileCoin Foundation | ||
|
||
//! Rust RwLock implementation used in SGX environments | ||
|
||
#![allow(dead_code)] | ||
|
||
use mc_sgx_tstdc::RwLock as SgxRwLock; | ||
|
||
/// SGX rwlock backend to use with the common Rust std lib | ||
/// [`RwLock`](https://doc.rust-lang.org/std/sync/struct.RwLock.html) interface. | ||
/// | ||
/// | ||
/// Read locks are implemented using a reference count. This means that clients | ||
/// are responsible for managing which threads hold the read locks and ensuring | ||
/// threads only unlock if they are currently holding a reader lock. Write locks | ||
/// do track which thread owns them. | ||
pub(crate) struct RwLock { | ||
inner: SgxRwLock, | ||
} | ||
|
||
unsafe impl Send for RwLock {} | ||
unsafe impl Sync for RwLock {} | ||
|
||
impl RwLock { | ||
/// Create a new [`RwLock`] | ||
pub const fn new() -> RwLock { | ||
RwLock { | ||
inner: SgxRwLock::new(), | ||
} | ||
} | ||
|
||
/// Acquire a read lock on the [`RwLock`] | ||
/// | ||
/// NB: This acquires **a** reader lock on the [`RwLock`] instance, it does | ||
/// not keep track of which threads have reader locks. | ||
/// | ||
/// # Panics | ||
/// Panics if the [`RwLock`] got into an invalid state. Invalid states | ||
/// include: | ||
/// - Corrupted underlying data | ||
/// - Trying to obtain a read lock when thread has write lock | ||
pub fn read(&self) { | ||
self.inner | ||
.read() | ||
.expect("RwLock got into an invalid state.") | ||
} | ||
|
||
/// Try to acquire a read lock on the [`RwLock`] | ||
/// | ||
/// NB: This acquires **a** reader lock on the [`RwLock`] instance, it does | ||
/// not keep track of which threads have reader locks. | ||
/// | ||
/// # Returns | ||
/// `true` if a read lock was acquired, `false` otherwise. | ||
pub fn try_read(&self) -> bool { | ||
self.inner | ||
.try_read() | ||
.expect("RwLock got into an invalid state.") | ||
} | ||
|
||
/// Acquire a write lock on the [`RwLock`] | ||
/// | ||
/// # Panics | ||
/// Panics if the [`RwLock`] got into an invalid state. Invalid states | ||
/// include: | ||
/// - Corrupted underlying data | ||
/// - Trying to obtain a write lock when the thread already has the write | ||
/// lock | ||
pub fn write(&self) { | ||
self.inner | ||
.read() | ||
.expect("RwLock got into an invalid state.") | ||
} | ||
|
||
/// Try to acquire a read lock on the [`RwLock`] | ||
/// | ||
/// # Returns | ||
/// `true` if a read lock was acquired, `false` otherwise. | ||
pub fn try_write(&self) -> bool { | ||
self.inner | ||
.try_write() | ||
.expect("RwLock got into an invalid state.") | ||
} | ||
|
||
/// Release a read lock on the [`RwLock`] | ||
/// | ||
/// NB: This release **a** reader lock on the [`RwLock`] instance, it does | ||
/// not validate that the current thread created the reader lock. | ||
/// | ||
/// # Panics | ||
/// Panics if the [`RwLock`] got into an invalid state. Invalid states | ||
/// include: | ||
/// - Corrupted underlying data | ||
/// - Trying to unlock when there are no read locks currently held | ||
pub fn read_unlock(&self) { | ||
self.inner | ||
.read_unlock() | ||
.expect("RwLock got into an invalid state.") | ||
} | ||
|
||
/// Release the write lock on the [`RwLock`] | ||
/// | ||
/// # Panics | ||
/// Panics if the [`RwLock`] got into an invalid state. Invalid states | ||
/// include: | ||
/// - Corrupted underlying data | ||
/// - Trying to unlock when the current thread doesn't hold the write lock | ||
pub fn write_unlock(&self) { | ||
// Note on the `expect()` statement, though unlock can fail due to out | ||
// of memory it's unlikely to happen as unlocking only allocates a | ||
// `void *` per waiting reader thread. | ||
self.inner | ||
.write_unlock() | ||
.expect("RwLock got into an invalid state.") | ||
} | ||
} |