aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys/unix/mutex.rs
diff options
context:
space:
mode:
authorValentin <[email protected]>2018-06-15 18:57:24 +0200
committerFenrirWolf <[email protected]>2018-06-15 10:57:24 -0600
commitf2a90174bb36b9ad528e863ab34c02ebce002b02 (patch)
tree959e8d67883d3a89e179b3549b1f30d28e51a87c /ctr-std/src/sys/unix/mutex.rs
parentMerge pull request #68 from linouxis9/master (diff)
downloadarchived-ctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.tar.xz
archived-ctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.zip
Update for latest nightly 2018-06-09 (#70)
* Update for latest nightly 2018-06-09 * We now have a proper horizon os and sys modules in libstd
Diffstat (limited to 'ctr-std/src/sys/unix/mutex.rs')
-rw-r--r--ctr-std/src/sys/unix/mutex.rs104
1 files changed, 77 insertions, 27 deletions
diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs
index 95c74a4..52cf3f9 100644
--- a/ctr-std/src/sys/unix/mutex.rs
+++ b/ctr-std/src/sys/unix/mutex.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -9,54 +9,93 @@
// except according to those terms.
use cell::UnsafeCell;
+use libc;
use mem;
-pub struct Mutex {
- inner: UnsafeCell<::libctru::LightLock>,
-}
+pub struct Mutex { inner: UnsafeCell<libc::pthread_mutex_t> }
#[inline]
-pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock {
+pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
m.inner.get()
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
+#[allow(dead_code)] // sys isn't exported yet
impl Mutex {
pub const fn new() -> Mutex {
- Mutex { inner: UnsafeCell::new(0) }
+ // Might be moved and address is changing it is better to avoid
+ // initialization of potentially opaque OS data before it landed
+ Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
}
-
#[inline]
pub unsafe fn init(&mut self) {
- ::libctru::LightLock_Init(self.inner.get());
+ // Issue #33770
+ //
+ // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
+ // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you
+ // try to re-lock it from the same thread when you already hold a lock.
+ //
+ // In practice, glibc takes advantage of this undefined behavior to
+ // implement hardware lock elision, which uses hardware transactional
+ // memory to avoid acquiring the lock. While a transaction is in
+ // progress, the lock appears to be unlocked. This isn't a problem for
+ // other threads since the transactional memory will abort if a conflict
+ // is detected, however no abort is generated if re-locking from the
+ // same thread.
+ //
+ // Since locking the same mutex twice will result in two aliasing &mut
+ // references, we instead create the mutex with type
+ // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
+ // re-lock it from the same thread, thus avoiding undefined behavior.
+ //
+ // We can't do anything for StaticMutex, but that type is deprecated
+ // anyways.
+ let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
+ let r = libc::pthread_mutexattr_init(&mut attr);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutex_init(self.inner.get(), &attr);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutexattr_destroy(&mut attr);
+ debug_assert_eq!(r, 0);
}
-
#[inline]
pub unsafe fn lock(&self) {
- ::libctru::LightLock_Lock(self.inner.get());
+ let r = libc::pthread_mutex_lock(self.inner.get());
+ debug_assert_eq!(r, 0);
}
-
#[inline]
pub unsafe fn unlock(&self) {
- ::libctru::LightLock_Unlock(self.inner.get());
+ let r = libc::pthread_mutex_unlock(self.inner.get());
+ debug_assert_eq!(r, 0);
}
-
#[inline]
pub unsafe fn try_lock(&self) -> bool {
- match ::libctru::LightLock_TryLock(self.inner.get()) {
- 0 => false,
- _ => true,
- }
+ libc::pthread_mutex_trylock(self.inner.get()) == 0
}
-
#[inline]
+ #[cfg(not(target_os = "dragonfly"))]
pub unsafe fn destroy(&self) {
+ let r = libc::pthread_mutex_destroy(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
+ #[cfg(target_os = "dragonfly")]
+ pub unsafe fn destroy(&self) {
+ use libc;
+ let r = libc::pthread_mutex_destroy(self.inner.get());
+ // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
+ // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
+ // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
+ // this behaviour no longer occurs.
+ debug_assert!(r == 0 || r == libc::EINVAL);
}
}
-pub struct ReentrantMutex { inner: UnsafeCell<::libctru::RecursiveLock> }
+pub struct ReentrantMutex { inner: UnsafeCell<libc::pthread_mutex_t> }
unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}
@@ -67,24 +106,35 @@ impl ReentrantMutex {
}
pub unsafe fn init(&mut self) {
- ::libctru::RecursiveLock_Init(self.inner.get());
+ let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
+ let result = libc::pthread_mutexattr_init(&mut attr as *mut _);
+ debug_assert_eq!(result, 0);
+ let result = libc::pthread_mutexattr_settype(&mut attr as *mut _,
+ libc::PTHREAD_MUTEX_RECURSIVE);
+ debug_assert_eq!(result, 0);
+ let result = libc::pthread_mutex_init(self.inner.get(), &attr as *const _);
+ debug_assert_eq!(result, 0);
+ let result = libc::pthread_mutexattr_destroy(&mut attr as *mut _);
+ debug_assert_eq!(result, 0);
}
pub unsafe fn lock(&self) {
- ::libctru::RecursiveLock_Lock(self.inner.get());
+ let result = libc::pthread_mutex_lock(self.inner.get());
+ debug_assert_eq!(result, 0);
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
- match ::libctru::RecursiveLock_TryLock(self.inner.get()) {
- 0 => false,
- _ => true,
- }
+ libc::pthread_mutex_trylock(self.inner.get()) == 0
}
pub unsafe fn unlock(&self) {
- ::libctru::RecursiveLock_Unlock(self.inner.get());
+ let result = libc::pthread_mutex_unlock(self.inner.get());
+ debug_assert_eq!(result, 0);
}
- pub unsafe fn destroy(&self) {}
+ pub unsafe fn destroy(&self) {
+ let result = libc::pthread_mutex_destroy(self.inner.get());
+ debug_assert_eq!(result, 0);
+ }
}