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), not(feature = "std")))]
44const MAX_SPINLOOP: usize = 1024;
45
46pub(crate) struct Backoff {
47 #[cfg(all(not(shuttle), not(loom), not(feature = "std")))]
48 state: usize,
49}
50
51impl Backoff {
52 pub fn new() -> Self {
53 #[cfg(all(not(shuttle), not(loom), not(feature = "std")))]
54 return Self { state: 1 };
55 #[cfg(any(shuttle, loom, feature = "std"))]
56 return Self {};
57 }
58
59 pub fn backoff(&mut self) {
60 #[cfg(all(not(shuttle), not(loom), not(feature = "std")))]
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, feature = "std"))]
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 pub trait Sealed {}
87}
88
89macro_rules! pack {
93 (($upper:expr, $lower:expr): $width:expr) => {
94 (($upper) << $width) | ($lower)
95 };
96}
97
98macro_rules! unpack {
102 (($packed:expr): $width:expr) => {{
103 let width = $width;
105 let packed_value = $packed;
106 let upper = packed_value >> width;
107 let lower = packed_value & ((1 << width) - 1);
108 (upper, lower)
109 }};
110}
111
112#[cfg(test)]
113pub(crate) fn sign_erase(ptr: u64) -> u64 {
114 ptr & ((1u64 << 48) - 1)
115}
116
117pub(crate) fn sign_extend(ptr: u64) -> u64 {
118 if ptr & (1u64 << 47) != 0 {
119 ptr | (!((1u64 << 48) - 1))
120 } else {
121 ptr
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 mod tagged_ptr {
130 use core::ptr::null;
131
132 use super::{sign_erase, sign_extend};
133
134 #[test]
135 fn into_tagged() {
136 let ptr = u64::MAX as *const u8;
137 let count = 0xDEAD;
138 let res = pack!((count, sign_erase(ptr as u64)): 48);
139 assert_eq!(res, 0xDEAD_FFFF_FFFF_FFFF);
140
141 let ptr2 = 0xDEAD_BEEF as *const u8;
142 let res = pack!((count, sign_erase(ptr2 as u64)): 48);
143 assert_eq!(res, 0xDEAD_0000_DEAD_BEEF);
144
145 let ptr: *const u8 = null();
146 assert_eq!(pack!((0, ptr as u64): 48), 0);
147 }
148
149 #[test]
150 fn from_tagged() {
151 let ptr = u64::MAX as *const u8;
152 let count = 0xDEAD;
153 let res = 0xDEAD_FFFF_FFFF_FFFF;
154
155 let (v1, v2) = unpack!((res): 48);
156
157 assert_eq!((v1, sign_extend(v2)), (count, ptr as u64));
158
159 let ptr2 = 0xDEAD_BEEF as *const u8;
160 let res = 0xDEAD_0000_DEAD_BEEF;
161
162 let (v1, v2) = unpack!((res): 48);
163
164 assert_eq!((v1, sign_extend(v2)), (count, ptr2 as u64));
165
166 let ptr: *const u8 = null();
167 assert_eq!(unpack!((0_u64): 48), (0, ptr as u64))
168 }
169
170 #[test]
171 fn tagged() {
172 let ptr = u64::MAX as *const u8;
173 let ptr2 = 0xDEAD_BEEF as *const u8;
174 let count = 0xDEAD;
175
176 let (v1, v2) = unpack!((pack!((count, sign_erase(ptr as u64)): 48)): 48);
177
178 assert_eq!((v1, sign_extend(v2)), (count, ptr as u64));
179
180 let (v1, v2) = unpack!((pack!((count, sign_erase(ptr2 as u64)): 48)): 48);
181
182 assert_eq!((v1, sign_extend(v2)), (count, ptr2 as u64));
183
184 let data = &4242;
185 let count = 42;
186 let ptr = pack!((count, data as *const i32 as u64): 48);
187 let (count_, data_): (_, u64) = unpack!((ptr): 48);
188 assert_eq!(count, count_);
189 assert_eq!(*data, unsafe { *(sign_extend(data_) as *const i32) });
192 }
193 }
194
195 mod dword {
196 use core::ptr::null;
197
198 #[test]
199 fn into_dword() {
200 let ptr = u64::MAX as *const u8;
201 let count = 0xDEAD;
202 let res = pack!((count, ptr as u128): 64);
203 assert_eq!(res, 0xDEAD_u128 << 64 | u64::MAX as u128);
204
205 let ptr2 = 0xDEAD_BEEF as *const u8;
206 let res = pack!((count, ptr2 as u128): 64);
207 assert_eq!(res, 0xDEAD_u128 << 64 | 0xDEAD_BEEF_u128);
208
209 let ptr: *const u8 = null();
210 assert_eq!(pack!((0, ptr as u128): 64), 0);
211 }
212
213 #[test]
214 fn from_dword() {
215 let ptr = u64::MAX as *const u8;
216 let count = 0xDEAD;
217 let res = 0xDEAD_u128 << 64 | u64::MAX as u128;
218
219 assert_eq!(unpack!((res): 64), (count, ptr as u128));
220
221 let ptr2 = 0xDEAD_BEEF as *const u8;
222 let res = 0xDEAD_u128 << 64 | 0xDEAD_BEEF_u128;
223
224 assert_eq!(unpack!((res): 64), (count, ptr2 as u128));
225
226 let ptr: *const u8 = null();
227 assert_eq!(unpack!((0_u128): 64), (0, ptr as u128));
228 }
229
230 #[test]
231 fn dword() {
232 let ptr = u64::MAX as *const u8;
233 let ptr2 = 0xDEAD_BEEF as *const u8;
234 let count = 0xDEAD;
235
236 assert_eq!(
237 unpack!((pack!((count, ptr as u128): 64)): 64),
238 (count, ptr as u128)
239 );
240 assert_eq!(
241 unpack!((pack!((count, ptr2 as u128): 64)): 64),
242 (count, ptr2 as u128)
243 );
244
245 let data = &4242;
246 let count = 42;
247 let val = pack!((count, data as *const i32 as *const u8 as u128): 64);
248 let (count_, data_): (_, u128) = unpack!((val): 64);
249 assert_eq!(count, count_);
250 assert_eq!(unsafe { *(data_ as *const i32) }, *data);
253 }
254 }
255
256 #[test]
257 fn prev_() {
258 assert_eq!(prev(9, 10), 8);
259 assert_eq!(prev(0, 5), 4);
260 }
261
262 #[test]
263 fn comp_() {
264 assert!(comp(0, 0, 1, 0, u16::MAX as u64 + 1));
267 assert!(!comp(1, 1, 0, 1, u16::MAX as u64 + 1));
268
269 assert!(comp(0, 1, 1, 2, u16::MAX as u64 + 1));
272 assert!(!comp(0, 1, 1, 0, u16::MAX as u64 + 1));
273 assert!(comp(0, u16::MAX as u64, 1, 0, u16::MAX as u64 + 1));
274 }
275}