Skip to content

Commit 6ac5bbb

Browse files
committed
Auto merge of #3823 - RalfJung:sync, r=RalfJung
simplify synchronization object creation logic
2 parents 3e698d0 + 7c81120 commit 6ac5bbb

File tree

2 files changed

+27
-102
lines changed

2 files changed

+27
-102
lines changed

src/tools/miri/src/concurrency/init_once.rs

+2-24
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,6 @@ pub(super) struct InitOnce {
2626
clock: VClock,
2727
}
2828

29-
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
30-
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
31-
/// Provides the closure with the next InitOnceId. Creates that InitOnce if the closure returns None,
32-
/// otherwise returns the value from the closure.
33-
#[inline]
34-
fn init_once_get_or_create<F>(&mut self, existing: F) -> InterpResult<'tcx, InitOnceId>
35-
where
36-
F: FnOnce(&mut MiriInterpCx<'tcx>, InitOnceId) -> InterpResult<'tcx, Option<InitOnceId>>,
37-
{
38-
let this = self.eval_context_mut();
39-
let next_index = this.machine.sync.init_onces.next_index();
40-
if let Some(old) = existing(this, next_index)? {
41-
Ok(old)
42-
} else {
43-
let new_index = this.machine.sync.init_onces.push(Default::default());
44-
assert_eq!(next_index, new_index);
45-
Ok(new_index)
46-
}
47-
}
48-
}
49-
5029
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
5130
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
5231
fn init_once_get_or_create_id(
@@ -56,9 +35,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
5635
offset: u64,
5736
) -> InterpResult<'tcx, InitOnceId> {
5837
let this = self.eval_context_mut();
59-
this.init_once_get_or_create(|ecx, next_id| {
60-
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
61-
})
38+
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.init_onces)?
39+
.ok_or_else(|| err_ub_format!("init_once has invalid ID").into())
6240
}
6341

6442
#[inline]

src/tools/miri/src/concurrency/sync.rs

