1#[macro_export]
12macro_rules! cfg_atomic_tagged64 {
13 ($($item:item)*) => {
14 $(
15 #[cfg(any(target_has_atomic = "64", feature = "atomic-fallback"))]
16 $item
17 )*
18 };
19}
20
21#[macro_export]
32macro_rules! cfg_atomic_tagged128 {
33 ($($item:item)*) => {
34 $(
35 #[cfg(any(target_has_atomic = "128", all(feature = "atomic-fallback", not(loom), not(shuttle))))]
36 $item
37 )*
38 };
39}
40
41pub(crate) use sealed::Sealed;
42
43#[cfg(all(not(shuttle), not(loom)))]
44const MAX_SPINLOOP: usize = 1024;
45
46pub(crate) struct Backoff {
47 #[cfg(all(not(shuttle), not(loom)))]
48 state: usize,
49}
50
51impl Backoff {
52 pub(crate) fn new() -> Self {
53 #[cfg(all(not(shuttle), not(loom)))]
54 return Self { state: 1 };
55 #[cfg(any(shuttle, loom))]
56 return Self {};
57 }
58
59 pub(crate) fn backoff(&mut self) {
60 #[cfg(all(not(shuttle), not(loom)))]
61 {
62 for _ in 0..self.state {
63 crate::sync::hint::spin_loop();
64 }
65 self.state = (self.state * 2).min(MAX_SPINLOOP);
66 }
67 #[cfg(any(shuttle, loom))]
68 crate::sync::thread::yield_now();
69 }
70}
71
72pub(crate) fn prev(i: usize, size: usize) -> usize {
73 (i + size - 1) % size
74}
75
76pub(crate) fn comp(i: usize, u: u64, j: usize, v: u64, w_max: u64) -> bool {
77 if u == v {
78 i < j
79 } else {
80 (v.wrapping_add(w_max).wrapping_sub(u)) % w_max < w_max / 2
81 }
82}
83
84pub(crate) mod sealed {
85 #[doc(hidden)]
86 #[allow(unnameable_types)]
87 pub trait Sealed {}
88}
89
90macro_rules! pack {
94 (($upper:expr, $lower:expr): $width:expr) => {
95 (($upper) << $width) | ($lower)
96 };
97}
98
99macro_rules! unpack {
103 (($packed:expr): $width:expr) => {{
104 let width = $width;
106 let packed_value = $packed;
107 let upper = packed_value >> width;
108 let lower = packed_value & ((1 << width) - 1);
109 (upper, lower)
110 }};
111}
112
113#[cfg(test)]
114pub(crate) fn sign_erase(ptr: u64) -> u64 {
115 ptr & ((1u64 << 48) - 1)
116}
117
118pub(crate) fn sign_extend(ptr: u64) -> u64 {
119 if ptr & (1u64 << 47) != 0 {
120 ptr | (!((1u64 << 48) - 1))
121 } else {
122 ptr
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 mod tagged_ptr {
131 use core::ptr::null;
132
133 use super::{sign_erase, sign_extend};
134
135 #[test]
136 fn into_tagged() {
137 let ptr = u64::MAX as *const u8;
138 let count = 0xDEAD;
139 let res = pack!((count, sign_erase(ptr as u64)): 48);
140 assert_eq!(res, 0xDEAD_FFFF_FFFF_FFFF);
141
142 let ptr2 = 0xDEAD_BEEF as *const u8;
143 let res = pack!((count, sign_erase(ptr2 as u64)): 48);
144 assert_eq!(res, 0xDEAD_0000_DEAD_BEEF);
145
146 let ptr: *const u8 = null();
147 assert_eq!(pack!((0, ptr as u64): 48), 0);
148 }
149
150 #[test]
151 fn from_tagged() {
152 let ptr = u64::MAX as *const u8;
153 let count = 0xDEAD;
154 let res = 0xDEAD_FFFF_FFFF_FFFF;
155
156 let (v1, v2) = unpack!((res): 48);
157
158 assert_eq!((v1, sign_extend(v2)), (count, ptr as u64));
159
160 let ptr2 = 0xDEAD_BEEF as *const u8;
161 let res = 0xDEAD_0000_DEAD_BEEF;
162
163 let (v1, v2) = unpack!((res): 48);
164
165 assert_eq!((v1, sign_extend(v2)), (count, ptr2 as u64));
166
167 let ptr: *const u8 = null();
168 assert_eq!(unpack!((0_u64): 48), (0, ptr as u64));
169 }
170
171 #[test]
172 fn tagged() {
173 let ptr = u64::MAX as *const u8;
174 let ptr2 = 0xDEAD_BEEF as *const u8;
175 let count = 0xDEAD;
176
177 let (v1, v2) = unpack!((pack!((count, sign_erase(ptr as u64)): 48)): 48);
178
179 assert_eq!((v1, sign_extend(v2)), (count, ptr as u64));
180
181 let (v1, v2) = unpack!((pack!((count, sign_erase(ptr2 as u64)): 48)): 48);
182
183 assert_eq!((v1, sign_extend(v2)), (count, ptr2 as u64));
184
185 let data = &4242;
186 let count = 42;
187 let ptr = pack!((count, data as *const i32 as u64): 48);
188 let (count_, data_): (_, u64) = unpack!((ptr): 48);
189 assert_eq!(count, count_);
190 assert_eq!(*data, unsafe { *(sign_extend(data_) as *const i32) });
193 }
194 }
195
196 mod dword {
197 use core::ptr::null;
198
199 #[test]
200 fn into_dword() {
201 let ptr = u64::MAX as *const u8;
202 let count = 0xDEAD;
203 let res = pack!((count, ptr as u128): 64);
204 assert_eq!(res, 0xDEAD_u128 << 64 | u64::MAX as u128);
205
206 let ptr2 = 0xDEAD_BEEF as *const u8;
207 let res = pack!((count, ptr2 as u128): 64);
208 assert_eq!(res, 0xDEAD_u128 << 64 | 0xDEAD_BEEF_u128);
209
210 let ptr: *const u8 = null();
211 assert_eq!(pack!((0, ptr as u128): 64), 0);
212 }
213
214 #[test]
215 fn from_dword() {
216 let ptr = u64::MAX as *const u8;
217 let count = 0xDEAD;
218 let res = 0xDEAD_u128 << 64 | u64::MAX as u128;
219
220 assert_eq!(unpack!((res): 64), (count, ptr as u128));
221
222 let ptr2 = 0xDEAD_BEEF as *const u8;
223 let res = 0xDEAD_u128 << 64 | 0xDEAD_BEEF_u128;
224
225 assert_eq!(unpack!((res): 64), (count, ptr2 as u128));
226
227 let ptr: *const u8 = null();
228 assert_eq!(unpack!((0_u128): 64), (0, ptr as u128));
229 }
230
231 #[test]
232 fn dword() {
233 let ptr = u64::MAX as *const u8;
234 let ptr2 = 0xDEAD_BEEF as *const u8;
235 let count = 0xDEAD;
236
237 assert_eq!(
238 unpack!((pack!((count, ptr as u128): 64)): 64),
239 (count, ptr as u128)
240 );
241 assert_eq!(
242 unpack!((pack!((count, ptr2 as u128): 64)): 64),
243 (count, ptr2 as u128)
244 );
245
246 let data = &4242;
247 let count = 42;
248 let val = pack!((count, (data as *const i32).cast::<u8>() as u128): 64);
249 let (count_, data_): (_, u128) = unpack!((val): 64);
250 assert_eq!(count, count_);
251 assert_eq!(unsafe { *(data_ as *const i32) }, *data);
254 }
255 }
256
257 #[test]
258 fn prev_() {
259 assert_eq!(prev(9, 10), 8);
260 assert_eq!(prev(0, 5), 4);
261 }
262
263 #[test]
264 fn comp_() {
265 assert!(comp(0, 0, 1, 0, u16::MAX as u64 + 1));
268 assert!(!comp(1, 1, 0, 1, u16::MAX as u64 + 1));
269
270 assert!(comp(0, 1, 1, 2, u16::MAX as u64 + 1));
273 assert!(!comp(0, 1, 1, 0, u16::MAX as u64 + 1));
274 assert!(comp(0, u16::MAX as u64, 1, 0, u16::MAX as u64 + 1));
275 }
276}