Skip to content

Commit 7cf32a7

Browse files
beepster4096RalfJung
authored andcommitted
code reuse for sync ids
1 parent 7ca6b17 commit 7cf32a7

File tree

4 files changed

+110
-162
lines changed

4 files changed

+110
-162
lines changed

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

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ use super::thread::MachineCallback;
1111
use super::vector_clock::VClock;
1212
use crate::*;
1313

14+
pub trait SyncId {
15+
fn from_u32(id: u32) -> Self;
16+
fn to_u32_scalar(&self) -> Scalar<Provenance>;
17+
}
18+
1419
/// We cannot use the `newtype_index!` macro because we have to use 0 as a
1520
/// sentinel value meaning that the identifier is not assigned. This is because
1621
/// the pthreads static initializers initialize memory with zeros (see the
@@ -22,11 +27,14 @@ macro_rules! declare_id {
2227
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
2328
pub struct $name(NonZeroU32);
2429

25-
impl $name {
30+
impl SyncId for $name {
2631
// Panics if `id == 0`.
27-
pub fn from_u32(id: u32) -> Self {
32+
fn from_u32(id: u32) -> Self {
2833
Self(NonZeroU32::new(id).unwrap())
2934
}
35+
fn to_u32_scalar(&self) -> Scalar<Provenance> {
36+
Scalar::from_u32(self.0.get())
37+
}
3038
}
3139

3240
impl Idx for $name {
@@ -166,7 +174,7 @@ impl<'mir, 'tcx> std::fmt::Debug for InitOnceWaiter<'mir, 'tcx> {
166174
}
167175
}
168176

169-
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq,)]
177+
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
170178
/// The current status of a one time initialization.
171179
pub enum InitOnceStatus {
172180
#[default]
@@ -212,6 +220,37 @@ impl<'mir, 'tcx> VisitTags for SynchronizationState<'mir, 'tcx> {
212220
// Private extension trait for local helper methods
213221
impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
214222
trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
223+
#[inline]
224+
// Miri sync structures contain zero-initialized ids stored at some offset behind a pointer
225+
fn get_or_create_id<Id: SyncId>(
226+
&mut self,
227+
next_id: Id,
228+
lock_op: &OpTy<'tcx, Provenance>,
229+
offset: u64,
230+
) -> InterpResult<'tcx, Option<Id>> {
231+
let this = self.eval_context_mut();
232+
let value_place =
233+
this.deref_operand_and_offset(lock_op, offset, this.machine.layouts.u32)?;
234+
235+
let (old, success) = this
236+
.atomic_compare_exchange_scalar(
237+
&value_place,
238+
&ImmTy::from_uint(0u32, this.machine.layouts.u32),
239+
next_id.to_u32_scalar(),
240+
AtomicRwOrd::Relaxed,
241+
AtomicReadOrd::Relaxed,
242+
false,
243+
)?
244+
.to_scalar_pair();
245+
246+
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
247+
// Caller of the closure needs to allocate next_id
248+
None
249+
} else {
250+
Some(Id::from_u32(old.to_u32().expect("layout is u32")))
251+
})
252+
}
253+
215254
/// Take a reader out of the queue waiting for the lock.
216255
/// Returns `true` if some thread got the rwlock.
217256
#[inline]
@@ -261,6 +300,48 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
261300
// situations.
262301
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
263302
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
303+
fn mutex_get_or_create_id(
304+
&mut self,
305+
lock_op: &OpTy<'tcx, Provenance>,
306+
offset: u64,
307+
) -> InterpResult<'tcx, MutexId> {
308+
let this = self.eval_context_mut();
309+
this.mutex_get_or_create(|ecx, next_id| Ok(ecx.get_or_create_id(next_id, lock_op, offset)?))
310+
}
311+
312+
fn rwlock_get_or_create_id(
313+
&mut self,
314+
lock_op: &OpTy<'tcx, Provenance>,
315+
offset: u64,
316+
) -> InterpResult<'tcx, RwLockId> {
317+
let this = self.eval_context_mut();
318+
this.rwlock_get_or_create(
319+
|ecx, next_id| Ok(ecx.get_or_create_id(next_id, lock_op, offset)?),
320+
)
321+
}
322+
323+
fn condvar_get_or_create_id(
324+
&mut self,
325+
lock_op: &OpTy<'tcx, Provenance>,
326+
offset: u64,
327+
) -> InterpResult<'tcx, CondvarId> {
328+
let this = self.eval_context_mut();
329+
this.condvar_get_or_create(|ecx, next_id| {
330+
Ok(ecx.get_or_create_id(next_id, lock_op, offset)?)
331+
})
332+
}
333+
334+
fn init_once_get_or_create_id(
335+
&mut self,
336+
lock_op: &OpTy<'tcx, Provenance>,
337+
offset: u64,
338+
) -> InterpResult<'tcx, InitOnceId> {
339+
let this = self.eval_context_mut();
340+
this.init_once_get_or_create(|ecx, next_id| {
341+
Ok(ecx.get_or_create_id(next_id, lock_op, offset)?)
342+
})
343+
}
344+
264345
#[inline]
265346
/// Create state for a new mutex.
266347
fn mutex_create(&mut self) -> MutexId {

src/tools/miri/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub use crate::concurrency::{
8787
AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd,
8888
EvalContextExt as DataRaceEvalContextExt,
8989
},
90-
sync::{CondvarId, EvalContextExt as SyncEvalContextExt, InitOnceId, MutexId, RwLockId},
90+
sync::{CondvarId, EvalContextExt as SyncEvalContextExt, InitOnceId, MutexId, RwLockId, SyncId},
9191
thread::{
9292
EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager,
9393
ThreadState, Time,

src/tools/miri/src/shims/unix/sync.rs

Lines changed: 17 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -108,33 +108,6 @@ fn mutex_set_id<'mir, 'tcx: 'mir>(
108108
)
109109
}
110110

