}
}
+ // FIXME: We should check that this lock was locked by the active thread.
fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
///
/// Note: on Windows OS this function is a no-op because we do not support
/// concurrency on Windows yet.
+ ///
+ /// FIXME: we do not support yet deallocation of thread local statics.
fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
if this.tcx.sess.target.target.target_os == "windows" {
impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
/// Check if we have an allocation for the given thread local static for the
/// active thread.
- pub fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<AllocId> {
+ fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<AllocId> {
self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned()
}
/// Set the allocation id as the allocation id of the given thread local
/// static for the active thread.
- pub fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) {
+ fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) {
assert!(
self.thread_local_alloc_ids
.borrow_mut()
--- /dev/null
+// ignore-windows
+
+#![feature(thread_local_internals)]
+
+use std::cell::RefCell;
+use std::thread;
+
+static A: std::thread::LocalKey<RefCell<u8>> = {
+ #[inline]
+ fn __init() -> RefCell<u8> {
+ RefCell::new(0)
+ }
+
+ unsafe fn __getit() -> Option<&'static RefCell<u8>> {
+ static __KEY: std::thread::__OsLocalKeyInner<RefCell<u8>> =
+ std::thread::__OsLocalKeyInner::new();
+ __KEY.get(__init)
+ }
+
+ unsafe { std::thread::LocalKey::new(__getit) }
+};
+
+struct Sender(*mut u8);
+
+unsafe impl Send for Sender {}
+
+fn main() {
+ A.with(|f| {
+ assert_eq!(*f.borrow(), 0);
+ *f.borrow_mut() = 4;
+ });
+
+ let handle = thread::spawn(|| {
+ let ptr = A.with(|f| {
+ assert_eq!(*f.borrow(), 0);
+ *f.borrow_mut() = 5;
+ &mut *f.borrow_mut() as *mut u8
+ });
+ Sender(ptr)
+ });
+ let ptr = handle.join().unwrap().0;
+ A.with(|f| {
+ assert_eq!(*f.borrow(), 4);
+ });
+ let _x = unsafe { *ptr }; //~ ERROR Undefined Behavior
+}
--- /dev/null
+// ignore-windows: No libc on Windows
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::cell::UnsafeCell;
+use std::sync::Arc;
+use std::thread;
+
+struct Mutex(UnsafeCell<libc::pthread_mutex_t>);
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+fn new_lock() -> Arc<Mutex> {
+ Arc::new(Mutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)))
+}
+
+fn main() {
+ unsafe {
+ let lock = new_lock();
+ assert_eq!(libc::pthread_mutex_lock(lock.0.get() as *mut _), 0);
+
+ let lock_copy = lock.clone();
+ thread::spawn(move || {
+ assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock
+ })
+ .join()
+ .unwrap();
+ }
+}
--- /dev/null
+// ignore-windows: No libc on Windows
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::cell::UnsafeCell;
+use std::sync::Arc;
+use std::thread;
+
+struct Mutex(UnsafeCell<libc::pthread_mutex_t>);
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+fn new_lock() -> Arc<Mutex> {
+ Arc::new(Mutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)))
+}
+
+fn main() {
+ unsafe {
+ let lock = new_lock();
+ assert_eq!(libc::pthread_mutex_lock(lock.0.get() as *mut _), 0);
+
+ let lock_copy = lock.clone();
+ thread::spawn(move || {
+ assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: called pthread_mutex_unlock on a mutex owned by another thread
+ })
+ .join()
+ .unwrap();
+ }
+}
--- /dev/null
+// ignore-windows: No libc on Windows
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::cell::UnsafeCell;
+use std::sync::Arc;
+use std::thread;
+
+struct RwLock(UnsafeCell<libc::pthread_rwlock_t>);
+
+unsafe impl Send for RwLock {}
+unsafe impl Sync for RwLock {}
+
+fn new_lock() -> Arc<RwLock> {
+ Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER)))
+}
+
+fn main() {
+ unsafe {
+ let lock = new_lock();
+ assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0);
+
+ let lock_copy = lock.clone();
+ thread::spawn(move || {
+ assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock
+ })
+ .join()
+ .unwrap();
+ }
+}
--- /dev/null
+// ignore-windows: No libc on Windows
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::cell::UnsafeCell;
+use std::sync::Arc;
+use std::thread;
+
+struct RwLock(UnsafeCell<libc::pthread_rwlock_t>);
+
+unsafe impl Send for RwLock {}
+unsafe impl Sync for RwLock {}
+
+fn new_lock() -> Arc<RwLock> {
+ Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER)))
+}
+
+fn main() {
+ unsafe {
+ let lock = new_lock();
+ assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0);
+
+ let lock_copy = lock.clone();
+ thread::spawn(move || {
+ assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock
+ })
+ .join()
+ .unwrap();
+ }
+}
// ignore-windows
-//! This test just calls the relevant APIs to check if Miri crashes.
-
-use std::sync::{Arc, Mutex};
+use std::sync::{Arc, Mutex, RwLock};
use std::thread;
-fn main() {
+fn check_mutex() {
let data = Arc::new(Mutex::new(0));
let mut threads = Vec::new();
let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
assert_eq!(data, 3);
}
+
+fn check_rwlock_write() {
+ let data = Arc::new(RwLock::new(0));
+ let mut threads = Vec::new();
+
+ for _ in 0..3 {
+ let data = Arc::clone(&data);
+ let thread = thread::spawn(move || {
+ let mut data = data.write().unwrap();
+ *data += 1;
+ });
+ threads.push(thread);
+ }
+
+ for thread in threads {
+ thread.join().unwrap();
+ }
+
+ assert!(data.try_write().is_ok());
+
+ let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
+ assert_eq!(data, 3);
+}
+
+fn check_rwlock_read_no_deadlock() {
+ let l1 = Arc::new(RwLock::new(0));
+ let l2 = Arc::new(RwLock::new(0));
+
+ let l1_copy = Arc::clone(&l1);
+ let l2_copy = Arc::clone(&l2);
+ let _guard1 = l1.read().unwrap();
+ let handle = thread::spawn(move || {
+ let _guard2 = l2_copy.read().unwrap();
+ thread::yield_now();
+ let _guard1 = l1_copy.read().unwrap();
+ });
+ thread::yield_now();
+ let _guard2 = l2.read().unwrap();
+ handle.join().unwrap();
+}
+
+fn main() {
+ check_mutex();
+ check_rwlock_write();
+ check_rwlock_read_no_deadlock();
+}