about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-01-09 16:35:16 +0100
committerRalf Jung <post@ralfj.de>2023-01-09 16:35:16 +0100
commit85e87a80fc5b51d395b08ba49adb4242bb751e35 (patch)
tree905fea2b1229e5d9e5ccc18f8bb3597f1a97254d /src
parentd61d359d5ef5e3192611297805dbfbb52c55de8f (diff)
downloadrust-85e87a80fc5b51d395b08ba49adb4242bb751e35.tar.gz
rust-85e87a80fc5b51d395b08ba49adb4242bb751e35.zip
add dtors_in_dtors_in_dtors
Diffstat (limited to 'src')
-rw-r--r--src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
index 04e89ec361b..7ccafec6037 100644
--- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
+++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
@@ -186,8 +186,65 @@ fn join_orders_after_tls_destructors() {
     }
 }
 
+fn dtors_in_dtors_in_dtors() {
+    use std::cell::UnsafeCell;
+    use std::sync::{Arc, Condvar, Mutex};
+
+    #[derive(Clone, Default)]
+    struct Signal(Arc<(Mutex<bool>, Condvar)>);
+
+    impl Signal {
+        fn notify(&self) {
+            let (set, cvar) = &*self.0;
+            *set.lock().unwrap() = true;
+            cvar.notify_one();
+        }
+
+        fn wait(&self) {
+            let (set, cvar) = &*self.0;
+            let mut set = set.lock().unwrap();
+            while !*set {
+                set = cvar.wait(set).unwrap();
+            }
+        }
+    }
+
+    struct NotifyOnDrop(Signal);
+
+    impl Drop for NotifyOnDrop {
+        fn drop(&mut self) {
+            let NotifyOnDrop(ref f) = *self;
+            f.notify();
+        }
+    }
+
+    struct S1(Signal);
+    thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+    thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None));
+
+    impl Drop for S1 {
+        fn drop(&mut self) {
+            let S1(ref signal) = *self;
+            unsafe {
+                let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone())));
+            }
+        }
+    }
+
+    let signal = Signal::default();
+    let signal2 = signal.clone();
+    let _t = thread::spawn(move || unsafe {
+        let mut signal = Some(signal2);
+        K1.with(|s| *s.get() = Some(S1(signal.take().unwrap())));
+    });
+    // Note that this test will deadlock if TLS destructors aren't run (this
+    // requires the destructor to be run to pass the test).
+    signal.wait();
+}
+
 fn main() {
     check_destructors();
     check_blocking();
     join_orders_after_tls_destructors();
+    dtors_in_dtors_in_dtors();
 }