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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! A shim crate to easily test code with `loom`.
//!
//! Import common types and modules like `UnsafeCell`, `thread`, `Arc`,
//! `AtomicI32`, etc from this crate, and run loom tests from the command line
//! with `cargo test --features loomy/enable`.
//!
//! ## Example
//!
//! The following module can be tested in two ways:
//!
//! ```sh
//! $ cargo test
//! $ cargo test --features loomy/enable
//! ```
//!
//! When `loomy/enable` is set, then the code will be tested as a loomy model,
//! otherwise all types default to their `std` equivalents, and the code will be
//! tested as normal.
//!
//! ```rust
//! // Note the use of `loomy` instead of `std` or `loom`.
//! use loomy::{
//! hint,
//! cell::UnsafeCell,
//! sync::atomic::{AtomicBool, Ordering},
//! };
//!
//! pub struct SpinLock<T> {
//! flag: AtomicBool,
//! data: UnsafeCell<T>,
//! }
//!
//! unsafe impl<T> Send for SpinLock<T> {}
//! unsafe impl<T> Sync for SpinLock<T> {}
//!
//! impl<T> SpinLock<T> {
//! pub fn new(t: T) -> Self {
//! Self {
//! flag: AtomicBool::new(false),
//! data: UnsafeCell::new(t),
//! }
//! }
//!
//! pub fn with<R, F: FnOnce(&mut T) -> R>(&self, f: F) -> R {
//! while let Err(_) = self
//! .flag
//! .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
//! {
//! hint::spin_loop()
//! }
//!
//! let out = self.data.with_mut(move |t| unsafe { f(&mut *t) });
//! self.flag.store(false, Ordering::Release);
//! out
//! }
//! }
//!
//! #[cfg(test)]
//! mod tests {
//! # }
//! // Also using `loomy` instead of `loom` or `std`.
//! use loomy::{thread, sync::Arc};
//! # mod tmp {
//! use super::*;
//! # }
//!
//! #[test]
//! # fn mock() {}
//! fn test_simple() {
//! loomy::model(|| {
//! let lock = Arc::new(SpinLock::new(123));
//! let lock2 = Arc::clone(&lock);
//!
//! let t = thread::spawn(move || {
//! lock2.with(|n| *n += 1);
//! });
//!
//! lock.with(|n| *n = 456);
//!
//! let out = lock.with(|n| *n);
//!
//! t.join().unwrap();
//!
//! assert!(out == 456 || out == 457);
//! });
//! }
//! # mod dummy {
//! }
//! # test_simple();
//! ```
//!
//! ## A note on `UnsafeCell`
//!
//! `UnsafeCell` in `loom` has a closure-based API. When using `std` types,
//! `UnsafeCell` is wrapped in order to provide the same API.
pub use *;