Skip to content

Commit

Permalink
Add mc-sgx-sync::sys::locks::RwLock
Browse files Browse the repository at this point in the history
  • Loading branch information
nick-mobilecoin committed Jan 25, 2023
1 parent f9042d6 commit 2a138be
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
2 changes: 1 addition & 1 deletion sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ doctest = false

[dependencies]
mc-sgx-panic = { path = "../panic", version = "=0.1.0" }
mc-sgx-tstdc = { version = "=0.4.1-beta.0", git = "https://github.com/mobilecoinfoundation/sgx", rev = "11ca0e657b34c268c74591c46acdf6dcf0fd651b" }
mc-sgx-tstdc = { version = "=0.4.1-beta.0", git = "https://github.com/mobilecoinfoundation/sgx", rev = "018f2dab7cb703cc743ab8b8f4c7535e1ce1daa8" }
1 change: 1 addition & 0 deletions sync/src/sys/locks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

mod condvar;
mod mutex;
mod rwlock;

pub(crate) use condvar::Condvar;
pub(crate) use mutex::Mutex;
114 changes: 114 additions & 0 deletions sync/src/sys/locks/rwlock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// 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 {
let result = self.inner.try_read();
result.is_ok()
}

/// 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 {
let result = self.inner.try_write();
result.is_ok()
}

/// 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.")
}
}

0 comments on commit 2a138be

Please sign in to comment.