]> git.lizzy.rs Git - rust.git/commitdiff
Add concurrency tests.
authorVytautas Astrauskas <astrauv@amazon.com>
Sat, 18 Apr 2020 19:25:11 +0000 (12:25 -0700)
committerVytautas Astrauskas <astrauv@amazon.com>
Mon, 27 Apr 2020 21:26:36 +0000 (14:26 -0700)
src/shims/sync.rs
src/shims/tls.rs
src/thread.rs
tests/compile-fail/concurrency/dangling_tls_lib.rs [new file with mode: 0644]
tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs [new file with mode: 0644]
tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs [new file with mode: 0644]
tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs [new file with mode: 0644]
tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs [new file with mode: 0644]
tests/run-pass/concurrency/locks.rs

index d8a00156384c3bc8ab37cc1373b9c36e258990b8..6a1ea108dbb06ed41cf4ceff2c53cb0fbe234b28 100644 (file)
@@ -532,6 +532,7 @@ fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResu
         }
     }
 
+    // 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();
 
index 722b24d747525e12f724ca0c9ccca411ca6051a7..89ec16596599e594e279d370a83cadff3d7406d7 100644 (file)
@@ -233,6 +233,8 @@ fn run_windows_tls_dtors(&mut self) -> InterpResult<'tcx> {
     ///
     /// 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" {
index 31296ad96ff0ff3b2b6a6b62024f98d91b320141..ab6a4c94db83147deee16cdaa560e258416285be 100644 (file)
@@ -164,13 +164,13 @@ fn default() -> Self {
 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()
diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs
new file mode 100644 (file)
index 0000000..ad12c10
--- /dev/null
@@ -0,0 +1,46 @@
+// 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
+}
diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs
new file mode 100644 (file)
index 0000000..5d04635
--- /dev/null
@@ -0,0 +1,32 @@
+// 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();
+    }
+}
diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs
new file mode 100644 (file)
index 0000000..3009721
--- /dev/null
@@ -0,0 +1,32 @@
+// 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();
+    }
+}
diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
new file mode 100644 (file)
index 0000000..19dce43
--- /dev/null
@@ -0,0 +1,32 @@
+// 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();
+    }
+}
diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
new file mode 100644 (file)
index 0000000..098c1c2
--- /dev/null
@@ -0,0 +1,32 @@
+// 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();
+    }
+}
index 3c8373691b842839846058e232a544af351991bf..90c10b8ffe247894252914ea8a541c7973d2f180 100644 (file)
@@ -1,11 +1,9 @@
 // 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();
 
@@ -27,3 +25,49 @@ fn main() {
     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();
+}