about summary refs log tree commit diff
path: root/src/libstd/sys/unix
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/unix')
-rw-r--r--src/libstd/sys/unix/mutex.rs48
-rw-r--r--src/libstd/sys/unix/sync.rs29
2 files changed, 76 insertions, 1 deletions
diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs
index 1c0ce293804..af814653c14 100644
--- a/src/libstd/sys/unix/mutex.rs
+++ b/src/libstd/sys/unix/mutex.rs
@@ -12,6 +12,7 @@ use prelude::v1::*;
 
 use cell::UnsafeCell;
 use sys::sync as ffi;
+use mem;
 
 pub struct Mutex { inner: UnsafeCell<ffi::pthread_mutex_t> }
 
@@ -67,3 +68,50 @@ impl Mutex {
         debug_assert!(r == 0 || r == libc::EINVAL);
     }
 }
+
+// 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>> }
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+    pub unsafe fn new() -> ReentrantMutex {
+        let mutex = ReentrantMutex { inner: box mem::uninitialized() };
+        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 _);
+        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) {
+        let result = ffi::pthread_mutex_lock(self.inner.get());
+        debug_assert_eq!(result, 0);
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        ffi::pthread_mutex_trylock(self.inner.get()) == 0
+    }
+
+    pub unsafe fn unlock(&self) {
+        let result = ffi::pthread_mutex_unlock(self.inner.get());
+        debug_assert_eq!(result, 0);
+    }
+
+    pub unsafe fn destroy(&self) {
+        let result = ffi::pthread_mutex_destroy(self.inner.get());
+        debug_assert_eq!(result, 0);
+    }
+}
diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs
index 3c05fd602be..41e1e206a42 100644
--- a/src/libstd/sys/unix/sync.rs
+++ b/src/libstd/sys/unix/sync.rs
@@ -12,17 +12,25 @@
 
 use libc;
 
-pub use self::os::{PTHREAD_MUTEX_INITIALIZER, pthread_mutex_t};
+pub use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_RECURSIVE, pthread_mutex_t,
+                   pthread_mutexattr_t};
 pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t};
 pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t};
 
 extern {
     // mutexes
+    pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t)
+                            -> libc::c_int;
     pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
     pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
     pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
     pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;
 
+    pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int;
+    pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int;
+    pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int)
+                                    -> libc::c_int;
+
     // cvars
     pub fn pthread_cond_wait(cond: *mut pthread_cond_t,
                              lock: *mut pthread_mutex_t) -> libc::c_int;
@@ -52,12 +60,14 @@ mod os {
     use libc;
 
     pub type pthread_mutex_t = *mut libc::c_void;
+    pub type pthread_mutexattr_t = *mut libc::c_void;
     pub type pthread_cond_t = *mut libc::c_void;
     pub type pthread_rwlock_t = *mut libc::c_void;
 
     pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _;
     pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _;
     pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _;
+    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
@@ -95,6 +105,12 @@ mod os {
         __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
     }
     #[repr(C)]
+    pub struct pthread_mutexattr_t {
+        __sig: libc::c_long,
+        // note, that this is 16 bytes just to be safe, the actual struct might be smaller.
+        __opaque: [u8; 16],
+    }
+    #[repr(C)]
     pub struct pthread_cond_t {
         __sig: libc::c_long,
         __opaque: [u8; __PTHREAD_COND_SIZE__],
@@ -117,6 +133,8 @@ mod os {
         __sig: _PTHREAD_RWLOCK_SIG_INIT,
         __opaque: [0; __PTHREAD_RWLOCK_SIZE__],
     };
+
+    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
 }
 
 #[cfg(target_os = "linux")]
@@ -161,6 +179,12 @@ mod os {
         size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
     }
     #[repr(C)]
+    pub struct pthread_mutexattr_t {
+        __align: libc::c_longlong,
+        // note, that this is 16 bytes just to be safe, the actual struct might be smaller.
+        size: [u8; 16],
+    }
+    #[repr(C)]
     pub struct pthread_cond_t {
         __align: libc::c_longlong,
         size: [u8; __SIZEOF_PTHREAD_COND_T],
@@ -183,6 +207,7 @@ mod os {
         __align: 0,
         size: [0; __SIZEOF_PTHREAD_RWLOCK_T],
     };
+    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
 }
 #[cfg(target_os = "android")]
 mod os {
@@ -190,6 +215,7 @@ mod os {
 
     #[repr(C)]
     pub struct pthread_mutex_t { value: libc::c_int }
+    pub type pthread_mutexattr_t = libc::c_long;
     #[repr(C)]
     pub struct pthread_cond_t { value: libc::c_int }
     #[repr(C)]
@@ -218,4 +244,5 @@ mod os {
         pendingWriters: 0,
         reserved: [0 as *mut _; 4],
     };
+    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
 }