111-
fn mutex_get_or_create_id<'mir, 'tcx: 'mir>(
112-
ecx: &mut MiriInterpCx<'mir, 'tcx>,
113-
mutex_op: &OpTy<'tcx, Provenance>,
114-
) -> InterpResult<'tcx, MutexId> {
115-
let value_place = ecx.deref_operand_and_offset(mutex_op, 4, ecx.machine.layouts.u32)?;
116-
117-
ecx.mutex_get_or_create(|ecx, next_id| {
118-
let (old, success) = ecx
119-
.atomic_compare_exchange_scalar(
120-
&value_place,
121-
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
122-
next_id.to_u32_scalar(),
123-
AtomicRwOrd::Relaxed,
124-
AtomicReadOrd::Relaxed,
125-
false,
126-
)?
127-
.to_scalar_pair();
128-
129-
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
130-
// Caller of the closure needs to allocate next_id
131-
None
132-
} else {
133-
Some(MutexId::from_u32(old.to_u32().expect("layout is u32")))
134-
})
135-
})
136-
}
137-
138111
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
139112

140113
// Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!):
@@ -149,33 +122,6 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>(
149122
ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed)
150123
}
151124

152-
fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>(
153-
ecx: &mut MiriInterpCx<'mir, 'tcx>,
154-
rwlock_op: &OpTy<'tcx, Provenance>,
155-
) -> InterpResult<'tcx, RwLockId> {
156-
let value_place = ecx.deref_operand_and_offset(rwlock_op, 4, ecx.machine.layouts.u32)?;
157-
158-
ecx.rwlock_get_or_create(|ecx, next_id| {
159-
let (old, success) = ecx
160-
.atomic_compare_exchange_scalar(
161-
&value_place,
162-
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
163-
next_id.to_u32_scalar(),
164-
AtomicRwOrd::Relaxed,
165-
AtomicReadOrd::Relaxed,
166-
false,
167-
)?
168-
.to_scalar_pair();
169-
170-
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
171-
// Caller of the closure needs to allocate next_id
172-
None
173-
} else {
174-
Some(RwLockId::from_u32(old.to_u32().expect("layout is u32")))
175-
})
176-
})
177-
}
178-
179125
// pthread_condattr_t
180126

