1 #![deny(warnings, rust_2018_idioms)]
2 use loom::thread;
3 use std::cell::RefCell;
4 use std::sync::atomic::{AtomicUsize, Ordering};
5
6 #[test]
thread_local()7 fn thread_local() {
8 loom::thread_local! {
9 static THREAD_LOCAL: RefCell<usize> = RefCell::new(1);
10 }
11
12 fn do_test(n: usize) {
13 THREAD_LOCAL.with(|local| {
14 assert_eq!(*local.borrow(), 1);
15 });
16 THREAD_LOCAL.with(|local| {
17 assert_eq!(*local.borrow(), 1);
18 *local.borrow_mut() = n;
19 assert_eq!(*local.borrow(), n);
20 });
21 THREAD_LOCAL.with(|local| {
22 assert_eq!(*local.borrow(), n);
23 });
24 }
25
26 loom::model(|| {
27 let t1 = thread::spawn(|| do_test(2));
28
29 let t2 = thread::spawn(|| do_test(3));
30
31 do_test(4);
32
33 t1.join().unwrap();
34 t2.join().unwrap();
35 });
36 }
37
38 #[test]
nested_with()39 fn nested_with() {
40 loom::thread_local! {
41 static LOCAL1: RefCell<usize> = RefCell::new(1);
42 static LOCAL2: RefCell<usize> = RefCell::new(2);
43 }
44
45 loom::model(|| {
46 LOCAL1.with(|local1| *local1.borrow_mut() = LOCAL2.with(|local2| local2.borrow().clone()));
47 });
48 }
49
50 #[test]
drop()51 fn drop() {
52 static DROPS: AtomicUsize = AtomicUsize::new(0);
53
54 struct CountDrops {
55 drops: &'static AtomicUsize,
56 dummy: bool,
57 }
58
59 impl Drop for CountDrops {
60 fn drop(&mut self) {
61 self.drops.fetch_add(1, Ordering::Release);
62 }
63 }
64
65 impl CountDrops {
66 fn new(drops: &'static AtomicUsize) -> Self {
67 Self { drops, dummy: true }
68 }
69 }
70
71 loom::thread_local! {
72 static DROPPED_LOCAL: CountDrops = CountDrops::new(&DROPS);
73 }
74
75 loom::model(|| {
76 assert_eq!(DROPS.load(Ordering::Acquire), 0);
77
78 thread::spawn(|| {
79 // force access to the thread local so that it's initialized.
80 DROPPED_LOCAL.with(|local| assert!(local.dummy));
81 assert_eq!(DROPS.load(Ordering::Acquire), 0);
82 })
83 .join()
84 .unwrap();
85
86 // When the first spawned thread completed, its copy of the thread local
87 // should have been dropped.
88 assert_eq!(DROPS.load(Ordering::Acquire), 1);
89
90 thread::spawn(|| {
91 // force access to the thread local so that it's initialized.
92 DROPPED_LOCAL.with(|local| assert!(local.dummy));
93 assert_eq!(DROPS.load(Ordering::Acquire), 1);
94 })
95 .join()
96 .unwrap();
97
98 // When the second spawned thread completed, its copy of the thread local
99 // should have been dropped as well.
100 assert_eq!(DROPS.load(Ordering::Acquire), 2);
101
102 // force access to the thread local so that it's initialized.
103 DROPPED_LOCAL.with(|local| assert!(local.dummy));
104 });
105
106 // Finally, when the model's "main thread" completes, its copy of the local
107 // should also be dropped.
108 assert_eq!(DROPS.load(Ordering::Acquire), 3);
109 }
110