ostd/specs/task/
cpu_local.rs1use vstd::{
17 prelude::*,
18 resource::{
19 Loc,
20 map::{GhostMapAuth, GhostPointsTo, GhostSubmap},
21 },
22};
23
24use crate::specs::task::cpu_core::CpuCoreLocalState;
25
26use crate::cpu::CpuId;
27
28verus! {
29
30pub tracked struct CpuLocalAuth<V> {
36 auth: GhostMapAuth<CpuId, V>,
37}
38
39pub tracked struct CpuLocalPointsToSet<V> {
45 points_to: GhostSubmap<CpuId, V>,
46}
47
48pub tracked struct CpuLocalPointsTo<V> {
56 points_to: GhostPointsTo<CpuId, V>,
57}
58
59impl<V> CpuCoreLocalState for CpuLocalPointsTo<V> {
60 open spec fn belongs_to_cpu(self, cpu: CpuId) -> bool {
61 self.cpu() == cpu
62 }
63
64 open spec fn local_key(self) -> Seq<Loc> {
65 seq![self.id()]
66 }
67}
68
69impl<V> View for CpuLocalAuth<V> {
70 type V = Map<CpuId, V>;
71
72 closed spec fn view(&self) -> Self::V {
73 self.auth@
74 }
75}
76
77impl<V> View for CpuLocalPointsToSet<V> {
78 type V = Map<CpuId, V>;
79
80 closed spec fn view(&self) -> Self::V {
81 self.points_to@
82 }
83}
84
85impl<V> CpuLocalAuth<V> {
86 pub proof fn new(initial: Map<CpuId, V>) -> (tracked res: (
92 CpuLocalAuth<V>,
93 CpuLocalPointsToSet<V>,
94 ))
95 ensures
96 res.0.id() == res.1.id(),
97 res.0@ == initial,
98 res.1@ == initial,
99 res.0.cpus() == initial.dom(),
100 res.1.cpus() == initial.dom(),
101 {
102 let tracked (auth, points_to) = GhostMapAuth::new(initial);
103 (CpuLocalAuth { auth }, CpuLocalPointsToSet { points_to })
104 }
105
106 pub closed spec fn id(&self) -> Loc {
108 self.auth.id()
109 }
110
111 pub open spec fn cpus(&self) -> Set<CpuId> {
113 self@.dom()
114 }
115
116 pub open spec fn value(&self, cpu: CpuId) -> V
118 recommends
119 self.cpus().contains(cpu),
120 {
121 self@[cpu]
122 }
123
124 pub open spec fn covers(&self, cpus: Set<CpuId>) -> bool {
126 self.cpus() == cpus
127 }
128}
129
130impl<V> CpuLocalPointsToSet<V> {
131 pub closed spec fn id(&self) -> Loc {
133 self.points_to.id()
134 }
135
136 pub open spec fn cpus(&self) -> Set<CpuId> {
138 self@.dom()
139 }
140
141 pub open spec fn contains(&self, cpu: CpuId) -> bool {
143 self.cpus().contains(cpu)
144 }
145
146 pub proof fn tracked_take(tracked &mut self, cpu: CpuId) -> (tracked res: CpuLocalPointsTo<V>)
148 requires
149 old(self).contains(cpu),
150 ensures
151 final(self).id() == old(self).id(),
152 res.id() == final(self).id(),
153 res.cpu() == cpu,
154 res.value() == old(self)@[cpu],
155 final(self)@ == old(self)@.remove(cpu),
156 final(self).cpus() == old(self).cpus().remove(cpu),
157 {
158 let tracked points_to = self.points_to.split_points_to(cpu);
159 let tracked res = CpuLocalPointsTo { points_to };
160 assert(res.value() == old(self)@[cpu]);
161 res
162 }
163
164 pub proof fn tracked_return(tracked &mut self, tracked points_to: CpuLocalPointsTo<V>)
166 requires
167 old(self).id() == points_to.id(),
168 !old(self).contains(points_to.cpu()),
169 ensures
170 final(self).id() == old(self).id(),
171 final(self)@ == old(self)@.insert(points_to.cpu(), points_to.value()),
172 final(self).cpus() == old(self).cpus().insert(points_to.cpu()),
173 {
174 self.points_to.combine_points_to(points_to.points_to);
175 }
176}
177
178impl<V> CpuLocalPointsTo<V> {
179 pub closed spec fn id(&self) -> Loc {
181 self.points_to.id()
182 }
183
184 pub closed spec fn cpu(&self) -> CpuId {
186 self.points_to.key()
187 }
188
189 pub closed spec fn value(&self) -> V {
191 self.points_to.value()
192 }
193
194 pub proof fn lemma_agree(tracked &self, tracked auth: &CpuLocalAuth<V>)
196 requires
197 self.id() == auth.id(),
198 ensures
199 auth.cpus().contains(self.cpu()),
200 auth.value(self.cpu()) == self.value(),
201 {
202 self.points_to.agree(&auth.auth);
203 }
204
205 pub proof fn tracked_update(tracked &mut self, tracked auth: &mut CpuLocalAuth<V>, value: V)
209 requires
210 old(self).id() == old(auth).id(),
211 ensures
212 final(self).id() == old(self).id(),
213 final(self).cpu() == old(self).cpu(),
214 final(self).value() == value,
215 final(auth).id() == old(auth).id(),
216 final(auth).cpus() == old(auth).cpus(),
217 final(auth)@ == old(auth)@.insert(old(self).cpu(), value),
218 {
219 self.points_to.agree(&auth.auth);
220 let ghost cpu = self.cpu();
221 self.points_to.update(&mut auth.auth, value);
222 assert(auth@ == old(auth)@.insert(cpu, value));
223 assert(auth@.dom() == old(auth)@.dom());
224 }
225
226 pub proof fn lemma_distinct(tracked &mut self, tracked other: &CpuLocalPointsTo<V>)
228 requires
229 old(self).id() == other.id(),
230 ensures
231 final(self).id() == old(self).id(),
232 final(self).cpu() == old(self).cpu(),
233 final(self).value() == old(self).value(),
234 final(self).cpu() != other.cpu(),
235 {
236 self.points_to.disjoint(&other.points_to);
237 }
238
239 pub proof fn lemma_same_cpu_has_distinct_auth(
242 tracked &mut self,
243 tracked other: &CpuLocalPointsTo<V>,
244 )
245 requires
246 old(self).cpu() == other.cpu(),
247 ensures
248 final(self).id() == old(self).id(),
249 final(self).cpu() == old(self).cpu(),
250 final(self).value() == old(self).value(),
251 final(self).id() != other.id(),
252 {
253 if self.id() == other.id() {
254 self.points_to.disjoint(&other.points_to);
255 }
256 }
257}
258
259proof fn cpu_local_points_to_smoke_test<V>(
262 initial: Map<CpuId, V>,
263 cpu1: CpuId,
264 cpu2: CpuId,
265 new_value: V,
266)
267 requires
268 initial.contains_key(cpu1),
269 initial.contains_key(cpu2),
270 cpu1 != cpu2,
271{
272 let tracked (mut auth, mut points_to_set) = CpuLocalAuth::new(initial);
273 let tracked mut points_to1 = points_to_set.tracked_take(cpu1);
274 let tracked mut points_to2 = points_to_set.tracked_take(cpu2);
275
276 points_to1.lemma_distinct(&points_to2);
277 let ghost old_cpu2_value = points_to2.value();
278 points_to1.tracked_update(&mut auth, new_value);
279 points_to2.lemma_agree(&auth);
280 assert(points_to2.value() == old_cpu2_value);
281
282 points_to_set.tracked_return(points_to1);
283 points_to_set.tracked_return(points_to2);
284 assert(points_to_set.cpus() == initial.dom());
285}
286
287}