From a9961d4ec400ef54a49183f9063ddf40f2ca23e7 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Tue, 18 Feb 2020 10:38:33 +0100 Subject: [PATCH] Add new `const_new` function to `lock_api` This new constructor allows creating mutexes, reentrant mutexes and RwLocks in a constant context on stable Rust by manually passing in the underlying raw mutex / rwlock. --- lock_api/src/mutex.rs | 14 +++++++++++++- lock_api/src/remutex.rs | 26 ++++++++++++++++++++++++-- lock_api/src/rwlock.rs | 15 ++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/lock_api/src/mutex.rs b/lock_api/src/mutex.rs index aa02bb0d..951ff0e2 100644 --- a/lock_api/src/mutex.rs +++ b/lock_api/src/mutex.rs @@ -95,7 +95,7 @@ pub unsafe trait RawMutexTimed: RawMutex { /// it is protecting. The data can only be accessed through the RAII guards /// returned from `lock` and `try_lock`, which guarantees that the data is only /// ever accessed when the mutex is locked. -pub struct Mutex { +pub struct Mutex { raw: R, data: UnsafeCell, } @@ -131,6 +131,18 @@ impl Mutex { } } +impl Mutex { + /// Creates a new mutex based on a pre-existing raw mutex. This allows + /// creating a mutex in a constant context on stable Rust. + #[inline] + pub const fn const_new(raw_mutex: R, val: T) -> Mutex { + Mutex { + raw: raw_mutex, + data: UnsafeCell::new(val), + } + } +} + impl Mutex { /// # Safety /// diff --git a/lock_api/src/remutex.rs b/lock_api/src/remutex.rs index 4fd102a9..f776336d 100644 --- a/lock_api/src/remutex.rs +++ b/lock_api/src/remutex.rs @@ -47,7 +47,7 @@ pub unsafe trait GetThreadId { fn nonzero_thread_id(&self) -> NonZeroUsize; } -struct RawReentrantMutex { +struct RawReentrantMutex { owner: AtomicUsize, lock_count: Cell, mutex: R, @@ -145,7 +145,7 @@ impl RawReentrantMutex { /// /// See [`Mutex`](struct.Mutex.html) for more details about the underlying mutex /// primitive. -pub struct ReentrantMutex { +pub struct ReentrantMutex { raw: RawReentrantMutex, data: UnsafeCell, } @@ -197,6 +197,28 @@ impl ReentrantMutex { } } +impl ReentrantMutex { + /// Creates a new reentrant mutex based on a pre-existing raw reentrant + /// mutex and a helper to get the thread ID. This allows creating a + /// reentrant mutex in a constant context on stable Rust. + #[inline] + pub const fn const_new( + raw_reentrant_mutex: R, + get_thread_id: G, + val: T, + ) -> ReentrantMutex { + ReentrantMutex { + data: UnsafeCell::new(val), + raw: RawReentrantMutex { + owner: AtomicUsize::new(0), + lock_count: Cell::new(0), + mutex: raw_reentrant_mutex, + get_thread_id, + }, + } + } +} + impl ReentrantMutex { /// # Safety /// diff --git a/lock_api/src/rwlock.rs b/lock_api/src/rwlock.rs index 0707e3cd..5560793e 100644 --- a/lock_api/src/rwlock.rs +++ b/lock_api/src/rwlock.rs @@ -231,7 +231,7 @@ pub unsafe trait RawRwLockUpgradeTimed: RawRwLockUpgrade + RawRwLockTimed { /// allow concurrent access through readers. The RAII guards returned from the /// locking methods implement `Deref` (and `DerefMut` for the `write` methods) /// to allow access to the contained of the lock. -pub struct RwLock { +pub struct RwLock { raw: R, data: UnsafeCell, } @@ -297,6 +297,19 @@ impl RwLock { } } +impl RwLock { + /// Creates a new new instance of an `RwLock` based on a pre-existing + /// `RawRwLock`. This allows creating a `RwLock` in a constant context + /// on stable Rust. + #[inline] + pub const fn const_new(raw_rwlock: R, val: T) -> RwLock { + RwLock { + data: UnsafeCell::new(val), + raw: raw_rwlock, + } + } +} + impl RwLock { /// # Safety ///