+25-78
Original file line numberDiff line numberDiff line change
@@ -164,100 +164,50 @@ pub struct SynchronizationObjects {
164164
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
165165
pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
166166
/// Lazily initialize the ID of this Miri sync structure.
167-
/// ('0' indicates uninit.)
167+
/// If memory stores '0', that indicates uninit and we generate a new instance.
168+
/// Returns `None` if memory stores a non-zero invalid ID.
169+
///
170+
/// `get_objs` must return the `IndexVec` that stores all the objects of this type.
168171
#[inline]
169-
fn get_or_create_id<Id: SyncId>(
172+
fn get_or_create_id<Id: SyncId + Idx, T: Default>(
170173
&mut self,
171-
next_id: Id,
172174
lock_op: &OpTy<'tcx>,
173175
lock_layout: TyAndLayout<'tcx>,
174176
offset: u64,
177+
get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec<Id, T>,
175178
) -> InterpResult<'tcx, Option<Id>> {
176179
let this = self.eval_context_mut();
177180
let value_place =
178181
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
182+
let next_index = get_objs(this).next_index();
179183

180184
// Since we are lazy, this update has to be atomic.
181185
let (old, success) = this
182186
.atomic_compare_exchange_scalar(
183187
&value_place,
184188
&ImmTy::from_uint(0u32, this.machine.layouts.u32),
185-
Scalar::from_u32(next_id.to_u32()),
189+
Scalar::from_u32(next_index.to_u32()),
186190
AtomicRwOrd::Relaxed, // deliberately *no* synchronization
187191
AtomicReadOrd::Relaxed,
188192
false,
189193
)?
190194
.to_scalar_pair();
191195

192196
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
193-
// Caller of the closure needs to allocate next_id
194-
None
195-
} else {
196-
Some(Id::from_u32(old.to_u32().expect("layout is u32")))
197-
})
198-
}
199-
200-
/// Provides the closure with the next MutexId. Creates that mutex if the closure returns None,
201-
/// otherwise returns the value from the closure.
202-
#[inline]
203-
fn mutex_get_or_create<F>(&mut self, existing: F) -> InterpResult<'tcx, MutexId>
204-
where
205-
F: FnOnce(&mut MiriInterpCx<'tcx>, MutexId) -> InterpResult<'tcx, Option<MutexId>>,
206-
{
207-
let this = self.eval_context_mut();
208-
let next_index = this.machine.sync.mutexes.next_index();
209-
if let Some(old) = existing(this, next_index)? {
210-
if this.machine.sync.mutexes.get(old).is_none() {
211-
throw_ub_format!("mutex has invalid ID");
212-
}
213-
Ok(old)
214-
} else {
215-
let new_index = this.machine.sync.mutexes.push(Default::default());
197+
// We set the in-memory ID to `next_index`, now also create this object in the machine
198+
// state.
199+
let new_index = get_objs(this).push(T::default());
216200
assert_eq!(next_index, new_index);
217-
Ok(new_index)
218-
}
219-
}
220-
221-
/// Provides the closure with the next RwLockId. Creates that RwLock if the closure returns None,
222-
/// otherwise returns the value from the closure.
223-
#[inline]
224-
fn rwlock_get_or_create<F>(&mut self, existing: F) -> InterpResult<'tcx, RwLockId>
225-
where
226-
F: FnOnce(&mut MiriInterpCx<'tcx>, RwLockId) -> InterpResult<'tcx, Option<RwLockId>>,
227-
{
228-
let this = self.eval_context_mut();
229-
let next_index = this.machine.sync.rwlocks.next_index();
230-
if let Some(old) = existing(this, next_index)? {
231-
if this.machine.sync.rwlocks.get(old).is_none() {
232-
throw_ub_format!("rwlock has invalid ID");
233-
}
234-
Ok(old)
201+
Some(new_index)
235202
} else {
236-
let new_index = this.machine.sync.rwlocks.push(Default::default());
237-
assert_eq!(next_index, new_index);
238-
Ok(new_index)
239-
}
240-
}
241-
242-
/// Provides the closure with the next CondvarId. Creates that Condvar if the closure returns None,
243-
/// otherwise returns the value from the closure.
244-
#[inline]
245-
fn condvar_get_or_create<F>(&mut self, existing: F) -> InterpResult<'tcx, CondvarId>
246-
where
247-
F: FnOnce(&mut MiriInterpCx<'tcx>, CondvarId) -> InterpResult<'tcx, Option<CondvarId>>,
248-
{
249-
let this = self.eval_context_mut();
250-
let next_index = this.machine.sync.condvars.next_index();
251-
if let Some(old) = existing(this, next_index)? {
252-
if this.machine.sync.condvars.get(old).is_none() {
253-
throw_ub_format!("condvar has invalid ID");
203+
let id = Id::from_u32(old.to_u32().expect("layout is u32"));
204+
if get_objs(this).get(id).is_none() {
205+
// The in-memory ID is invalid.
206+
None
207+
} else {
208+
Some(id)
254209
}
255-
Ok(old)
256-
} else {
257-
let new_index = this.machine.sync.condvars.push(Default::default());
258-
assert_eq!(next_index, new_index);
259-
Ok(new_index)
260-
}
210+
})
261211
}
262212

263213
fn condvar_reacquire_mutex(
@@ -293,9 +243,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
293243
offset: u64,
294244
) -> InterpResult<'tcx, MutexId> {
295245
let this = self.eval_context_mut();
296-
this.mutex_get_or_create(|ecx, next_id| {
297-
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
298-
})
246+
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.mutexes)?
247+
.ok_or_else(|| err_ub_format!("mutex has invalid ID").into())
299248
}
300249

301250
fn rwlock_get_or_create_id(
@@ -305,9 +254,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
305254
offset: u64,
306255
) -> InterpResult<'tcx, RwLockId> {
307256
let this = self.eval_context_mut();
308-
this.rwlock_get_or_create(|ecx, next_id| {
309-
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
310-
})
257+
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.rwlocks)?
258+
.ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
311259
}
312260

313261
fn condvar_get_or_create_id(
@@ -317,9 +265,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
317265
offset: u64,
318266
) -> InterpResult<'tcx, CondvarId> {
319267
let this = self.eval_context_mut();
320-
this.condvar_get_or_create(|ecx, next_id| {
321-
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
322-
})
268+
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.condvars)?
269+
.ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
323270
}
324271

325272
#[inline]

0 commit comments

Comments
 (0)