Skip to content

Commit bfb36e3

Browse files
committed
Remove MutexID list
1 parent f736269 commit bfb36e3

File tree

5 files changed

+111
-86
lines changed

5 files changed

+111
-86
lines changed

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

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
use std::cell::RefCell;
12
use std::collections::VecDeque;
23
use std::collections::hash_map::Entry;
4+
use std::default::Default;
35
use std::ops::Not;
6+
use std::rc::Rc;
47
use std::time::Duration;
58

69
use rustc_data_structures::fx::FxHashMap;
@@ -44,8 +47,6 @@ macro_rules! declare_id {
4447
}
4548
pub(super) use declare_id;
4649

47-
declare_id!(MutexId);
48-
4950
/// The mutex state.
5051
#[derive(Default, Debug)]
5152
struct Mutex {
@@ -59,6 +60,21 @@ struct Mutex {
5960
clock: VClock,
6061
}
6162

63+
#[derive(Default, Clone, Debug)]
64+
pub struct MutexRef(Rc<RefCell<Mutex>>);
65+
66+
impl MutexRef {
67+
fn new() -> Self {
68+
MutexRef(Rc::new(RefCell::new(Mutex::default())))
69+
}
70+
}
71+
72+
impl VisitProvenance for MutexRef {
73+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
74+
// Mutex contains no provenance.
75+
}
76+
}
77+
6278
declare_id!(RwLockId);
6379

