Make it possible to have unboxed mutexes on specific platforms.
This commit keeps all mutexes boxed on all platforms, but makes it trivial to remove the box on some platforms later.
This commit is contained in:
parent
a8c2d4fc3d
commit
58deb7001d
10 changed files with 51 additions and 9 deletions
|
@ -15,6 +15,8 @@ extern "C" {
|
||||||
// implemented identically.
|
// implemented identically.
|
||||||
pub struct Mutex(RWLock);
|
pub struct Mutex(RWLock);
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
|
pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
|
||||||
rwlock::raw(&m.0)
|
rwlock::raw(&m.0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ pub struct Mutex {
|
||||||
inner: SpinMutex<WaitVariable<bool>>,
|
inner: SpinMutex<WaitVariable<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
|
// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
|
||||||
impl Mutex {
|
impl Mutex {
|
||||||
pub const fn new() -> Mutex {
|
pub const fn new() -> Mutex {
|
||||||
|
|
|
@ -5,6 +5,8 @@ pub struct Mutex {
|
||||||
inner: UnsafeCell<libc::pthread_mutex_t>,
|
inner: UnsafeCell<libc::pthread_mutex_t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
|
pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
|
||||||
m.inner.get()
|
m.inner.get()
|
||||||
|
|
|
@ -4,6 +4,8 @@ pub struct Mutex {
|
||||||
locked: UnsafeCell<bool>,
|
locked: UnsafeCell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
unsafe impl Send for Mutex {}
|
unsafe impl Send for Mutex {}
|
||||||
unsafe impl Sync for Mutex {} // no threads on this platform
|
unsafe impl Sync for Mutex {} // no threads on this platform
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ pub struct Mutex {
|
||||||
inner: UnsafeCell<libc::pthread_mutex_t>,
|
inner: UnsafeCell<libc::pthread_mutex_t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
|
pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
|
||||||
m.inner.get()
|
m.inner.get()
|
||||||
|
|
|
@ -8,6 +8,8 @@ pub struct Mutex {
|
||||||
locked: AtomicUsize,
|
locked: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
// Mutexes have a pretty simple implementation where they contain an `i32`
|
// Mutexes have a pretty simple implementation where they contain an `i32`
|
||||||
// internally that is 0 when unlocked and 1 when the mutex is locked.
|
// internally that is 0 when unlocked and 1 when the mutex is locked.
|
||||||
// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
|
// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
|
||||||
|
|
|
@ -29,6 +29,8 @@ pub struct Mutex {
|
||||||
lock: AtomicUsize,
|
lock: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
unsafe impl Send for Mutex {}
|
unsafe impl Send for Mutex {}
|
||||||
unsafe impl Sync for Mutex {}
|
unsafe impl Sync for Mutex {}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::sys::condvar as imp;
|
use crate::sys::condvar as imp;
|
||||||
|
use crate::sys::mutex as mutex_imp;
|
||||||
use crate::sys_common::mutex::MovableMutex;
|
use crate::sys_common::mutex::MovableMutex;
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
use check::CondvarCheck;
|
|
||||||
|
|
||||||
mod check;
|
mod check;
|
||||||
|
|
||||||
|
type CondvarCheck = <mutex_imp::MovableMutex as check::CondvarCheck>::Check;
|
||||||
|
|
||||||
/// An OS-based condition variable.
|
/// An OS-based condition variable.
|
||||||
pub struct Condvar {
|
pub struct Condvar {
|
||||||
inner: Box<imp::Condvar>,
|
inner: Box<imp::Condvar>,
|
||||||
|
|
|
@ -2,13 +2,22 @@ use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use crate::sys::mutex as mutex_imp;
|
use crate::sys::mutex as mutex_imp;
|
||||||
use crate::sys_common::mutex::MovableMutex;
|
use crate::sys_common::mutex::MovableMutex;
|
||||||
|
|
||||||
/// A `Condvar` will check it's only ever used with the same mutex, based on
|
pub trait CondvarCheck {
|
||||||
/// its (stable) address.
|
type Check;
|
||||||
pub struct CondvarCheck {
|
}
|
||||||
|
|
||||||
|
/// For boxed mutexes, a `Condvar` will check it's only ever used with the same
|
||||||
|
/// mutex, based on its (stable) address.
|
||||||
|
impl CondvarCheck for Box<mutex_imp::Mutex> {
|
||||||
|
type Check = SameMutexCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SameMutexCheck {
|
||||||
addr: AtomicUsize,
|
addr: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CondvarCheck {
|
#[allow(dead_code)]
|
||||||
|
impl SameMutexCheck {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self { addr: AtomicUsize::new(0) }
|
Self { addr: AtomicUsize::new(0) }
|
||||||
}
|
}
|
||||||
|
@ -21,3 +30,19 @@ impl CondvarCheck {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unboxed mutexes may move, so `Condvar` can not require its address to stay
|
||||||
|
/// constant.
|
||||||
|
impl CondvarCheck for mutex_imp::Mutex {
|
||||||
|
type Check = NoCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NoCheck;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl NoCheck {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
pub fn verify(&self, _: &MovableMutex) {}
|
||||||
|
}
|
||||||
|
|
|
@ -58,16 +58,17 @@ impl Drop for StaticMutexGuard<'_> {
|
||||||
///
|
///
|
||||||
/// This mutex does not implement poisoning.
|
/// This mutex does not implement poisoning.
|
||||||
///
|
///
|
||||||
/// This is a wrapper around `Box<imp::Mutex>`, to allow the object to be moved
|
/// This is either a wrapper around `Box<imp::Mutex>` or `imp::Mutex`,
|
||||||
/// without moving the raw mutex.
|
/// depending on the platform. It is boxed on platforms where `imp::Mutex` may
|
||||||
pub struct MovableMutex(Box<imp::Mutex>);
|
/// not be moved.
|
||||||
|
pub struct MovableMutex(imp::MovableMutex);
|
||||||
|
|
||||||
unsafe impl Sync for MovableMutex {}
|
unsafe impl Sync for MovableMutex {}
|
||||||
|
|
||||||
impl MovableMutex {
|
impl MovableMutex {
|
||||||
/// Creates a new mutex.
|
/// Creates a new mutex.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut mutex = box imp::Mutex::new();
|
let mut mutex = imp::MovableMutex::from(imp::Mutex::new());
|
||||||
unsafe { mutex.init() };
|
unsafe { mutex.init() };
|
||||||
Self(mutex)
|
Self(mutex)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue