1#![allow(unused_imports)]
2
3use core::sync::atomic::{
4 AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicIsize, AtomicPtr, AtomicU8, AtomicU16,
5 AtomicU32, AtomicUsize, Ordering,
6};
7
8#[cfg(target_has_atomic = "64")]
9use core::sync::atomic::{AtomicI64, AtomicU64};
10
11use super::modes::*;
12use super::pervasive::*;
13use super::prelude::*;
14use super::raw_ptr::PointsTo;
15use super::view::*;
16use super::wrapping::*;
17
18macro_rules! make_unsigned_integer_atomic {
19 ($at_ident:ident, $p_ident:ident, $p_data_ident:ident, $rust_ty: ty, $value_ty: ty, $modname:ident) => {
20 atomic_types!($at_ident, $p_ident, $p_data_ident, $rust_ty, $value_ty);
21 #[cfg_attr(verus_keep_ghost, verus::internal(verus_macro))]
22 impl $at_ident {
23 atomic_common_methods!($at_ident, $p_ident, $p_data_ident, $rust_ty, $value_ty, []);
24 atomic_integer_methods!($at_ident, $p_ident, $rust_ty, $value_ty, $modname);
25 }
26 };
27}
28
29macro_rules! make_signed_integer_atomic {
30 ($at_ident:ident, $p_ident:ident, $p_data_ident:ident, $rust_ty: ty, $value_ty: ty, $modname:ident) => {
31 atomic_types!($at_ident, $p_ident, $p_data_ident, $rust_ty, $value_ty);
32 #[cfg_attr(verus_keep_ghost, verus::internal(verus_macro))]
33 impl $at_ident {
34 atomic_common_methods!($at_ident, $p_ident, $p_data_ident, $rust_ty, $value_ty, []);
35 atomic_integer_methods!($at_ident, $p_ident, $rust_ty, $value_ty, $modname);
36 }
37 };
38}
39
40macro_rules! make_bool_atomic {
41 ($at_ident:ident, $p_ident:ident, $p_data_ident:ident, $rust_ty: ty, $value_ty: ty) => {
42 atomic_types!($at_ident, $p_ident, $p_data_ident, $rust_ty, $value_ty);
43 #[cfg_attr(verus_keep_ghost, verus::internal(verus_macro))]
44 impl $at_ident {
45 atomic_common_methods!($at_ident, $p_ident, $p_data_ident, $rust_ty, $value_ty, []);
46 atomic_bool_methods!($at_ident, $p_ident, $rust_ty, $value_ty);
47 }
48 };
49}
50
51macro_rules! atomic_types {
52 ($at_ident:ident, $p_ident:ident, $p_data_ident:ident, $rust_ty: ty, $value_ty: ty) => {
53 verus! {
54
55 #[verifier::external_body] pub struct $at_ident {
57 ato: $rust_ty,
58 }
59
60 #[verifier::external_body] pub tracked struct $p_ident {
62 no_copy: NoCopy,
63 unused: $value_ty,
64 }
65
66 pub ghost struct $p_data_ident {
67 pub patomic: int,
68 pub value: $value_ty,
69 }
70
71 impl $p_ident {
72 #[verifier::external_body] pub uninterp spec fn view(self) -> $p_data_ident;
74
75 pub open spec fn is_for(&self, patomic: $at_ident) -> bool {
76 self.view().patomic == patomic.id()
77 }
78
79 pub open spec fn points_to(&self, v: $value_ty) -> bool {
80 self.view().value == v
81 }
82
83 #[verifier::inline]
84 pub open spec fn value(&self) -> $value_ty {
85 self.view().value
86 }
87
88 #[verifier::inline]
89 pub open spec fn id(&self) -> AtomicCellId {
90 self.view().patomic
91 }
92 }
93
94 }
95 };
96}
97
98macro_rules! atomic_types_generic {
99 ($at_ident:ident, $p_ident:ident, $p_data_ident:ident, $rust_ty: ty, $value_ty: ty) => {
100 verus! {
101
102 #[verifier::accept_recursive_types(T)]
103 #[verifier::external_body] pub struct $at_ident <T> {
105 ato: $rust_ty,
106 }
107
108 #[verifier::accept_recursive_types(T)]
109 #[verifier::external_body] pub tracked struct $p_ident <T> {
111 no_copy: NoCopy,
112 unusued: $value_ty,
113 }
114
115 #[verifier::accept_recursive_types(T)]
116 pub ghost struct $p_data_ident <T> {
117 pub patomic: int,
118 pub value: $value_ty,
119 }
120
121 impl<T> $p_ident <T> {
122 #[verifier::external_body] pub uninterp spec fn view(self) -> $p_data_ident <T>;
124
125 pub open spec fn is_for(&self, patomic: $at_ident <T>) -> bool {
126 self.view().patomic == patomic.id()
127 }
128
129 pub open spec fn points_to(&self, v: $value_ty) -> bool {
130 self.view().value == v
131 }
132
133 #[verifier::inline]
134 pub open spec fn value(&self) -> $value_ty {
135 self.view().value
136 }
137
138 #[verifier::inline]
139 pub open spec fn id(&self) -> AtomicCellId {
140 self.view().patomic
141 }
142 }
143
144 }
145 };
146}
147
148pub type AtomicCellId = int;
149
150macro_rules! atomic_common_methods {
151 ($at_ident: ty, $p_ident: ty, $p_data_ident: ty, $rust_ty: ty, $value_ty: ty, [ $($addr:tt)* ]) => {
152 verus_impl!{
153
154 pub uninterp spec fn id(&self) -> int;
155
156 #[inline(always)]
157 #[verifier::external_body] pub const fn new(i: $value_ty) -> (res: ($at_ident, Tracked<$p_ident>))
159 ensures
160 equal(res.1@.view(), $p_data_ident{ patomic: res.0.id(), value: i }),
161 {
162 let p = $at_ident { ato: <$rust_ty>::new(i) };
163 (p, Tracked::assume_new())
164 }
165
166 #[inline(always)]
167 #[verifier::external_body] #[verifier::atomic] pub fn load(&self, Tracked(perm): Tracked<&$p_ident>) -> (ret: $value_ty)
170 requires
171 equal(self.id(), perm.view().patomic),
172 ensures equal(perm.view().value, ret),
173 opens_invariants none
174 no_unwind
175 {
176 self.ato.load(Ordering::SeqCst)
177 }
178
179 #[inline(always)]
180 #[verifier::external_body] #[verifier::atomic] pub fn store(&self, Tracked(perm): Tracked<&mut $p_ident>, v: $value_ty)
183 requires
184 equal(self.id(), old(perm).view().patomic),
185 ensures equal(final(perm).view().value, v) && equal(self.id(), final(perm).view().patomic),
186 opens_invariants none
187 no_unwind
188 {
189 self.ato.store(v, Ordering::SeqCst)
190 }
191
192 #[inline(always)]
193 #[verifier::external_body] #[verifier::atomic] pub fn compare_exchange(&self, Tracked(perm): Tracked<&mut $p_ident>, current: $value_ty, new: $value_ty) -> (ret: Result<$value_ty, $value_ty>)
196 requires
197 equal(self.id(), old(perm).view().patomic),
198 ensures
199 equal(self.id(), final(perm).view().patomic)
200 && match ret {
201 Result::Ok(r) =>
202 current $($addr)* == old(perm).view().value $($addr)*
203 && equal(final(perm).view().value, new)
204 && equal(r, old(perm).view().value),
205 Result::Err(r) =>
206 current $($addr)* != old(perm).view().value $($addr)*
207 && equal(final(perm).view().value, old(perm).view().value)
208 && equal(r, old(perm).view().value),
209 },
210 opens_invariants none
211 no_unwind
212 {
213 self.ato.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst)
214 }
215
216 #[inline(always)]
217 #[verifier::external_body] #[verifier::atomic] pub fn compare_exchange_weak(&self, Tracked(perm): Tracked<&mut $p_ident>, current: $value_ty, new: $value_ty) -> (ret: Result<$value_ty, $value_ty>)
220 requires
221 equal(self.id(), old(perm).view().patomic),
222 ensures
223 equal(self.id(), final(perm).view().patomic)
224 && match ret {
225 Result::Ok(r) =>
226 current $($addr)* == old(perm).view().value $($addr)*
227 && equal(final(perm).view().value, new)
228 && equal(r, old(perm).view().value),
229 Result::Err(r) =>
230 equal(final(perm).view().value, old(perm).view().value)
231 && equal(r, old(perm).view().value),
232 },
233 opens_invariants none
234 no_unwind
235 {
236 self.ato.compare_exchange_weak(current, new, Ordering::SeqCst, Ordering::SeqCst)
237 }
238
239 #[inline(always)]
240 #[verifier::external_body] #[verifier::atomic] pub fn swap(&self, Tracked(perm): Tracked<&mut $p_ident>, v: $value_ty) -> (ret: $value_ty)
243 requires
244 equal(self.id(), old(perm).view().patomic),
245 ensures
246 equal(final(perm).view().value, v)
247 && equal(old(perm).view().value, ret)
248 && equal(self.id(), final(perm).view().patomic),
249 opens_invariants none
250 no_unwind
251 {
252 self.ato.swap(v, Ordering::SeqCst)
253 }
254
255 #[inline(always)]
256 #[verifier::external_body] pub fn into_inner(self, Tracked(perm): Tracked<$p_ident>) -> (ret: $value_ty)
258 requires
259 equal(self.id(), perm.view().patomic),
260 ensures equal(perm.view().value, ret),
261 opens_invariants none
262 no_unwind
263 {
264 self.ato.into_inner()
265 }
266
267 }
268 };
269}
270
271macro_rules! atomic_integer_methods {
272 ($at_ident:ident, $p_ident:ident, $rust_ty: ty, $value_ty: ty, $modname:ident) => {
273 verus_impl!{
274
275 #[inline(always)]
279 #[verifier::external_body] #[verifier::atomic] pub fn fetch_add_wrapping(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
282 requires equal(self.id(), old(perm).view().patomic),
283 ensures
284 equal(old(perm).view().value, ret),
285 final(perm).view().patomic == old(perm).view().patomic,
286 final(perm).view().value as int == $modname::wrapping_add(old(perm).view().value, n),
287 opens_invariants none
288 no_unwind
289 {
290 self.ato.fetch_add(n, Ordering::SeqCst)
291 }
292
293 #[inline(always)]
294 #[verifier::external_body] #[verifier::atomic] pub fn fetch_sub_wrapping(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
297 requires equal(self.id(), old(perm).view().patomic),
298 ensures
299 equal(old(perm).view().value, ret),
300 final(perm).view().patomic == old(perm).view().patomic,
301 final(perm).view().value as int == $modname::wrapping_sub(old(perm).view().value, n),
302 opens_invariants none
303 no_unwind
304 {
305 self.ato.fetch_sub(n, Ordering::SeqCst)
306 }
307
308 #[inline(always)]
312 #[verifier::atomic] pub fn fetch_add(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
314 requires
315 equal(self.id(), old(perm).view().patomic),
316 (<$value_ty>::MIN as int) <= old(perm).view().value + n,
317 old(perm).view().value + n <= (<$value_ty>::MAX as int),
318 ensures
319 equal(old(perm).view().value, ret),
320 final(perm).view().patomic == old(perm).view().patomic,
321 final(perm).view().value == old(perm).view().value + n,
322 opens_invariants none
323 no_unwind
324 {
325 self.fetch_add_wrapping(Tracked(&mut *perm), n)
326 }
327
328 #[inline(always)]
329 #[verifier::atomic] pub fn fetch_sub(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
331 requires
332 equal(self.id(), old(perm).view().patomic),
333 (<$value_ty>::MIN as int) <= old(perm).view().value - n,
334 old(perm).view().value - n <= <$value_ty>::MAX as int,
335 ensures
336 equal(old(perm).view().value, ret),
337 final(perm).view().patomic == old(perm).view().patomic,
338 final(perm).view().value == old(perm).view().value - n,
339 opens_invariants none
340 no_unwind
341 {
342 self.fetch_sub_wrapping(Tracked(&mut *perm), n)
343 }
344
345 #[inline(always)]
346 #[verifier::external_body] #[verifier::atomic] pub fn fetch_and(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
349 requires equal(self.id(), old(perm).view().patomic),
350 ensures
351 equal(old(perm).view().value, ret),
352 final(perm).view().patomic == old(perm).view().patomic,
353 final(perm).view().value == (old(perm).view().value & n),
354 opens_invariants none
355 no_unwind
356 {
357 self.ato.fetch_and(n, Ordering::SeqCst)
358 }
359
360 #[inline(always)]
361 #[verifier::external_body] #[verifier::atomic] pub fn fetch_or(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
364 requires equal(self.id(), old(perm).view().patomic),
365 ensures
366 equal(old(perm).view().value, ret),
367 final(perm).view().patomic == old(perm).view().patomic,
368 final(perm).view().value == (old(perm).view().value | n),
369 opens_invariants none
370 no_unwind
371 {
372 self.ato.fetch_or(n, Ordering::SeqCst)
373 }
374
375 #[inline(always)]
376 #[verifier::external_body] #[verifier::atomic] pub fn fetch_xor(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
379 requires equal(self.id(), old(perm).view().patomic),
380 ensures
381 equal(old(perm).view().value, ret),
382 final(perm).view().patomic == old(perm).view().patomic,
383 final(perm).view().value == (old(perm).view().value ^ n),
384 opens_invariants none
385 no_unwind
386 {
387 self.ato.fetch_xor(n, Ordering::SeqCst)
388 }
389
390 #[inline(always)]
391 #[verifier::external_body] #[verifier::atomic] pub fn fetch_nand(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
394 requires equal(self.id(), old(perm).view().patomic),
395 ensures
396 equal(old(perm).view().value, ret),
397 final(perm).view().patomic == old(perm).view().patomic,
398 final(perm).view().value == !(old(perm).view().value & n),
399 opens_invariants none
400 no_unwind
401 {
402 self.ato.fetch_nand(n, Ordering::SeqCst)
403 }
404
405 #[inline(always)]
406 #[verifier::external_body] #[verifier::atomic] pub fn fetch_max(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
409 requires equal(self.id(), old(perm).view().patomic),
410 ensures
411 equal(old(perm).view().value, ret),
412 final(perm).view().patomic == old(perm).view().patomic,
413 final(perm).view().value == (if old(perm).view().value > n { old(perm).view().value } else { n }),
414 opens_invariants none
415 no_unwind
416 {
417 self.ato.fetch_max(n, Ordering::SeqCst)
418 }
419
420 #[inline(always)]
421 #[verifier::external_body] #[verifier::atomic] pub fn fetch_min(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
424 requires equal(self.id(), old(perm).view().patomic),
425 ensures
426 equal(old(perm).view().value, ret),
427 final(perm).view().patomic == old(perm).view().patomic,
428 final(perm).view().value == (if old(perm).view().value < n { old(perm).view().value } else { n }),
429 opens_invariants none
430 no_unwind
431 {
432 self.ato.fetch_min(n, Ordering::SeqCst)
433 }
434
435 }
436 };
437}
438
439macro_rules! atomic_bool_methods {
440 ($at_ident:ident, $p_ident:ident, $rust_ty: ty, $value_ty: ty) => {
441 verus!{
442
443 #[inline(always)]
444 #[verifier::external_body] #[verifier::atomic] pub fn fetch_and(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
447 requires
448 equal(self.id(), old(perm).view().patomic),
449 ensures
450 equal(old(perm).view().value, ret)
451 && final(perm).view().patomic == old(perm).view().patomic
452 && final(perm).view().value == (old(perm).view().value && n),
453 opens_invariants none
454 no_unwind
455 {
456 self.ato.fetch_and(n, Ordering::SeqCst)
457 }
458
459 #[inline(always)]
460 #[verifier::external_body] #[verifier::atomic] pub fn fetch_or(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
463 requires
464 equal(self.id(), old(perm).view().patomic),
465 ensures
466 equal(old(perm).view().value, ret)
467 && final(perm).view().patomic == old(perm).view().patomic
468 && final(perm).view().value == (old(perm).view().value || n),
469 opens_invariants none
470 no_unwind
471 {
472 self.ato.fetch_or(n, Ordering::SeqCst)
473 }
474
475 #[inline(always)]
476 #[verifier::external_body] #[verifier::atomic] pub fn fetch_xor(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
479 requires
480 equal(self.id(), old(perm).view().patomic),
481 ensures
482 equal(old(perm).view().value, ret)
483 && final(perm).view().patomic == old(perm).view().patomic
484 && final(perm).view().value == ((old(perm).view().value && !n) || (!old(perm).view().value && n)),
485 opens_invariants none
486 no_unwind
487 {
488 self.ato.fetch_xor(n, Ordering::SeqCst)
489 }
490
491 #[inline(always)]
492 #[verifier::external_body] #[verifier::atomic] pub fn fetch_nand(&self, Tracked(perm): Tracked<&mut $p_ident>, n: $value_ty) -> (ret: $value_ty)
495 requires
496 equal(self.id(), old(perm).view().patomic),
497 ensures
498 equal(old(perm).view().value, ret)
499 && final(perm).view().patomic == old(perm).view().patomic
500 && final(perm).view().value == !(old(perm).view().value && n),
501 opens_invariants none
502 no_unwind
503 {
504 self.ato.fetch_nand(n, Ordering::SeqCst)
505 }
506
507 }
508 };
509}
510
511macro_rules! ptr_atomic_methods {
512 ($at_ty: ty, $rust_ty: ty, $value_ty: ty, $width: literal) => {
513 #[cfg(target_has_atomic_primitive_alignment = $width)]
519 const _: () = assert!(
520 core::mem::align_of::<$value_ty>() == core::mem::align_of::<$rust_ty>(),
521 concat!(
522 stringify!($at_ty),
523 ": align_of::<",
524 stringify!($value_ty),
525 ">() differs from align_of::<",
526 stringify!($rust_ty),
527 ">() on this target",
528 )
529 );
530
531 #[cfg(target_has_atomic_primitive_alignment = $width)]
532 verus!{
533 impl $at_ty {
534 #[inline(always)]
544 #[verifier::atomic]
545 #[verifier::external_body]
546 pub fn from_ptr_store(ptr: *mut $value_ty, value: $value_ty, Tracked(perm): Tracked<&mut PointsTo<$value_ty>>)
547 requires
548 old(perm).ptr() == ptr,
549 ensures
550 value == final(perm).value(),
551 old(perm).ptr() == final(perm).ptr(),
552 final(perm).is_init(),
553 opens_invariants none
554 no_unwind
555 {
556 unsafe { $rust_ty::from_ptr(ptr).store(value, Ordering::SeqCst) }
557 }
558
559 #[inline(always)]
561 #[verifier::atomic]
562 #[verifier::external_body]
563 pub fn from_ptr_load(ptr: *mut $value_ty, perm: Tracked<&PointsTo<$value_ty>>) -> (ret: $value_ty)
564 requires
565 perm.ptr() == ptr,
566 perm.is_init(),
567 ensures
568 ret == perm.value(),
569 opens_invariants none
570 no_unwind
571 {
572 unsafe { $rust_ty::from_ptr(ptr).load(Ordering::SeqCst) }
573 }
574
575 #[inline(always)]
580 #[verifier::external_body] #[verifier::atomic] pub fn from_ptr_swap(ptr: *mut $value_ty, Tracked(perm): Tracked<&mut PointsTo<$value_ty>>, v: $value_ty) -> (ret: $value_ty)
583 requires
584 ptr == old(perm).ptr(),
585 old(perm).is_init(),
586 ensures
587 final(perm).value() == v,
588 final(perm).is_init(),
589 old(perm).value() == ret,
590 ptr == final(perm).ptr(),
591 opens_invariants none
592 no_unwind
593 {
594 unsafe {
595 $rust_ty::from_ptr(ptr).swap(v, Ordering::SeqCst)}
596 }
597 }
598}
599 };
600}
601
602#[cfg(target_has_atomic = "64")]
603ptr_atomic_methods!(PAtomicU64, AtomicU64, u64, "64");
604
605ptr_atomic_methods!(PAtomicU32, AtomicU32, u32, "32");
606ptr_atomic_methods!(PAtomicU16, AtomicU16, u16, "16");
607ptr_atomic_methods!(PAtomicU8, AtomicU8, u8, "8");
608ptr_atomic_methods!(PAtomicUsize, AtomicUsize, usize, "ptr");
609
610#[cfg(target_has_atomic = "64")]
611ptr_atomic_methods!(PAtomicI64, AtomicI64, i64, "64");
612
613ptr_atomic_methods!(PAtomicI32, AtomicI32, i32, "32");
614ptr_atomic_methods!(PAtomicI16, AtomicI16, i16, "16");
615ptr_atomic_methods!(PAtomicI8, AtomicI8, i8, "8");
616ptr_atomic_methods!(PAtomicIsize, AtomicIsize, isize, "ptr");
617
618make_bool_atomic!(PAtomicBool, PermissionBool, PermissionDataBool, AtomicBool, bool);
619
620make_unsigned_integer_atomic!(PAtomicU8, PermissionU8, PermissionDataU8, AtomicU8, u8, u8_specs);
621make_unsigned_integer_atomic!(
622 PAtomicU16,
623 PermissionU16,
624 PermissionDataU16,
625 AtomicU16,
626 u16,
627 u16_specs
628);
629make_unsigned_integer_atomic!(
630 PAtomicU32,
631 PermissionU32,
632 PermissionDataU32,
633 AtomicU32,
634 u32,
635 u32_specs
636);
637
638#[cfg(target_has_atomic = "64")]
639make_unsigned_integer_atomic!(
640 PAtomicU64,
641 PermissionU64,
642 PermissionDataU64,
643 AtomicU64,
644 u64,
645 u64_specs
646);
647make_unsigned_integer_atomic!(
648 PAtomicUsize,
649 PermissionUsize,
650 PermissionDataUsize,
651 AtomicUsize,
652 usize,
653 usize_specs
654);
655
656make_signed_integer_atomic!(PAtomicI8, PermissionI8, PermissionDataI8, AtomicI8, i8, i8_specs);
657make_signed_integer_atomic!(
658 PAtomicI16,
659 PermissionI16,
660 PermissionDataI16,
661 AtomicI16,
662 i16,
663 i16_specs
664);
665make_signed_integer_atomic!(
666 PAtomicI32,
667 PermissionI32,
668 PermissionDataI32,
669 AtomicI32,
670 i32,
671 i32_specs
672);
673
674#[cfg(target_has_atomic = "64")]
675make_signed_integer_atomic!(
676 PAtomicI64,
677 PermissionI64,
678 PermissionDataI64,
679 AtomicI64,
680 i64,
681 i64_specs
682);
683make_signed_integer_atomic!(
684 PAtomicIsize,
685 PermissionIsize,
686 PermissionDataIsize,
687 AtomicIsize,
688 isize,
689 isize_specs
690);
691
692atomic_types_generic!(PAtomicPtr, PermissionPtr, PermissionDataPtr, AtomicPtr<T>, *mut T);
693
694#[cfg_attr(verus_keep_ghost, verifier::verus_macro)]
695impl<T> PAtomicPtr<T> {
696 atomic_common_methods!(
697 PAtomicPtr::<T>,
698 PermissionPtr::<T>,
699 PermissionDataPtr::<T>,
700 AtomicPtr::<T>,
701 *mut T,
702 [ .view().addr ]
703 );
704}
705
706impl<X, Y, Pred> core::fmt::Debug for AtomicUpdate<X, Y, Pred> {
707 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
708 f.debug_struct("AtomicUpdate").finish_non_exhaustive()
709 }
710}
711
712unsafe impl<X: Send, Y: Send, Pred> Send for AtomicUpdate<X, Y, Pred> {}
724
725unsafe impl<X, Y, Pred> Sync for AtomicUpdate<X, Y, Pred> {}
733
734verus! {
735
736#[doc(hidden)]
737#[verifier::external_body]
738pub struct AtomicUpdateLifetimeMarker<'a> {
739 _marker: core::marker::PhantomData<fn (&'a ())>,
740}
741
742#[verifier::reject_recursive_types(X)]
761#[verifier::reject_recursive_types(Y)]
762#[verifier::reject_recursive_types(Pred)]
763#[verifier::external_body]
764pub struct AtomicUpdate<X, Y, Pred> {
765 pred: Pred,
766 _dummy: core::marker::PhantomData<fn (fn (X) -> Y)>,
767 _not_send_sync: core::marker::PhantomData<*const ()>,
768}
769
770impl<X, Y, Pred> AtomicUpdate<X, Y, Pred> {
771 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::pred"]
775 pub uninterp spec fn pred(self) -> Pred;
776
777 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::resolves"]
784 pub uninterp spec fn resolves(self) -> bool;
785
786 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::input"]
791 pub uninterp spec fn input(self) -> X;
792
793 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::output"]
798 pub uninterp spec fn output(self) -> Y;
799}
800
801impl<X, Y, Pred: UpdatePredicate<X, Y>> AtomicUpdate<X, Y, Pred> {
802 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::req"]
803 pub open spec fn req(self, x: X) -> bool {
804 self.pred().req(x)
805 }
806
807 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::ens"]
808 pub open spec fn ens(self, x: X, y: Y) -> bool {
809 self.pred().ens(x, y)
810 }
811
812 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::outer_mask"]
813 pub open spec fn outer_mask(self) -> ISet<int> {
814 self.pred().outer_mask()
815 }
816
817 #[rustc_diagnostic_item = "verus::vstd::atomic::AtomicUpdate::inner_mask"]
818 pub open spec fn inner_mask(self) -> ISet<int> {
819 self.pred().inner_mask()
820 }
821}
822
823#[cfg(verus_keep_ghost)]
824#[rustc_diagnostic_item = "verus::vstd::atomic::pred_args"]
825#[doc(hidden)]
826pub uninterp spec fn pred_args<Pred, Args>(pred: Pred) -> Args;
827
828pub trait UpdatePredicate<X, Y>: Sized {
860 spec fn req(self, x: X) -> bool;
862
863 spec fn ens(self, x: X, y: Y) -> bool;
865
866 open spec fn outer_mask(self) -> ISet<int> {
868 ISet::empty()
869 }
870
871 open spec fn inner_mask(self) -> ISet<int> {
873 ISet::empty()
874 }
875}
876
877pub enum UpdateControlFlow {
879 Commit,
884 Abort,
889}
890
891impl UpdateControlFlow {
892 pub open spec fn is_commit(self) -> bool {
893 match self {
894 UpdateControlFlow::Commit => true,
895 UpdateControlFlow::Abort => false,
896 }
897 }
898
899 pub open spec fn is_abort(self) -> bool {
900 !self.is_commit()
901 }
902}
903
904pub trait UpdateTry {
905 spec fn branch(self) -> UpdateControlFlow;
906}
907
908impl<T, E> UpdateTry for Result<T, E> {
909 open spec fn branch(self) -> UpdateControlFlow {
910 match self {
911 Ok(_) => UpdateControlFlow::Commit,
912 Err(_) => UpdateControlFlow::Abort,
913 }
914 }
915}
916
917#[derive(Debug)]
921pub struct Commit<T>(pub T);
922
923impl<T> Commit<T> {
924 pub proof fn get(tracked self) -> (tracked out: T)
925 ensures
926 self@ == out,
927 {
928 self.0
929 }
930}
931
932impl<T> View for Commit<T> {
933 type V = T;
934
935 #[verifier::inline]
936 open spec fn view(&self) -> T {
937 self.0
938 }
939}
940
941impl<T> UpdateTry for Commit<T> {
942 open spec fn branch(self) -> UpdateControlFlow {
943 UpdateControlFlow::Commit
944 }
945}
946
947impl UpdateTry for () {
948 open spec fn branch(self) -> UpdateControlFlow {
949 UpdateControlFlow::Commit
950 }
951}
952
953#[cfg(verus_keep_ghost)]
954#[rustc_diagnostic_item = "verus::vstd::atomic::branch_bool"]
955#[doc(hidden)]
956pub open spec fn branch_bool<T: UpdateTry>(this: T) -> bool {
957 this.branch().is_commit()
958}
959
960#[cfg(verus_keep_ghost)]
962#[rustc_diagnostic_item = "verus::vstd::atomic::atomically"]
963#[doc(hidden)]
964#[verifier::external]
965pub fn atomically<X, Y: UpdateTry, P: UpdatePredicate<X, Y>>(
966 _body: impl FnOnce(fn (X) -> Y, Ghost<AtomicUpdate<X, Y, P>>),
967) -> AtomicUpdate<X, Y, P> {
968 arbitrary()
969}
970
971#[doc(hidden)]
973pub struct BlockGuard<T> {
974 _inner: core::marker::PhantomData<T>,
975}
976
977#[cfg(verus_keep_ghost)]
978#[doc(hidden)]
979#[verifier::external] pub fn bind_lifetime_internal<'a, X: 'a, Y, P>(
981 _block_guard: &'a BlockGuard<AtomicUpdate<X, Y, P>>,
982) -> X {
983 unimplemented!()
984}
985
986#[cfg(verus_keep_ghost)]
987#[rustc_diagnostic_item = "verus::vstd::atomic::try_open_atomic_update_begin"]
988#[doc(hidden)]
989#[verifier::external] pub fn try_open_atomic_update_begin<X, Y: UpdateTry, P: UpdatePredicate<X, Y>>(
991 _atomic_update: AtomicUpdate<X, Y, P>,
992) -> BlockGuard<AtomicUpdate<X, Y, P>> {
993 unimplemented!()
994}
995
996#[cfg(verus_keep_ghost)]
997#[rustc_diagnostic_item = "verus::vstd::atomic::try_open_atomic_update_end"]
998#[doc(hidden)]
999#[verifier::external] pub fn try_open_atomic_update_end<X, Y: UpdateTry, P: UpdatePredicate<X, Y>>(
1001 _guard: BlockGuard<AtomicUpdate<X, Y, P>>,
1002 _y: Tracked<Y>,
1003) -> Tracked<Result<(), AtomicUpdate<X, Y, P>>> {
1004 unimplemented!()
1005}
1006
1007#[macro_export]
1009macro_rules! open_atomic_update {
1010 ($($tail:tt)*) => {
1011 {
1012 let _ = ::verus_builtin_macros::verus_exec_open_au_macro_exprs!(
1013 $crate::atomic::try_open_atomic_update_internal!(
1014 $($tail)*, @EXEC, au_commit_wrap_exec
1015 )
1016 );
1017 }
1018 };
1019}
1020
1021#[macro_export]
1022macro_rules! open_atomic_update_in_proof {
1023 ($($tail:tt)*) => {
1024 {
1025 let _ = ::verus_builtin_macros::verus_ghost_open_au_macro_exprs!(
1026 $crate::atomic::try_open_atomic_update_internal!(
1027 $($tail)*, @PROOF, au_commit_wrap_proof
1028 )
1029 );
1030 }
1031 };
1032}
1033
1034#[macro_export]
1035macro_rules! peek_atomic_update {
1036 ($($tail:tt)*) => {
1037 {
1038 #[verifier::exec]
1039 let err_au = ::verus_builtin_macros::verus_exec_open_au_macro_exprs!(
1040 $crate::atomic::try_open_atomic_update_internal!(
1041 $($tail)*, @EXEC, au_abort_wrap_exec
1042 )
1043 );
1044
1045 match () {
1046 #[cfg(verus_keep_ghost_body)]
1047 _ => $crate::atomic::au_abort_unwrap_exec(err_au),
1048
1049 #[cfg(not(verus_keep_ghost_body))]
1050 _ => ::verus_builtin::Tracked::assume_new_fallback(|| ::core::unreachable!()),
1051 }
1052 }
1053 };
1054}
1055
1056#[macro_export]
1057macro_rules! peek_atomic_update_in_proof {
1058 ($($tail:tt)*) => {
1059 {
1060 #[verifier::proof]
1061 let err_au = ::verus_builtin_macros::verus_ghost_open_au_macro_exprs!(
1062 $crate::atomic::try_open_atomic_update_internal!(
1063 $($tail)*, @PROOF, au_abort_wrap_proof
1064 )
1065 );
1066
1067 match () {
1068 #[cfg(verus_keep_ghost_body)]
1069 _ => $crate::atomic::au_abort_unwrap_proof(err_au),
1070
1071 #[cfg(not(verus_keep_ghost_body))]
1072 _ => ::verus_builtin::Tracked::assume_new_fallback(|| ::core::unreachable!()),
1073 }
1074 }
1075 };
1076}
1077
1078#[macro_export]
1079macro_rules! try_open_atomic_update {
1080 ($($tail:tt)*) => {
1081 ::verus_builtin_macros::verus_exec_open_au_macro_exprs!(
1082 $crate::atomic::try_open_atomic_update_internal!($($tail)*)
1083 )
1084 };
1085}
1086
1087#[macro_export]
1088macro_rules! try_open_atomic_update_in_proof {
1089 ($($tail:tt)*) => {
1090 ::verus_builtin_macros::verus_ghost_open_au_macro_exprs!(
1091 $crate::atomic::try_open_atomic_update_internal!($($tail)*)
1092 )
1093 };
1094}
1095
1096#[macro_export]
1097macro_rules! try_open_atomic_update_internal {
1098 ($au:expr, $x:pat => $body:block, @EXEC, $wrap_fn:ident) => {
1099 $crate::atomic::try_open_atomic_update_internal!($au, $x => {
1100 #[verifier::exec]
1101 let v = $body;
1102
1103 match () {
1104 #[cfg(verus_keep_ghost_body)]
1105 _ => $crate::atomic::$wrap_fn(v),
1106
1107 #[cfg(not(verus_keep_ghost_body))]
1108 _ => ::verus_builtin::Tracked::assume_new_fallback(|| ::core::unreachable!()),
1109 }
1110 })
1111 };
1112
1113 ($au:expr, $x:pat => $body:block, @PROOF, $wrap_fn:ident) => {
1114 $crate::atomic::try_open_atomic_update_internal!($au, $x => {
1115 #[verifier::proof]
1116 let v = $body;
1117
1118 match () {
1119 #[cfg(verus_keep_ghost_body)]
1120 _ => $crate::atomic::$wrap_fn(v),
1121
1122 #[cfg(not(verus_keep_ghost_body))]
1123 _ => ::verus_builtin::Tracked::assume_new_fallback(|| ::core::unreachable!()),
1124 }
1125 })
1126 };
1127
1128 ($au:expr, $x:pat => $body:block) => {
1129 #[cfg_attr(verus_keep_ghost, verifier::open_au_block)] {
1130 #[cfg(verus_keep_ghost_body)]
1131 let guard = $crate::atomic::try_open_atomic_update_begin($au);
1132 #[cfg(verus_keep_ghost_body)]
1133 let $x = $crate::atomic::bind_lifetime_internal(&guard);
1134 let res = $body;
1135
1136 match res {
1137 #[cfg(verus_keep_ghost_body)]
1138 res => $crate::atomic::try_open_atomic_update_end(guard, res),
1139
1140 #[cfg(not(verus_keep_ghost_body))]
1141 _ => ::verus_builtin::Tracked::assume_new_fallback(|| ::core::unreachable!()),
1142 }
1143 }
1144 };
1145}
1146
1147#[doc(hidden)]
1148pub use {try_open_atomic_update_internal};
1149pub use {
1150 open_atomic_update,
1151 open_atomic_update_in_proof,
1152 peek_atomic_update,
1153 peek_atomic_update_in_proof,
1154 try_open_atomic_update,
1155 try_open_atomic_update_in_proof,
1156};
1157
1158impl<T> PAtomicPtr<T> {
1159 #[inline(always)]
1160 #[verifier::external_body] #[verifier::atomic] #[cfg(any(verus_keep_ghost, feature = "strict_provenance_atomic_ptr"))]
1163 pub fn fetch_and(&self, Tracked(perm): Tracked<&mut PermissionPtr<T>>, n: usize) -> (ret:
1164 *mut T)
1165 requires
1166 equal(self.id(), old(perm).view().patomic),
1167 ensures
1168 equal(old(perm).view().value, ret),
1169 final(perm).view().patomic == old(perm).view().patomic,
1170 final(perm).view().value@.addr == (old(perm).view().value@.addr & n),
1171 final(perm).view().value@.provenance == old(perm).view().value@.provenance,
1172 final(perm).view().value@.metadata == old(perm).view().value@.metadata,
1173 opens_invariants none
1174 no_unwind
1175 {
1176 self.ato.fetch_and(n, Ordering::SeqCst)
1177 }
1178
1179 #[inline(always)]
1180 #[verifier::external_body] #[verifier::atomic] #[cfg(any(verus_keep_ghost, feature = "strict_provenance_atomic_ptr"))]
1183 pub fn fetch_xor(&self, Tracked(perm): Tracked<&mut PermissionPtr<T>>, n: usize) -> (ret:
1184 *mut T)
1185 requires
1186 equal(self.id(), old(perm).view().patomic),
1187 ensures
1188 equal(old(perm).view().value, ret),
1189 final(perm).view().patomic == old(perm).view().patomic,
1190 final(perm).view().value@.addr == (old(perm).view().value@.addr ^ n),
1191 final(perm).view().value@.provenance == old(perm).view().value@.provenance,
1192 final(perm).view().value@.metadata == old(perm).view().value@.metadata,
1193 opens_invariants none
1194 no_unwind
1195 {
1196 self.ato.fetch_xor(n, Ordering::SeqCst)
1197 }
1198
1199 #[inline(always)]
1200 #[verifier::external_body] #[verifier::atomic] #[cfg(any(verus_keep_ghost, feature = "strict_provenance_atomic_ptr"))]
1203 pub fn fetch_or(&self, Tracked(perm): Tracked<&mut PermissionPtr<T>>, n: usize) -> (ret: *mut T)
1204 requires
1205 equal(self.id(), old(perm).view().patomic),
1206 ensures
1207 equal(old(perm).view().value, ret),
1208 final(perm).view().patomic == old(perm).view().patomic,
1209 final(perm).view().value@.addr == (old(perm).view().value@.addr | n),
1210 final(perm).view().value@.provenance == old(perm).view().value@.provenance,
1211 final(perm).view().value@.metadata == old(perm).view().value@.metadata,
1212 opens_invariants none
1213 no_unwind
1214 {
1215 self.ato.fetch_or(n, Ordering::SeqCst)
1216 }
1217}
1218
1219}