6480
/// The read-write lock state.
@@ -133,7 +149,6 @@ struct FutexWaiter {
133149
/// The state of all synchronization objects.
134150
#[derive(Default, Debug)]
135151
pub struct SynchronizationObjects {
136-
mutexes: IndexVec<MutexId, Mutex>,
137152
rwlocks: IndexVec<RwLockId, RwLock>,
138153
condvars: IndexVec<CondvarId, Condvar>,
139154
pub(super) init_onces: IndexVec<InitOnceId, InitOnce>,
@@ -147,17 +162,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
147162
pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
148163
fn condvar_reacquire_mutex(
149164
&mut self,
150-
mutex: MutexId,
165+
mutex_ref: &MutexRef,
151166
retval: Scalar,
152167
dest: MPlaceTy<'tcx>,
153168
) -> InterpResult<'tcx> {
154169
let this = self.eval_context_mut();
155-
if this.mutex_is_locked(mutex) {
156-
assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
157-
this.mutex_enqueue_and_block(mutex, Some((retval, dest)));
170+
if this.mutex_is_locked(mutex_ref) {
171+
assert_ne!(this.mutex_get_owner(mutex_ref), this.active_thread());
172+
this.mutex_enqueue_and_block(mutex_ref, Some((retval, dest)));
158173
} else {
159174
// We can have it right now!
160-
this.mutex_lock(mutex);
175+
this.mutex_lock(mutex_ref);
161176
// Don't forget to write the return value.
162177
this.write_scalar(retval, &dest)?;
163178
}
@@ -166,10 +181,9 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
166181
}
167182

168183
impl SynchronizationObjects {
169-
pub fn mutex_create(&mut self) -> MutexId {
170-
self.mutexes.push(Default::default())
184+
pub fn mutex_create(&mut self) -> MutexRef {
185+
MutexRef::new()
171186
}
172-
173187
pub fn rwlock_create(&mut self) -> RwLockId {
174188
self.rwlocks.push(Default::default())
175189
}
@@ -201,7 +215,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
201215
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
202216
/// Helper for lazily initialized `alloc_extra.sync` data:
203217
/// this forces an immediate init.
204-
fn lazy_sync_init<T: 'static + Copy>(
218+
fn lazy_sync_init<T: 'static>(
205219
&mut self,
206220
primitive: &MPlaceTy<'tcx>,
207221
init_offset: Size,
@@ -227,7 +241,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
227241
/// - If yes, fetches the data from `alloc_extra.sync`, or calls `missing_data` if that fails
228242
/// and stores that in `alloc_extra.sync`.
229243
/// - Otherwise, calls `new_data` to initialize the primitive.
230-
fn lazy_sync_get_data<T: 'static + Copy>(
244+
///
245+
/// The return value is a *clone* of the stored data, so if you intend to mutate it
246+
/// better wrap everything into an `Rc`.
247+
fn lazy_sync_get_data<T: 'static + Clone>(
231248
&mut self,
232249
primitive: &MPlaceTy<'tcx>,
233250
init_offset: Size,
@@ -258,15 +275,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
258275
let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
259276
let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc)?;
260277
if let Some(data) = alloc_extra.get_sync::<T>(offset) {
261-
interp_ok(*data)
278+
interp_ok(data.clone())
262279
} else {
263280
let data = missing_data()?;
264-
alloc_extra.sync.insert(offset, Box::new(data));
281+
alloc_extra.sync.insert(offset, Box::new(data.clone()));
265282
interp_ok(data)
266283
}
267284
} else {
268285
let data = new_data(this)?;
269-
this.lazy_sync_init(primitive, init_offset, data)?;
286+
this.lazy_sync_init(primitive, init_offset, data.clone())?;
270287
interp_ok(data)
271288
}
272289
}
@@ -298,23 +315,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
298315

299316
#[inline]
300317
/// Get the id of the thread that currently owns this lock.
301-
fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId {
302-
let this = self.eval_context_ref();
303-
this.machine.sync.mutexes[id].owner.unwrap()
318+
fn mutex_get_owner(&mut self, mutex_ref: &MutexRef) -> ThreadId {
319+
mutex_ref.0.borrow().owner.unwrap()
304320
}
305321

306322
#[inline]
307323
/// Check if locked.
308-
fn mutex_is_locked(&self, id: MutexId) -> bool {
309-
let this = self.eval_context_ref();
310-
this.machine.sync.mutexes[id].owner.is_some()
324+
fn mutex_is_locked(&self, mutex_ref: &MutexRef) -> bool {
325+
mutex_ref.0.borrow().owner.is_some()
311326
}
312327

313328
/// Lock by setting the mutex owner and increasing the lock count.
314-
fn mutex_lock(&mut self, id: MutexId) {
329+
fn mutex_lock(&mut self, mutex_ref: &MutexRef) {
315330
let this = self.eval_context_mut();
316331
let thread = this.active_thread();
317-
let mutex = &mut this.machine.sync.mutexes[id];
332+
let mut mutex = mutex_ref.0.borrow_mut();
318333
if let Some(current_owner) = mutex.owner {
319334
assert_eq!(thread, current_owner, "mutex already locked by another thread");
320335
assert!(
@@ -334,9 +349,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
334349
/// count. If the lock count reaches 0, release the lock and potentially
335350
/// give to a new owner. If the lock was not locked by the current thread,
336351
/// return `None`.
337-
fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<usize>> {
352+
fn mutex_unlock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx, Option<usize>> {
338353
let this = self.eval_context_mut();
339-
let mutex = &mut this.machine.sync.mutexes[id];
354+
let mut mutex = mutex_ref.0.borrow_mut();
340355
interp_ok(if let Some(current_owner) = mutex.owner {
341356
// Mutex is locked.
342357
if current_owner != this.machine.threads.active_thread() {
@@ -354,8 +369,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
354369
mutex.clock.clone_from(clock)
355370
});
356371
}
357-
if let Some(thread) = this.machine.sync.mutexes[id].queue.pop_front() {
358-
this.unblock_thread(thread, BlockReason::Mutex(id))?;
372+
let thread_id = mutex.queue.pop_front();
373+
// We need to drop our mutex borrow before unblock_thread
374+
// because it will be borrowed again in the unblock callback.
375+
drop(mutex);
376+
if thread_id.is_some() {
377+
this.unblock_thread(thread_id.unwrap(), BlockReason::Mutex)?;
359378
}
360379
}
361380
Some(old_lock_count)
@@ -372,24 +391,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
372391
#[inline]
373392
fn mutex_enqueue_and_block(
374393
&mut self,
375-
id: MutexId,
394+
mutex_ref: &MutexRef,
376395
retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
377396
) {
378397
let this = self.eval_context_mut();
379-
assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
398+
assert!(this.mutex_is_locked(mutex_ref), "queuing on unlocked mutex");
380399
let thread = this.active_thread();
381-
this.machine.sync.mutexes[id].queue.push_back(thread);
400+
mutex_ref.0.borrow_mut().queue.push_back(thread);
401+
let mutex_ref = mutex_ref.clone();
382402
this.block_thread(
383-
BlockReason::Mutex(id),
403+
BlockReason::Mutex,
384404
None,
385405
callback!(
386406
@capture<'tcx> {
387-
id: MutexId,
407+
mutex_ref: MutexRef,
388408
retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
389409
}
390410
@unblock = |this| {
391-
assert!(!this.mutex_is_locked(id));
392-
this.mutex_lock(id);
411+
assert!(!this.mutex_is_locked(&mutex_ref));
412+
this.mutex_lock(&mutex_ref);
393413

394414
if let Some((retval, dest)) = retval_dest {
395415
this.write_scalar(retval, &dest)?;
@@ -610,14 +630,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
610630
fn condvar_wait(
611631
&mut self,
612632
condvar: CondvarId,
613-
mutex: MutexId,
633+
mutex_ref: MutexRef,
614634
timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
615635
retval_succ: Scalar,
616636
retval_timeout: Scalar,
617637
dest: MPlaceTy<'tcx>,
618638
) -> InterpResult<'tcx> {
619639
let this = self.eval_context_mut();
620-
if let Some(old_locked_count) = this.mutex_unlock(mutex)? {
640+
if let Some(old_locked_count) = this.mutex_unlock(&mutex_ref)? {
621641
if old_locked_count != 1 {
622642
throw_unsup_format!(
623643
"awaiting a condvar on a mutex acquired multiple times is not supported"
@@ -637,7 +657,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
637657
callback!(
638658
@capture<'tcx> {
639659
condvar: CondvarId,
640-
mutex: MutexId,
660+
mutex_ref: MutexRef,
641661
retval_succ: Scalar,
642662
retval_timeout: Scalar,
643663
dest: MPlaceTy<'tcx>,
@@ -652,15 +672,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
652672
}
653673
// Try to acquire the mutex.
654674
// The timeout only applies to the first wait (until the signal), not for mutex acquisition.
655-
this.condvar_reacquire_mutex(mutex, retval_succ, dest)
675+
this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
656676
}
657677
@timeout = |this| {
658678
// We have to remove the waiter from the queue again.
659679
let thread = this.active_thread();
660680
let waiters = &mut this.machine.sync.condvars[condvar].waiters;
661681
waiters.retain(|waiter| *waiter != thread);
662682
// Now get back the lock.
663-
this.condvar_reacquire_mutex(mutex, retval_timeout, dest)
683+
this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
664684
}
665685
),
666686
);

src/tools/miri/src/concurrency/thread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ pub enum BlockReason {
162162
/// Waiting for time to pass.
163163
Sleep,
164164
/// Blocked on a mutex.
165-
Mutex(MutexId),
165+
Mutex,
166166
/// Blocked on a condition variable.
167167
Condvar(CondvarId),
168168
/// Blocked on a reader-writer lock.

src/tools/miri/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub use crate::concurrency::data_race::{
121121
};
122122
pub use crate::concurrency::init_once::{EvalContextExt as _, InitOnceId};
123123
pub use crate::concurrency::sync::{
124-
CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects,
124+
CondvarId, EvalContextExt as _, MutexRef, RwLockId, SynchronizationObjects,
125125
};
126126
pub use crate::concurrency::thread::{
127127
BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor,

0 commit comments

Comments
 (0)