1 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
2 | |
3 | // ----------------------------------------------------------------------------- |
4 | // Lock-free implementations |
5 | |
6 | #[cfg (not(any( |
7 | all( |
8 | portable_atomic_no_atomic_load_store, |
9 | not(all(target_arch = "bpf" , not(feature = "critical-section" ))), |
10 | ), |
11 | target_arch = "avr" , |
12 | target_arch = "msp430" , |
13 | )))] |
14 | #[cfg_attr ( |
15 | portable_atomic_no_cfg_target_has_atomic, |
16 | cfg(not(all( |
17 | any( |
18 | target_arch = "riscv32" , |
19 | target_arch = "riscv64" , |
20 | feature = "critical-section" , |
21 | portable_atomic_unsafe_assume_single_core, |
22 | ), |
23 | portable_atomic_no_atomic_cas, |
24 | ))) |
25 | )] |
26 | #[cfg_attr ( |
27 | not(portable_atomic_no_cfg_target_has_atomic), |
28 | cfg(not(all( |
29 | any( |
30 | target_arch = "riscv32" , |
31 | target_arch = "riscv64" , |
32 | feature = "critical-section" , |
33 | portable_atomic_unsafe_assume_single_core, |
34 | ), |
35 | not(target_has_atomic = "ptr" ), |
36 | ))) |
37 | )] |
38 | mod core_atomic; |
39 | |
40 | // AVR |
41 | #[cfg (target_arch = "avr" )] |
42 | #[cfg (not(portable_atomic_no_asm))] |
43 | #[cfg (not(feature = "critical-section" ))] |
44 | mod avr; |
45 | |
46 | // MSP430 |
47 | #[cfg (target_arch = "msp430" )] |
48 | pub(crate) mod msp430; |
49 | |
50 | // RISC-V without A-extension |
51 | #[cfg (any(test, not(feature = "critical-section" )))] |
52 | #[cfg_attr ( |
53 | portable_atomic_no_cfg_target_has_atomic, |
54 | cfg(any( |
55 | all(test, not(any(miri, portable_atomic_sanitize_thread))), |
56 | portable_atomic_no_atomic_cas, |
57 | )) |
58 | )] |
59 | #[cfg_attr ( |
60 | not(portable_atomic_no_cfg_target_has_atomic), |
61 | cfg(any( |
62 | all(test, not(any(miri, portable_atomic_sanitize_thread))), |
63 | not(target_has_atomic = "ptr" ), |
64 | )) |
65 | )] |
66 | #[cfg (any(target_arch = "riscv32" , target_arch = "riscv64" ))] |
67 | mod riscv; |
68 | |
69 | // x86-specific optimizations |
70 | // Miri and Sanitizer do not support inline assembly. |
71 | #[cfg (all( |
72 | any(target_arch = "x86" , target_arch = "x86_64" ), |
73 | not(any(miri, portable_atomic_sanitize_thread)), |
74 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
75 | ))] |
76 | mod x86; |
77 | |
78 | // 64-bit atomic implementations on 32-bit architectures |
79 | #[cfg (any(target_arch = "arm" , target_arch = "riscv32" ))] |
80 | mod atomic64; |
81 | |
82 | // 128-bit atomic implementations on 64-bit architectures |
83 | #[cfg (any( |
84 | target_arch = "aarch64" , |
85 | target_arch = "arm64ec" , |
86 | target_arch = "powerpc64" , |
87 | target_arch = "riscv64" , |
88 | target_arch = "s390x" , |
89 | target_arch = "x86_64" , |
90 | ))] |
91 | mod atomic128; |
92 | |
93 | // ----------------------------------------------------------------------------- |
94 | // Lock-based fallback implementations |
95 | |
96 | #[cfg (feature = "fallback" )] |
97 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))] |
98 | #[cfg_attr (not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr" ))] |
99 | #[cfg (any( |
100 | test, |
101 | not(any( |
102 | all( |
103 | target_arch = "aarch64" , |
104 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
105 | ), |
106 | all(target_arch = "arm64ec" , not(portable_atomic_no_asm)), |
107 | all( |
108 | target_arch = "x86_64" , |
109 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
110 | any(target_feature = "cmpxchg16b" , portable_atomic_target_feature = "cmpxchg16b" ), |
111 | ), |
112 | all( |
113 | target_arch = "riscv64" , |
114 | not(any(miri, portable_atomic_sanitize_thread)), |
115 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
116 | any(target_feature = "zacas" , portable_atomic_target_feature = "zacas" ), |
117 | ), |
118 | all( |
119 | target_arch = "powerpc64" , |
120 | portable_atomic_unstable_asm_experimental_arch, |
121 | any( |
122 | target_feature = "quadword-atomics" , |
123 | portable_atomic_target_feature = "quadword-atomics" , |
124 | ), |
125 | ), |
126 | all(target_arch = "s390x" , not(portable_atomic_no_asm)), |
127 | )) |
128 | ))] |
129 | mod fallback; |
130 | |
131 | // ----------------------------------------------------------------------------- |
132 | // Critical section based fallback implementations |
133 | |
134 | // On AVR, we always use critical section based fallback implementation. |
135 | // AVR can be safely assumed to be single-core, so this is sound. |
136 | // MSP430 as well. |
137 | // See the module-level comments of interrupt module for more. |
138 | #[cfg (any( |
139 | all(test, target_os = "none" ), |
140 | portable_atomic_unsafe_assume_single_core, |
141 | feature = "critical-section" , |
142 | target_arch = "avr" , |
143 | target_arch = "msp430" , |
144 | ))] |
145 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(any(test, portable_atomic_no_atomic_cas)))] |
146 | #[cfg_attr ( |
147 | not(portable_atomic_no_cfg_target_has_atomic), |
148 | cfg(any(test, not(target_has_atomic = "ptr" ))) |
149 | )] |
150 | #[cfg (any( |
151 | target_arch = "arm" , |
152 | target_arch = "avr" , |
153 | target_arch = "msp430" , |
154 | target_arch = "riscv32" , |
155 | target_arch = "riscv64" , |
156 | target_arch = "xtensa" , |
157 | feature = "critical-section" , |
158 | ))] |
159 | mod interrupt; |
160 | |
161 | // ----------------------------------------------------------------------------- |
162 | // Atomic float implementations |
163 | |
164 | #[cfg (feature = "float" )] |
165 | pub(crate) mod float; |
166 | |
167 | // ----------------------------------------------------------------------------- |
168 | |
169 | // has CAS | (has core atomic & !(avr | msp430 | critical section)) => core atomic |
170 | #[cfg (not(any( |
171 | portable_atomic_no_atomic_load_store, |
172 | target_arch = "avr" , |
173 | target_arch = "msp430" , |
174 | )))] |
175 | #[cfg_attr ( |
176 | portable_atomic_no_cfg_target_has_atomic, |
177 | cfg(not(all( |
178 | any( |
179 | target_arch = "riscv32" , |
180 | target_arch = "riscv64" , |
181 | feature = "critical-section" , |
182 | portable_atomic_unsafe_assume_single_core, |
183 | ), |
184 | portable_atomic_no_atomic_cas, |
185 | ))) |
186 | )] |
187 | #[cfg_attr ( |
188 | not(portable_atomic_no_cfg_target_has_atomic), |
189 | cfg(not(all( |
190 | any( |
191 | target_arch = "riscv32" , |
192 | target_arch = "riscv64" , |
193 | feature = "critical-section" , |
194 | portable_atomic_unsafe_assume_single_core, |
195 | ), |
196 | not(target_has_atomic = "ptr" ), |
197 | ))) |
198 | )] |
199 | items! { |
200 | pub(crate) use self::core_atomic::{ |
201 | AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32, AtomicU8, |
202 | AtomicUsize, |
203 | }; |
204 | #[cfg_attr ( |
205 | portable_atomic_no_cfg_target_has_atomic, |
206 | cfg(any( |
207 | not(portable_atomic_no_atomic_64), |
208 | not(any(target_pointer_width = "16" , target_pointer_width = "32" )), |
209 | )) |
210 | )] |
211 | #[cfg_attr ( |
212 | not(portable_atomic_no_cfg_target_has_atomic), |
213 | cfg(any( |
214 | target_has_atomic = "64" , |
215 | not(any(target_pointer_width = "16" , target_pointer_width = "32" )), |
216 | )) |
217 | )] |
218 | pub(crate) use self::core_atomic::{AtomicI64, AtomicU64}; |
219 | } |
220 | // bpf & !(critical section) => core atomic |
221 | #[cfg (all( |
222 | target_arch = "bpf" , |
223 | portable_atomic_no_atomic_load_store, |
224 | not(feature = "critical-section" ), |
225 | ))] |
226 | pub(crate) use self::core_atomic::{AtomicI64, AtomicIsize, AtomicPtr, AtomicU64, AtomicUsize}; |
227 | |
228 | // RISC-V without A-extension & !(assume single core | critical section) |
229 | #[cfg (not(any(portable_atomic_unsafe_assume_single_core, feature = "critical-section" )))] |
230 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(portable_atomic_no_atomic_cas))] |
231 | #[cfg_attr (not(portable_atomic_no_cfg_target_has_atomic), cfg(not(target_has_atomic = "ptr" )))] |
232 | #[cfg (any(target_arch = "riscv32" , target_arch = "riscv64" ))] |
233 | items! { |
234 | pub(crate) use self::riscv::{ |
235 | AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32, AtomicU8, |
236 | AtomicUsize, |
237 | }; |
238 | #[cfg(target_arch = "riscv64" )] |
239 | pub(crate) use self::riscv::{AtomicI64, AtomicU64}; |
240 | } |
241 | |
242 | // no core atomic CAS & (assume single core | critical section) => critical section based fallback |
243 | #[cfg (any( |
244 | portable_atomic_unsafe_assume_single_core, |
245 | feature = "critical-section" , |
246 | target_arch = "avr" , |
247 | target_arch = "msp430" , |
248 | ))] |
249 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(portable_atomic_no_atomic_cas))] |
250 | #[cfg_attr (not(portable_atomic_no_cfg_target_has_atomic), cfg(not(target_has_atomic = "ptr" )))] |
251 | items! { |
252 | pub(crate) use self::interrupt::{ |
253 | AtomicI16, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU8, AtomicUsize, |
254 | }; |
255 | #[cfg(any(not(target_pointer_width = "16" ), feature = "fallback" ))] |
256 | pub(crate) use self::interrupt::{AtomicI32, AtomicU32}; |
257 | #[cfg(any( |
258 | not(any(target_pointer_width = "16" , target_pointer_width = "32" )), |
259 | feature = "fallback" , |
260 | ))] |
261 | pub(crate) use self::interrupt::{AtomicI64, AtomicU64}; |
262 | #[cfg(feature = "fallback" )] |
263 | pub(crate) use self::interrupt::{AtomicI128, AtomicU128}; |
264 | } |
265 | |
266 | // no core (64-bit | 128-bit) atomic & has CAS => use lock-base fallback |
267 | #[cfg (feature = "fallback" )] |
268 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))] |
269 | #[cfg_attr (not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr" ))] |
270 | items! { |
271 | #[cfg (not(any( |
272 | all( |
273 | target_arch = "arm" , |
274 | not(any(miri, portable_atomic_sanitize_thread)), |
275 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
276 | any(target_os = "linux" , target_os = "android" ), |
277 | not(any(target_feature = "v6" , portable_atomic_target_feature = "v6" )), |
278 | not(portable_atomic_no_outline_atomics), |
279 | ), |
280 | all( |
281 | target_arch = "riscv32" , |
282 | not(any(miri, portable_atomic_sanitize_thread)), |
283 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
284 | any( |
285 | target_feature = "zacas" , |
286 | portable_atomic_target_feature = "zacas" , |
287 | all( |
288 | feature = "fallback" , |
289 | not(portable_atomic_no_outline_atomics), |
290 | any(target_os = "linux" , target_os = "android" ), |
291 | ), |
292 | ), |
293 | ), |
294 | )))] |
295 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(portable_atomic_no_atomic_64))] |
296 | #[cfg_attr (not(portable_atomic_no_cfg_target_has_atomic), cfg(not(target_has_atomic = "64" )))] |
297 | pub(crate) use self::fallback::{AtomicI64, AtomicU64}; |
298 | #[cfg (not(any( |
299 | all( |
300 | target_arch = "aarch64" , |
301 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
302 | ), |
303 | all(target_arch = "arm64ec" , not(portable_atomic_no_asm)), |
304 | all( |
305 | target_arch = "x86_64" , |
306 | not(all( |
307 | any(miri, portable_atomic_sanitize_thread), |
308 | portable_atomic_no_cmpxchg16b_intrinsic, |
309 | )), |
310 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
311 | any( |
312 | target_feature = "cmpxchg16b" , |
313 | portable_atomic_target_feature = "cmpxchg16b" , |
314 | all( |
315 | feature = "fallback" , |
316 | not(portable_atomic_no_outline_atomics), |
317 | not(any(target_env = "sgx" , miri)), |
318 | ), |
319 | ), |
320 | ), |
321 | all( |
322 | target_arch = "riscv64" , |
323 | not(any(miri, portable_atomic_sanitize_thread)), |
324 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
325 | any( |
326 | target_feature = "zacas" , |
327 | portable_atomic_target_feature = "zacas" , |
328 | all( |
329 | feature = "fallback" , |
330 | not(portable_atomic_no_outline_atomics), |
331 | any(target_os = "linux" , target_os = "android" ), |
332 | ), |
333 | ), |
334 | ), |
335 | all( |
336 | target_arch = "powerpc64" , |
337 | portable_atomic_unstable_asm_experimental_arch, |
338 | any( |
339 | target_feature = "quadword-atomics" , |
340 | portable_atomic_target_feature = "quadword-atomics" , |
341 | all( |
342 | feature = "fallback" , |
343 | not(portable_atomic_no_outline_atomics), |
344 | any( |
345 | all( |
346 | target_os = "linux" , |
347 | any( |
348 | all( |
349 | target_env = "gnu" , |
350 | any(target_endian = "little" , not(target_feature = "crt-static" )), |
351 | ), |
352 | all( |
353 | any(target_env = "musl" , target_env = "ohos" , target_env = "uclibc" ), |
354 | not(target_feature = "crt-static" ), |
355 | ), |
356 | portable_atomic_outline_atomics, |
357 | ), |
358 | ), |
359 | target_os = "android" , |
360 | target_os = "freebsd" , |
361 | target_os = "openbsd" , |
362 | all( |
363 | target_os = "aix" , |
364 | not(portable_atomic_pre_llvm_20), |
365 | portable_atomic_outline_atomics, // TODO(aix): currently disabled by default |
366 | ), |
367 | ), |
368 | not(any(miri, portable_atomic_sanitize_thread)), |
369 | ), |
370 | ), |
371 | ), |
372 | all(target_arch = "s390x" , not(portable_atomic_no_asm)), |
373 | )))] |
374 | pub(crate) use self::fallback::{AtomicI128, AtomicU128}; |
375 | } |
376 | |
377 | // 64-bit atomics (platform-specific) |
378 | // pre-v6 Arm Linux |
379 | #[cfg (feature = "fallback" )] |
380 | #[cfg (all( |
381 | target_arch = "arm" , |
382 | not(any(miri, portable_atomic_sanitize_thread)), |
383 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
384 | any(target_os = "linux" , target_os = "android" ), |
385 | not(any(target_feature = "v6" , portable_atomic_target_feature = "v6" )), |
386 | not(portable_atomic_no_outline_atomics), |
387 | ))] |
388 | #[cfg_attr (portable_atomic_no_cfg_target_has_atomic, cfg(portable_atomic_no_atomic_64))] |
389 | #[cfg_attr (not(portable_atomic_no_cfg_target_has_atomic), cfg(not(target_has_atomic = "64" )))] |
390 | pub(crate) use self::atomic64::arm_linux::{AtomicI64, AtomicU64}; |
391 | // riscv32 & (zacas | outline-atomics) |
392 | #[cfg (all( |
393 | target_arch = "riscv32" , |
394 | not(any(miri, portable_atomic_sanitize_thread)), |
395 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
396 | any( |
397 | target_feature = "zacas" , |
398 | portable_atomic_target_feature = "zacas" , |
399 | all( |
400 | feature = "fallback" , |
401 | not(portable_atomic_no_outline_atomics), |
402 | any(target_os = "linux" , target_os = "android" ), |
403 | ), |
404 | ), |
405 | ))] |
406 | pub(crate) use self::atomic64::riscv32::{AtomicI64, AtomicU64}; |
407 | |
408 | // 128-bit atomics (platform-specific) |
409 | // AArch64 |
410 | #[cfg (any( |
411 | all(target_arch = "aarch64" , any(not(portable_atomic_no_asm), portable_atomic_unstable_asm)), |
412 | all(target_arch = "arm64ec" , not(portable_atomic_no_asm)) |
413 | ))] |
414 | pub(crate) use self::atomic128::aarch64::{AtomicI128, AtomicU128}; |
415 | // x86_64 & (cmpxchg16b | outline-atomics) |
416 | #[cfg (all( |
417 | target_arch = "x86_64" , |
418 | not(all(any(miri, portable_atomic_sanitize_thread), portable_atomic_no_cmpxchg16b_intrinsic)), |
419 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
420 | any( |
421 | target_feature = "cmpxchg16b" , |
422 | portable_atomic_target_feature = "cmpxchg16b" , |
423 | all( |
424 | feature = "fallback" , |
425 | not(portable_atomic_no_outline_atomics), |
426 | not(any(target_env = "sgx" , miri)), |
427 | ), |
428 | ), |
429 | ))] |
430 | pub(crate) use self::atomic128::x86_64::{AtomicI128, AtomicU128}; |
431 | // riscv64 & (zacas | outline-atomics) |
432 | #[cfg (all( |
433 | target_arch = "riscv64" , |
434 | not(any(miri, portable_atomic_sanitize_thread)), |
435 | any(not(portable_atomic_no_asm), portable_atomic_unstable_asm), |
436 | any( |
437 | target_feature = "zacas" , |
438 | portable_atomic_target_feature = "zacas" , |
439 | all( |
440 | feature = "fallback" , |
441 | not(portable_atomic_no_outline_atomics), |
442 | any(target_os = "linux" , target_os = "android" ), |
443 | ), |
444 | ), |
445 | ))] |
446 | pub(crate) use self::atomic128::riscv64::{AtomicI128, AtomicU128}; |
447 | // powerpc64 & (pwr8 | outline-atomics) |
448 | #[cfg (all( |
449 | target_arch = "powerpc64" , |
450 | portable_atomic_unstable_asm_experimental_arch, |
451 | any( |
452 | target_feature = "quadword-atomics" , |
453 | portable_atomic_target_feature = "quadword-atomics" , |
454 | all( |
455 | feature = "fallback" , |
456 | not(portable_atomic_no_outline_atomics), |
457 | any( |
458 | all( |
459 | target_os = "linux" , |
460 | any( |
461 | all( |
462 | target_env = "gnu" , |
463 | any(target_endian = "little" , not(target_feature = "crt-static" )), |
464 | ), |
465 | all( |
466 | any(target_env = "musl" , target_env = "ohos" , target_env = "uclibc" ), |
467 | not(target_feature = "crt-static" ), |
468 | ), |
469 | portable_atomic_outline_atomics, |
470 | ), |
471 | ), |
472 | target_os = "android" , |
473 | target_os = "freebsd" , |
474 | target_os = "openbsd" , |
475 | all( |
476 | target_os = "aix" , |
477 | not(portable_atomic_pre_llvm_20), |
478 | portable_atomic_outline_atomics, // TODO(aix): currently disabled by default |
479 | ), |
480 | ), |
481 | not(any(miri, portable_atomic_sanitize_thread)), |
482 | ), |
483 | ), |
484 | ))] |
485 | pub(crate) use self::atomic128::powerpc64::{AtomicI128, AtomicU128}; |
486 | // s390x |
487 | #[cfg (all(target_arch = "s390x" , not(portable_atomic_no_asm)))] |
488 | pub(crate) use self::atomic128::s390x::{AtomicI128, AtomicU128}; |
489 | |