diff options
| author | Simonas Kazlauskas <git@kazlauskas.me> | 2015-04-04 00:46:54 +0300 |
|---|---|---|
| committer | Simonas Kazlauskas <git@kazlauskas.me> | 2015-04-08 19:42:16 +0300 |
| commit | 45aa6c8d1bc2f7863c92da6643de4642bb2d83bf (patch) | |
| tree | 53f8648a696dc49072ceef53c36974f6fc599515 /src/libstd/sys/unix | |
| parent | 80def6c2447d23a624e611417f24cf0ab2a5a676 (diff) | |
| download | rust-45aa6c8d1bc2f7863c92da6643de4642bb2d83bf.tar.gz rust-45aa6c8d1bc2f7863c92da6643de4642bb2d83bf.zip | |
Implement reentrant mutexes and make stdio use them
write_fmt calls write for each formatted field. The default implementation of write_fmt is used, which will call write on not-yet-locked stdout (and write locking after), therefore making print! in multithreaded environment still interleave contents of two separate prints. This patch implements reentrant mutexes, changes stdio handles to use these mutexes and overrides write_fmt to lock the stdio handle for the whole duration of the call.
Diffstat (limited to 'src/libstd/sys/unix')
| -rw-r--r-- | src/libstd/sys/unix/mutex.rs | 48 | ||||
| -rw-r--r-- | src/libstd/sys/unix/sync.rs | 29 |
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; } |