181127
// Our chosen memory layout for emulation (does not have to match the platform layout!):
@@ -232,33 +178,6 @@ fn cond_set_id<'mir, 'tcx: 'mir>(
232178
)
233179
}
234180

235-
fn cond_get_or_create_id<'mir, 'tcx: 'mir>(
236-
ecx: &mut MiriInterpCx<'mir, 'tcx>,
237-
cond_op: &OpTy<'tcx, Provenance>,
238-
) -> InterpResult<'tcx, CondvarId> {
239-
let value_place = ecx.deref_operand_and_offset(cond_op, 4, ecx.machine.layouts.u32)?;
240-
241-
ecx.condvar_get_or_create(|ecx, next_id| {
242-
let (old, success) = ecx
243-
.atomic_compare_exchange_scalar(
244-
&value_place,
245-
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
246-
next_id.to_u32_scalar(),
247-
AtomicRwOrd::Relaxed,
248-
AtomicReadOrd::Relaxed,
249-
false,
250-
)?
251-
.to_scalar_pair();
252-
253-
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
254-
// Caller of the closure needs to allocate next_id
255-
None
256-
} else {
257-
Some(CondvarId::from_u32(old.to_u32().expect("layout is u32")))
258-
})
259-
})
260-
}
261-
262181
fn cond_get_clock_id<'mir, 'tcx: 'mir>(
263182
ecx: &MiriInterpCx<'mir, 'tcx>,
264183
cond_op: &OpTy<'tcx, Provenance>,
@@ -435,7 +354,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
435354
let this = self.eval_context_mut();
436355

437356
let kind = mutex_get_kind(this, mutex_op)?;
438-
let id = mutex_get_or_create_id(this, mutex_op)?;
357+
let id = this.mutex_get_or_create_id(mutex_op, 4)?;
439358
let active_thread = this.get_active_thread();
440359

441360
if this.mutex_is_locked(id) {
@@ -475,7 +394,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
475394
let this = self.eval_context_mut();
476395

477396
let kind = mutex_get_kind(this, mutex_op)?;
478-
let id = mutex_get_or_create_id(this, mutex_op)?;
397+
let id = this.mutex_get_or_create_id(mutex_op, 4)?;
479398
let active_thread = this.get_active_thread();
480399

481400
if this.mutex_is_locked(id) {
@@ -511,7 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
511430
let this = self.eval_context_mut();
512431

513432
let kind = mutex_get_kind(this, mutex_op)?;
514-
let id = mutex_get_or_create_id(this, mutex_op)?;
433+
let id = this.mutex_get_or_create_id(mutex_op, 4)?;
515434
let active_thread = this.get_active_thread();
516435

517436
if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread) {
@@ -545,7 +464,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
545464
) -> InterpResult<'tcx, i32> {
546465
let this = self.eval_context_mut();
547466

548-
let id = mutex_get_or_create_id(this, mutex_op)?;
467+
let id = this.mutex_get_or_create_id(mutex_op, 4)?;
549468

550469
if this.mutex_is_locked(id) {
551470
throw_ub_format!("destroyed a locked mutex");
@@ -568,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
568487
) -> InterpResult<'tcx, i32> {
569488
let this = self.eval_context_mut();
570489

571-
let id = rwlock_get_or_create_id(this, rwlock_op)?;
490+
let id = this.rwlock_get_or_create_id(rwlock_op, 4)?;
572491
let active_thread = this.get_active_thread();
573492

574493
if this.rwlock_is_write_locked(id) {
@@ -586,7 +505,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
586505
) -> InterpResult<'tcx, i32> {
587506
let this = self.eval_context_mut();
588507

589-
let id = rwlock_get_or_create_id(this, rwlock_op)?;
508+
let id = this.rwlock_get_or_create_id(rwlock_op, 4)?;
590509
let active_thread = this.get_active_thread();
591510

592511
if this.rwlock_is_write_locked(id) {
@@ -603,7 +522,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
603522
) -> InterpResult<'tcx, i32> {
604523
let this = self.eval_context_mut();
605524

606-
let id = rwlock_get_or_create_id(this, rwlock_op)?;
525+
let id = this.rwlock_get_or_create_id(rwlock_op, 4)?;
607526
let active_thread = this.get_active_thread();
608527

609528
if this.rwlock_is_locked(id) {
@@ -633,7 +552,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
633552
) -> InterpResult<'tcx, i32> {
634553
let this = self.eval_context_mut();
635554

636-
let id = rwlock_get_or_create_id(this, rwlock_op)?;
555+
let id = this.rwlock_get_or_create_id(rwlock_op, 4)?;
637556
let active_thread = this.get_active_thread();
638557

639558
if this.rwlock_is_locked(id) {
@@ -650,7 +569,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
650569
) -> InterpResult<'tcx, i32> {
651570
let this = self.eval_context_mut();
652571

653-
let id = rwlock_get_or_create_id(this, rwlock_op)?;
572+
let id = this.rwlock_get_or_create_id(rwlock_op, 4)?;
654573
let active_thread = this.get_active_thread();
655574

656575
#[allow(clippy::if_same_then_else)]
@@ -669,7 +588,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
669588
) -> InterpResult<'tcx, i32> {
670589
let this = self.eval_context_mut();
671590

