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