-
Notifications
You must be signed in to change notification settings - Fork 114
/
Copy pathatomic.rs
125 lines (101 loc) · 2.76 KB
/
atomic.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#![deny(warnings, rust_2018_idioms)]
use loom::sync::atomic::AtomicUsize;
use loom::thread;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
use std::sync::Arc;
loom::lazy_static! {
static ref A: AtomicUsize = AtomicUsize::new(0);
static ref NO_LEAK: loom::sync::Arc<usize> = Default::default();
static ref ARC_WITH_SLOW_CONSTRUCTOR: loom::sync::Arc<usize> = { thread::yield_now(); Default::default() };
}
loom::thread_local! {
static B: usize = A.load(Relaxed);
}
#[test]
#[should_panic]
fn lazy_static_arc_shutdown() {
loom::model(|| {
// note that we are not waiting for this thread,
// so it may access the static during shutdown,
// which is not okay.
thread::spawn(|| {
assert_eq!(**NO_LEAK, 0);
});
});
}
#[test]
fn lazy_static_arc_race() {
loom::model(|| {
let jh = thread::spawn(|| {
assert_eq!(**ARC_WITH_SLOW_CONSTRUCTOR, 0);
});
assert_eq!(**ARC_WITH_SLOW_CONSTRUCTOR, 0);
jh.join().unwrap();
});
}
#[test]
fn lazy_static_arc_doesnt_leak() {
loom::model(|| {
assert_eq!(**NO_LEAK, 0);
});
}
#[test]
fn legal_load_after_lazy_static() {
loom::model(|| {
let t1 = thread::spawn(|| {
B.try_with(|h| *h).unwrap_or_else(|_| A.load(Relaxed));
});
let t2 = thread::spawn(|| {
B.try_with(|h| *h).unwrap_or_else(|_| A.load(Relaxed));
});
t1.join().unwrap();
t2.join().unwrap();
});
}
#[test]
#[should_panic]
fn invalid_unsync_load_relaxed() {
loom::model(|| {
let a = Arc::new(AtomicUsize::new(0));
let b = a.clone();
let thread = thread::spawn(move || {
unsafe { a.unsync_load() };
});
b.store(1, Relaxed);
thread.join().unwrap();
});
}
#[test]
#[ignore]
#[should_panic]
fn compare_and_swap_reads_old_values() {
loom::model(|| {
let a = Arc::new(AtomicUsize::new(0));
let b = Arc::new(AtomicUsize::new(0));
let a2 = a.clone();
let b2 = b.clone();
let th = thread::spawn(move || {
a2.store(1, Release);
b2.compare_and_swap(0, 2, AcqRel);
});
b.store(1, Release);
a.compare_and_swap(0, 2, AcqRel);
th.join().unwrap();
let a_val = a.load(Acquire);
let b_val = b.load(Acquire);
if a_val == 2 && b_val == 2 {
panic!();
}
});
}
#[test]
fn fetch_add_atomic() {
loom::model(|| {
let a1 = Arc::new(AtomicUsize::new(0));
let a2 = a1.clone();
let th = thread::spawn(move || a2.fetch_add(1, Relaxed));
let v1 = a1.fetch_add(1, Relaxed);
let v2 = th.join().unwrap();
assert_ne!(v1, v2);
});
}