672-
let id = rwlock_get_or_create_id(this, rwlock_op)?;
591+
let id = this.rwlock_get_or_create_id(rwlock_op, 4)?;
673592

674593
if this.rwlock_is_locked(id) {
675594
throw_ub_format!("destroyed a locked rwlock");
@@ -772,7 +691,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
772691

773692
fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
774693
let this = self.eval_context_mut();
775-
let id = cond_get_or_create_id(this, cond_op)?;
694+
let id = this.condvar_get_or_create_id(cond_op, 4)?;
776695
if let Some((thread, mutex)) = this.condvar_signal(id) {
777696
post_cond_signal(this, thread, mutex)?;
778697
}
@@ -785,7 +704,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
785704
cond_op: &OpTy<'tcx, Provenance>,
786705
) -> InterpResult<'tcx, i32> {
787706
let this = self.eval_context_mut();
788-
let id = cond_get_or_create_id(this, cond_op)?;
707+
let id = this.condvar_get_or_create_id(cond_op, 4)?;
789708

790709
while let Some((thread, mutex)) = this.condvar_signal(id) {
791710
post_cond_signal(this, thread, mutex)?;
@@ -801,8 +720,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
801720
) -> InterpResult<'tcx, i32> {
802721
let this = self.eval_context_mut();
803722

804-
let id = cond_get_or_create_id(this, cond_op)?;
805-
let mutex_id = mutex_get_or_create_id(this, mutex_op)?;
723+
let id = this.condvar_get_or_create_id(cond_op, 4)?;
724+
let mutex_id = this.mutex_get_or_create_id(mutex_op, 4)?;
806725
let active_thread = this.get_active_thread();
807726

808727
release_cond_mutex_and_block(this, active_thread, mutex_id)?;
@@ -822,8 +741,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
822741

823742
this.check_no_isolation("`pthread_cond_timedwait`")?;
824743

825-
let id = cond_get_or_create_id(this, cond_op)?;
826-
let mutex_id = mutex_get_or_create_id(this, mutex_op)?;
744+
let id = this.condvar_get_or_create_id(cond_op, 4)?;
745+
let mutex_id = this.mutex_get_or_create_id(mutex_op, 4)?;
827746
let active_thread = this.get_active_thread();
828747

829748
// Extract the timeout.
@@ -899,7 +818,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
899818
) -> InterpResult<'tcx, i32> {
900819
let this = self.eval_context_mut();
901820

902-
let id = cond_get_or_create_id(this, cond_op)?;
821+
let id = this.condvar_get_or_create_id(cond_op, 4)?;
903822
if this.condvar_is_awaited(id) {
904823
throw_ub_format!("destroying an awaited conditional variable");
905824
}

0 commit comments

Comments
 (0)