std: Remove a double-box in ReentrantMutex

Perform unsafe initialization up front and then only afterward the mutex is in
place do we initialize it.
This commit is contained in:
Alex Crichton 2015-05-05 16:44:28 -07:00
parent a031325e83
commit 7529bd60c3
3 changed files with 25 additions and 22 deletions

View file

@ -19,9 +19,9 @@ use sys::mutex as sys;
/// A re-entrant mutual exclusion
///
/// This mutex will block *other* threads waiting for the lock to become available. The thread
/// which has already locked the mutex can lock it multiple times without blocking, preventing a
/// common source of deadlocks.
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
inner: Box<sys::ReentrantMutex>,
poison: poison::Flag,
@ -51,10 +51,14 @@ impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {}
impl<T> ReentrantMutex<T> {
/// Creates a new reentrant mutex in an unlocked state.
pub fn new(t: T) -> ReentrantMutex<T> {
ReentrantMutex {
inner: box unsafe { sys::ReentrantMutex::new() },
poison: poison::FLAG_INIT,
data: t,
unsafe {
let mut mutex = ReentrantMutex {
inner: box sys::ReentrantMutex::uninitialized(),
poison: poison::FLAG_INIT,
data: t,
};
mutex.inner.init();
return mutex
}
}

View file

@ -69,30 +69,27 @@ impl Mutex {
}
}
// FIXME: remove the box, because box happens twice now, once at the common layer and once here.
// Box is necessary here, because mutex may not change address after it is intialised on some
// platforms. Regular Mutex above handles this by offloading intialisation to the OS on first lock.
// Sadly, as far as reentrant mutexes go, this scheme is not quite portable and we must initialise
// when we create the mutex, in the `new`.
pub struct ReentrantMutex { inner: Box<UnsafeCell<ffi::pthread_mutex_t>> }
pub struct ReentrantMutex { inner: UnsafeCell<ffi::pthread_mutex_t> }
unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}
impl ReentrantMutex {
pub unsafe fn new() -> ReentrantMutex {
let mutex = ReentrantMutex { inner: box mem::uninitialized() };
pub unsafe fn uninitialized() -> ReentrantMutex {
ReentrantMutex { inner: mem::uninitialized() }
}
pub unsafe fn init(&mut self) {
let mut attr: ffi::pthread_mutexattr_t = mem::uninitialized();
let result = ffi::pthread_mutexattr_init(&mut attr as *mut _);
debug_assert_eq!(result, 0);
let result = ffi::pthread_mutexattr_settype(&mut attr as *mut _,
ffi::PTHREAD_MUTEX_RECURSIVE);
debug_assert_eq!(result, 0);
let result = ffi::pthread_mutex_init(mutex.inner.get(), &attr as *const _);
let result = ffi::pthread_mutex_init(self.inner.get(), &attr as *const _);
debug_assert_eq!(result, 0);
let result = ffi::pthread_mutexattr_destroy(&mut attr as *mut _);
debug_assert_eq!(result, 0);
mutex
}
pub unsafe fn lock(&self) {

View file

@ -59,16 +59,18 @@ impl Mutex {
}
}
pub struct ReentrantMutex { inner: Box<UnsafeCell<ffi::CRITICAL_SECTION>> }
pub struct ReentrantMutex { inner: UnsafeCell<ffi::CRITICAL_SECTION> }
unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}
impl ReentrantMutex {
pub unsafe fn new() -> ReentrantMutex {
let mutex = ReentrantMutex { inner: box mem::uninitialized() };
ffi::InitializeCriticalSection(mutex.inner.get());
mutex
pub unsafe fn uninitialized() -> ReentrantMutex {
mem::uninitialized()
}
pub unsafe fn init(&mut self) {
ffi::InitializeCriticalSection(self.inner.get());
}
pub unsafe fn lock(&self) {