1use crate::{
2 ghost::{FnGhost, Perm, perm::PermTarget},
3 logic::FMap,
4 prelude::*,
5 std::sync::{
6 committer::Committer,
7 view::{AcquireSyncView, HasTimestamp, ReleaseSyncView, SyncView, Timestamp},
8 },
9};
10use core::sync::atomic::{Ordering as OrderingTy, fence};
11
12pub mod ordering {
14 use core::sync::atomic::Ordering as OrderingTy;
15
16 pub trait Ordering {
17 const ORDERING: OrderingTy;
18 }
19
20 pub trait LoadOrdering: Ordering {}
21 pub trait StoreOrdering: Ordering {}
22 pub trait UpdateOrdering: Ordering {
23 type Load: LoadOrdering;
24 type Store: StoreOrdering;
25 }
26
27 macro_rules! impl_ordering {
28 ( $order:ident, load = $load:ident, store = $store:ident ) => {
29 pub struct $order;
30
31 impl Ordering for $order {
32 const ORDERING: OrderingTy = OrderingTy::$order;
33 }
34
35 impl UpdateOrdering for $order {
36 type Load = $load;
37 type Store = $store;
38 }
39 };
40 }
41
42 impl_ordering!(Relaxed, load = Relaxed, store = Relaxed);
43 impl_ordering!(Acquire, load = Acquire, store = Relaxed);
44 impl_ordering!(Release, load = Relaxed, store = Release);
45 impl_ordering!(AcqRel, load = Acquire, store = Release);
46
47 impl LoadOrdering for Relaxed {}
48 impl StoreOrdering for Relaxed {}
49 impl LoadOrdering for Acquire {}
50 impl StoreOrdering for Release {}
51}
52
53use ordering::{LoadOrdering, StoreOrdering, UpdateOrdering};
54
55const SEQ_CST: OrderingTy = OrderingTy::SeqCst;
56
57macro_rules! impl_atomic {
58 ($( ($type:ty, $atomic_type:ident $(< $T:ident >)?) ),+) => { $(
59
60 #[doc = concat!("Creusot wrapper around [`std::sync::atomic::", stringify!($atomic_type), "`].")]
61 pub struct $atomic_type $(< $T >)?(::core::sync::atomic::$atomic_type $(< $T >)?);
62
63 impl $(< $T >)? PermTarget for $atomic_type $(< $T >)? {
64 type Value = FMap<Timestamp, ($type, SyncView)>;
65 type Objectiveness = ();
66 }
67
68 impl $(< $T >)? HasTimestamp for $atomic_type $(< $T >)? {
69 #[logic(opaque)]
70 fn get_timestamp(self, _: SyncView) -> Timestamp {
71 dead
72 }
73
74 #[logic(law)]
75 #[requires(x <= y)]
76 #[ensures(self.get_timestamp(x) <= self.get_timestamp(y))]
77 #[trusted]
78 fn get_timestamp_monotonic(self, x: SyncView, y: SyncView) {}
79 }
80
81 impl $(< $T >)? $atomic_type $(< $T >)? {
82 #[ensures(result.1.val() == FMap::singleton(result.0.get_timestamp(^sync_view), (val, ^sync_view)))]
83 #[ensures(**sync_view <= ^sync_view)]
84 #[ensures(*result.1.ward() == result.0)]
85 #[inline(always)]
86 #[trusted]
87 #[check(terminates)]
88 #[allow(unused_variables)]
89 pub fn new(val: $type, sync_view: Ghost<&mut SyncView>) -> (Self, Ghost<Perm<$atomic_type $(< $T >)?>>) {
90 (Self(core::sync::atomic::$atomic_type::new(val)), Ghost::conjure())
91 }
92
93 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::into_inner`].")]
94 #[requires(self == *own.ward())]
95 #[ensures(match own.val().lookup(self.get_timestamp(*result.1)) { Some((v, _)) => result.0 == v, None => false })]
96 #[ensures(forall<t> match own.val().lookup(t) {
97 Some((_, view)) => t <= self.get_timestamp(*result.1) && view <= *result.1,
98 None => true
99 })]
100 #[inline(always)]
101 #[trusted]
102 #[check(terminates)]
103 #[allow(unused_variables)]
104 pub fn into_inner(self, own: Ghost<Perm<$atomic_type $(< $T >)?>>) -> ($type, Ghost<SyncView>) {
105 (self.0.into_inner(), Ghost::conjure())
106 }
107
108
109 #[doc = "Clear the old unusable history, thanks to the full ownership of the atomic."]
110 #[requires(*self == *own.ward())]
111 #[ensures(**sync_view <= ^sync_view)]
112 #[ensures(match (*own).val().lookup(self.get_timestamp(^sync_view)) {
113 Some((v, _)) => (^own).val() == FMap::singleton(self.get_timestamp(^sync_view), (v, **sync_view)),
114 None => false
115 })]
116 #[ensures(forall<t> match own.val().lookup(t) {
117 Some((_, view)) => t <= self.get_timestamp(^sync_view) && view <= ^sync_view,
118 None => true
119 })]
120 #[ensures(*self == ^self)]
121 #[inline(always)]
122 #[trusted]
123 #[check(terminates)]
124 #[allow(unused_variables)]
125 pub fn refresh(&mut self, own: Ghost<&mut Perm<$atomic_type $(< $T >)?>>, sync_view: Ghost<&mut SyncView>) {}
126
127 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::compare_exchange`].")]
128 #[doc = ""]
129 #[doc = "The load and the store are always sequentially consistent."]
130 #[requires(forall<c: &mut Committer<Self, $type, _, _>>
131 !c.shot_store() ==> c.ward() == *self ==>
132 c.val_load().deep_model() == current.deep_model() ==>
133 c.val_store() == new ==>
134 f.precondition((Ok(c),)) && (f.postcondition_once((Ok(c),), ()) ==> (^c).shot_store())
135 )]
136 #[requires(forall<c: &Committer<Self, $type, _, _>>
137 !c.shot_store() ==> c.ward() == *self ==>
138 c.val_load().deep_model() != current.deep_model() ==>
140 f.precondition((Err(c),))
141 )]
142 #[ensures(
143 (exists<c: &mut Committer<Self, $type, _, _>>
144 !c.shot_store() && c.ward() == *self &&
145 c.val_load().deep_model() == current.deep_model() &&
146 c.val_store() == new &&
147 result == Ok(c.val_load()) &&
148 f.postcondition_once((Ok(c),), ())) ||
149 (exists<c: &Committer<Self, $type, _, _>>
150 !c.shot_store() && c.ward() == *self &&
151 c.val_load().deep_model() != current.deep_model() &&
153 result == Err(c.val_load()) &&
154 f.postcondition_once((Err(c),), ())
155 )
156 )]
157 #[inline(always)]
158 #[trusted]
159 #[allow(unused_variables)]
160 pub fn compare_exchange<F, Success: UpdateOrdering, Failure: LoadOrdering>(&self, current: $type, new: $type, f: Ghost<F>) -> Result<$type, $type>
161 where
162 F: FnGhost + FnOnce(Result<
163 &mut Committer<Self, $type, Success::Load, Success::Store>,
164 &Committer<Self, $type, Failure, ()>
165 >,
166 )
167 {
168 self.0.compare_exchange(
169 current,
170 new,
171 if cfg!(feature = "sc-drf") { SEQ_CST } else { Success::ORDERING },
172 if cfg!(feature = "sc-drf") { SEQ_CST } else { Failure::ORDERING }
173 )
174 }
175
176 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::compare_exchange_weak`].")]
177 #[doc = ""]
178 #[doc = "The load and the store are always sequentially consistent."]
179 #[requires(forall<c: &mut Committer<Self, $type, _, _>>
180 !c.shot_store() ==> c.ward() == *self ==>
181 c.val_load().deep_model() == current.deep_model() ==>
182 c.val_store() == new ==>
183 f.precondition((Ok(c),)) && (f.postcondition_once((Ok(c),), ()) ==> (^c).shot_store())
184 )]
185 #[requires(forall<c: &Committer<Self, $type, _, _>>
186 !c.shot_store() ==> c.ward() == *self ==>
187 f.precondition((Err(c),))
188 )]
189 #[ensures(
190 (exists<c: &mut Committer<Self, $type, _, _>>
191 !c.shot_store() && c.ward() == *self &&
192 c.val_load().deep_model() == current.deep_model() &&
193 c.val_store() == new &&
194 result == Ok(c.val_load()) &&
195 f.postcondition_once((Ok(c),), ())) ||
196 (exists<c: &Committer<Self, $type, _, _>>
197 !c.shot_store() && c.ward() == *self &&
198 result == Err(c.val_load()) &&
199 f.postcondition_once((Err(c),), ())
200 )
201 )]
202 #[inline(always)]
203 #[trusted]
204 #[allow(unused_variables)]
205 pub fn compare_exchange_weak<F, Success: UpdateOrdering, Failure: LoadOrdering>(&self, current: $type, new: $type, f: Ghost<F>) -> Result<$type, $type>
206 where
207 F: FnGhost + FnOnce(Result<
208 &mut Committer<Self, $type, Success::Load, Success::Store>,
209 &Committer<Self, $type, Failure, ()>
210 >,
211 )
212 {
213 self.0.compare_exchange_weak(
214 current,
215 new,
216 if cfg!(feature = "sc-drf") { SEQ_CST } else { Success::ORDERING },
217 if cfg!(feature = "sc-drf") { SEQ_CST } else { Failure::ORDERING }
218 )
219 }
220
221 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::load`].")]
222 #[requires(forall<c: &Committer<Self, $type, Load, ()>>
223 !c.shot_store() ==> c.ward() == *self ==> f.precondition((c,))
224 )]
225 #[ensures(exists<c: &Committer<Self, $type, Load, ()>>
226 !c.shot_store() && c.ward() == *self && c.val_load() == result && f.postcondition_once((c,), ())
227 )]
228 #[inline(always)]
229 #[trusted]
230 #[allow(unused_variables)]
231 pub fn load<F, Load: LoadOrdering>(&self, f: Ghost<F>) -> $type
232 where
233 F: FnGhost + FnOnce(&Committer<Self, $type, Load, ()>),
234 {
235 self.0.load(if cfg!(feature = "sc-drf") { SEQ_CST } else { Load::ORDERING })
237 }
238
239 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::store`].")]
240 #[requires(forall<c: &mut Committer<Self, $type, (), Store>>
241 !c.shot_store() ==> c.ward() == *self ==> c.val_store() == val ==>
242 f.precondition((c,)) && (f.postcondition_once((c,), ()) ==> (^c).shot_store())
243 )]
244 #[ensures(exists<c: &mut Committer<Self, $type, (), Store>>
245 !c.shot_store() && c.ward() == *self && c.val_store() == val &&
246 f.postcondition_once((c,), ())
247 )]
248 #[inline(always)]
249 #[trusted]
250 #[allow(unused_variables)]
251 pub fn store<F, Store: StoreOrdering>(&self, val: $type, f: Ghost<F>)
252 where
253 F: FnGhost + FnOnce(&mut Committer<Self, $type, (), Store>),
254 {
255 self.0.store(
256 val,
257 if cfg!(feature = "sc-drf") { SEQ_CST } else { Store::ORDERING },
258 )
259 }
260 }
261
262 )* };
263}
264
265macro_rules! impl_atomic_int {
266 ($( ($int_type:ty, $atomic_type:ident) ),+) => { $(
267
268 impl_atomic!(($int_type, $atomic_type));
269
270 impl $atomic_type {
271 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::fetch_add`].")]
272 #[requires(forall<c: &mut Committer<Self, $int_type, Ord::Load, Ord::Store>>
273 !c.shot_store() ==> c.ward() == *self ==> c.val_store() == val + c.val_load() ==>
274 f.precondition((c,)) && (f.postcondition_once((c,), ()) ==> (^c).shot_store())
275 )]
276 #[ensures(exists<c: &mut Committer<Self, $int_type, Ord::Load, Ord::Store>>
277 !c.shot_store() && c.ward() == *self && c.val_store() == val + c.val_load() &&
278 c.val_load() == result && f.postcondition_once((c,), ())
279 )]
280 #[inline(always)]
281 #[trusted]
282 #[allow(unused_variables)]
283 pub fn fetch_add<F, Ord: UpdateOrdering>(&self, val: $int_type, f: Ghost<F>) -> $int_type
284 where
285 F: FnGhost + FnOnce(&mut Committer<Self, $int_type, Ord::Load, Ord::Store>),
286 {
287 self.0.fetch_add(
288 val,
289 if cfg!(feature = "sc-drf") { SEQ_CST } else { Ord::ORDERING },
290 )
291 }
292 }
293
294 )* };
295}
296
297#[cfg(target_has_atomic = "8")]
298impl_atomic!((bool, AtomicBool));
299#[cfg(target_has_atomic = "ptr")]
300impl_atomic!((*mut T, AtomicPtr<T>));
301
302#[cfg(target_has_atomic = "8")]
303impl_atomic_int!((i8, AtomicI8), (u8, AtomicU8));
304#[cfg(target_has_atomic = "16")]
305impl_atomic_int!((i16, AtomicI16), (u16, AtomicU16));
306#[cfg(target_has_atomic = "32")]
307impl_atomic_int!((i32, AtomicI32), (u32, AtomicU32));
308#[cfg(target_has_atomic = "64")]
309impl_atomic_int!((i64, AtomicI64), (u64, AtomicU64));
310
311#[cfg(target_has_atomic = "ptr")]
316impl_atomic_int!((isize, AtomicIsize), (usize, AtomicUsize));
317
318#[ensures(*sync_view == result@)]
319#[trusted]
320#[allow(unused_variables)]
321pub fn fence_release(sync_view: Ghost<SyncView>) -> Ghost<ReleaseSyncView> {
322 fence(OrderingTy::Release);
323 Ghost::conjure()
324}
325
326#[ensures(acq_view@ == *result)]
327#[trusted]
328#[allow(unused_variables)]
329pub fn fence_acquire(acq_view: Ghost<AcquireSyncView>) -> Ghost<SyncView> {
330 fence(OrderingTy::Acquire);
331 Ghost::conjure()
332}
333
334#[ensures(acq_view@ == result@)]
335#[trusted]
336#[allow(unused_variables)]
337pub fn fence_acqrel(acq_view: Ghost<AcquireSyncView>) -> Ghost<ReleaseSyncView> {
338 fence(OrderingTy::AcqRel);
339 Ghost::conjure()
340}