Skip to content

Commit 2e89443

Browse files
committedMay 26, 2024
add a macro to declare thread unblock callbacks
1 parent e6bb468 commit 2e89443

File tree

6 files changed

+256
-249
lines changed

6 files changed

+256
-249
lines changed
 

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7575
fn init_once_enqueue_and_block(
7676
&mut self,
7777
id: InitOnceId,
78-
callback: impl UnblockCallback<'mir, 'tcx> + 'tcx,
78+
callback: impl UnblockCallback<'tcx> + 'tcx,
7979
) {
8080
let this = self.eval_context_mut();
8181
let thread = this.active_thread();

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

Lines changed: 130 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ macro_rules! declare_id {
3535
}
3636
}
3737

38+
impl $crate::VisitProvenance for $name {
39+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
40+
}
41+
3842
impl Idx for $name {
3943
fn new(idx: usize) -> Self {
4044
// We use 0 as a sentinel value (see the comment above) and,
@@ -258,6 +262,25 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
258262
Ok(new_index)
259263
}
260264
}
265+
266+
fn condvar_reacquire_mutex(
267+
&mut self,
268+
mutex: MutexId,
269+
retval: Scalar<Provenance>,
270+
dest: MPlaceTy<'tcx, Provenance>,
271+
) -> InterpResult<'tcx> {
272+
let this = self.eval_context_mut();
273+
if this.mutex_is_locked(mutex) {
274+
assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
275+
this.mutex_enqueue_and_block(mutex, retval, dest);
276+
} else {
277+
// We can have it right now!
278+
this.mutex_lock(mutex);
279+
// Don't forget to write the return value.
280+
this.write_scalar(retval, &dest)?;
281+
}
282+
Ok(())
283+
}
261284
}
262285

263286
// Public interface to synchronization primitives. Please note that in most
@@ -384,29 +407,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
384407
assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
385408
let thread = this.active_thread();
386409
this.machine.sync.mutexes[id].queue.push_back(thread);
387-
this.block_thread(BlockReason::Mutex(id), None, Callback { id, retval, dest });
388-
389-
struct Callback<'tcx> {
390-
id: MutexId,
391-
retval: Scalar<Provenance>,
392-
dest: MPlaceTy<'tcx, Provenance>,
393-
}
394-
impl<'tcx> VisitProvenance for Callback<'tcx> {
395-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
396-
let Callback { id: _, retval, dest } = self;
397-
retval.visit_provenance(visit);
398-
dest.visit_provenance(visit);
399-
}
400-
}
401-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for Callback<'tcx> {
402-
fn unblock(self: Box<Self>, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
403-
assert!(!this.mutex_is_locked(self.id));
404-
this.mutex_lock(self.id);
405-
406-
this.write_scalar(self.retval, &self.dest)?;
407-
Ok(())
408-
}
409-
}
410+
this.block_thread(
411+
BlockReason::Mutex(id),
412+
None,
413+
callback!(
414+
@capture<'tcx> {
415+
id: MutexId,
416+
retval: Scalar<Provenance>,
417+
dest: MPlaceTy<'tcx, Provenance>,
418+
}
419+
@unblock = |this| {
420+
assert!(!this.mutex_is_locked(id));
421+
this.mutex_lock(id);
422+
this.write_scalar(retval, &dest)?;
423+
Ok(())
424+
}
425+
),
426+
);
410427
}
411428

412429
#[inline]
@@ -500,27 +517,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
500517
let thread = this.active_thread();
501518
assert!(this.rwlock_is_write_locked(id), "read-queueing on not write locked rwlock");
502519
this.machine.sync.rwlocks[id].reader_queue.push_back(thread);
503-
this.block_thread(BlockReason::RwLock(id), None, Callback { id, retval, dest });
504-
505-
struct Callback<'tcx> {
506-
id: RwLockId,
507-
retval: Scalar<Provenance>,
508-
dest: MPlaceTy<'tcx, Provenance>,
509-
}
510-
impl<'tcx> VisitProvenance for Callback<'tcx> {
511-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
512-
let Callback { id: _, retval, dest } = self;
513-
retval.visit_provenance(visit);
514-
dest.visit_provenance(visit);
515-
}
516-
}
517-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for Callback<'tcx> {
518-
fn unblock(self: Box<Self>, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
519-
this.rwlock_reader_lock(self.id);
520-
this.write_scalar(self.retval, &self.dest)?;
521-
Ok(())
522-
}
523-
}
520+
this.block_thread(
521+
BlockReason::RwLock(id),
522+
None,
523+
callback!(
524+
@capture<'tcx> {
525+
id: RwLockId,
526+
retval: Scalar<Provenance>,
527+
dest: MPlaceTy<'tcx, Provenance>,
528+
}
529+
@unblock = |this| {
530+
this.rwlock_reader_lock(id);
531+
this.write_scalar(retval, &dest)?;
532+
Ok(())
533+
}
534+
),
535+
);
524536
}
525537

526538
/// Lock by setting the writer that owns the lock.
@@ -588,27 +600,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
588600
assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock");
589601
let thread = this.active_thread();
590602
this.machine.sync.rwlocks[id].writer_queue.push_back(thread);
591-
this.block_thread(BlockReason::RwLock(id), None, Callback { id, retval, dest });
592-
593-
struct Callback<'tcx> {
594-
id: RwLockId,
595-
retval: Scalar<Provenance>,
596-
dest: MPlaceTy<'tcx, Provenance>,
597-
}
598-
impl<'tcx> VisitProvenance for Callback<'tcx> {
599-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
600-
let Callback { id: _, retval, dest } = self;
601-
retval.visit_provenance(visit);
602-
dest.visit_provenance(visit);
603-
}
604-
}
605-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for Callback<'tcx> {
606-
fn unblock(self: Box<Self>, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
607-
this.rwlock_writer_lock(self.id);
608-
this.write_scalar(self.retval, &self.dest)?;
609-
Ok(())
610-
}
611-
}
603+
this.block_thread(
604+
BlockReason::RwLock(id),
605+
None,
606+
callback!(
607+
@capture<'tcx> {
608+
id: RwLockId,
609+
retval: Scalar<Provenance>,
610+
dest: MPlaceTy<'tcx, Provenance>,
611+
}
612+
@unblock = |this| {
613+
this.rwlock_writer_lock(id);
614+
this.write_scalar(retval, &dest)?;
615+
Ok(())
616+
}
617+
),
618+
);
612619
}
613620

614621
/// Is the conditional variable awaited?
@@ -648,71 +655,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
648655
this.block_thread(
649656
BlockReason::Condvar(condvar),
650657
timeout,
651-
Callback { condvar, mutex, retval_succ, retval_timeout, dest },
652-
);
653-
return Ok(());
654-
655-
struct Callback<'tcx> {
656-
condvar: CondvarId,
657-
mutex: MutexId,
658-
retval_succ: Scalar<Provenance>,
659-
retval_timeout: Scalar<Provenance>,
660-
dest: MPlaceTy<'tcx, Provenance>,
661-
}
662-
impl<'tcx> VisitProvenance for Callback<'tcx> {
663-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
664-
let Callback { condvar: _, mutex: _, retval_succ, retval_timeout, dest } = self;
665-
retval_succ.visit_provenance(visit);
666-
retval_timeout.visit_provenance(visit);
667-
dest.visit_provenance(visit);
668-
}
669-
}
670-
impl<'tcx, 'mir> Callback<'tcx> {
671-
#[allow(clippy::boxed_local)]
672-
fn reacquire_mutex(
673-
self: Box<Self>,
674-
this: &mut MiriInterpCx<'mir, 'tcx>,
675-
retval: Scalar<Provenance>,
676-
) -> InterpResult<'tcx> {
677-
if this.mutex_is_locked(self.mutex) {
678-
assert_ne!(this.mutex_get_owner(self.mutex), this.active_thread());
679-
this.mutex_enqueue_and_block(self.mutex, retval, self.dest);
680-
} else {
681-
// We can have it right now!
682-
this.mutex_lock(self.mutex);
683-
// Don't forget to write the return value.
684-
this.write_scalar(retval, &self.dest)?;
658+
callback!(
659+
@capture<'tcx> {
660+
condvar: CondvarId,
661+
mutex: MutexId,
662+
retval_succ: Scalar<Provenance>,
663+
retval_timeout: Scalar<Provenance>,
664+
dest: MPlaceTy<'tcx, Provenance>,
685665
}
686-
Ok(())
687-
}
688-
}
689-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for Callback<'tcx> {
690-
fn unblock(self: Box<Self>, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
691-
// The condvar was signaled. Make sure we get the clock for that.
692-
if let Some(data_race) = &this.machine.data_race {
693-
data_race.acquire_clock(
694-
&this.machine.sync.condvars[self.condvar].clock,
695-
&this.machine.threads,
696-
);
666+
@unblock = |this| {
667+
// The condvar was signaled. Make sure we get the clock for that.
668+
if let Some(data_race) = &this.machine.data_race {
669+
data_race.acquire_clock(
670+
&this.machine.sync.condvars[condvar].clock,
671+
&this.machine.threads,
672+
);
673+
}
674+
// Try to acquire the mutex.
675+
// The timeout only applies to the first wait (until the signal), not for mutex acquisition.
676+
this.condvar_reacquire_mutex(mutex, retval_succ, dest)
697677
}
698-
// Try to acquire the mutex.
699-
// The timeout only applies to the first wait (until the signal), not for mutex acquisition.
700-
let retval = self.retval_succ;
701-
self.reacquire_mutex(this, retval)
702-
}
703-
fn timeout(
704-
self: Box<Self>,
705-
this: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
706-
) -> InterpResult<'tcx> {
707-
// We have to remove the waiter from the queue again.
708-
let thread = this.active_thread();
709-
let waiters = &mut this.machine.sync.condvars[self.condvar].waiters;
710-
waiters.retain(|waiter| *waiter != thread);
711-
// Now get back the lock.
712-
let retval = self.retval_timeout;
713-
self.reacquire_mutex(this, retval)
714-
}
715-
}
678+
@timeout = |this| {
679+
// We have to remove the waiter from the queue again.
680+
let thread = this.active_thread();
681+
let waiters = &mut this.machine.sync.condvars[condvar].waiters;
682+
waiters.retain(|waiter| *waiter != thread);
683+
// Now get back the lock.
684+
this.condvar_reacquire_mutex(mutex, retval_timeout, dest)
685+
}
686+
),
687+
);
688+
return Ok(());
716689
}
717690

718691
/// Wake up some thread (if there is any) sleeping on the conditional
@@ -755,50 +728,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
755728
this.block_thread(
756729
BlockReason::Futex { addr },
757730
timeout,
758-
Callback { addr, retval_succ, retval_timeout, dest, errno_timeout },
759-
);
760-
761-
struct Callback<'tcx> {
762-
addr: u64,
763-
retval_succ: Scalar<Provenance>,
764-
retval_timeout: Scalar<Provenance>,
765-
dest: MPlaceTy<'tcx, Provenance>,
766-
errno_timeout: Scalar<Provenance>,
767-
}
768-
impl<'tcx> VisitProvenance for Callback<'tcx> {
769-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
770-
let Callback { addr: _, retval_succ, retval_timeout, dest, errno_timeout } = self;
771-
retval_succ.visit_provenance(visit);
772-
retval_timeout.visit_provenance(visit);
773-
dest.visit_provenance(visit);
774-
errno_timeout.visit_provenance(visit);
775-
}
776-
}
777-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for Callback<'tcx> {
778-
fn unblock(self: Box<Self>, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
779-
let futex = this.machine.sync.futexes.get(&self.addr).unwrap();
780-
// Acquire the clock of the futex.
781-
if let Some(data_race) = &this.machine.data_race {
782-
data_race.acquire_clock(&futex.clock, &this.machine.threads);
731+
callback!(
732+
@capture<'tcx> {
733+
addr: u64,
734+
retval_succ: Scalar<Provenance>,
735+
retval_timeout: Scalar<Provenance>,
736+
dest: MPlaceTy<'tcx, Provenance>,
737+
errno_timeout: Scalar<Provenance>,
783738
}
784-
// Write the return value.
785-
this.write_scalar(self.retval_succ, &self.dest)?;
786-
Ok(())
787-
}
788-
fn timeout(
789-
self: Box<Self>,
790-
this: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
791-
) -> InterpResult<'tcx> {
792-
// Remove the waiter from the futex.
793-
let thread = this.active_thread();
794-
let futex = this.machine.sync.futexes.get_mut(&self.addr).unwrap();
795-
futex.waiters.retain(|waiter| waiter.thread != thread);
796-
// Set errno and write return value.
797-
this.set_last_error(self.errno_timeout)?;
798-
this.write_scalar(self.retval_timeout, &self.dest)?;
799-
Ok(())
800-
}
801-
}
739+
@unblock = |this| {
740+
let futex = this.machine.sync.futexes.get(&addr).unwrap();
741+
// Acquire the clock of the futex.
742+
if let Some(data_race) = &this.machine.data_race {
743+
data_race.acquire_clock(&futex.clock, &this.machine.threads);
744+
}
745+
// Write the return value.
746+
this.write_scalar(retval_succ, &dest)?;
747+
Ok(())
748+
}
749+
@timeout = |this| {
750+
// Remove the waiter from the futex.
751+
let thread = this.active_thread();
752+
let futex = this.machine.sync.futexes.get_mut(&addr).unwrap();
753+
futex.waiters.retain(|waiter| waiter.thread != thread);
754+
// Set errno and write return value.
755+
this.set_last_error(errno_timeout)?;
756+
this.write_scalar(retval_timeout, &dest)?;
757+
Ok(())
758+
}
759+
),
760+
);
802761
}
803762

804763
/// Returns whether anything was woken.

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

Lines changed: 79 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,75 @@ pub enum TlsAllocAction {
4141
}
4242

4343
/// Trait for callbacks that are executed when a thread gets unblocked.
44-
pub trait UnblockCallback<'mir, 'tcx>: VisitProvenance {
45-
fn unblock(
44+
pub trait UnblockCallback<'tcx>: VisitProvenance {
45+
/// Will be invoked when the thread was unblocked the "regular" way,
46+
/// i.e. whatever event it was blocking on has happened.
47+
fn unblock<'mir>(
4648
self: Box<Self>,
4749
ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
4850
) -> InterpResult<'tcx>;
4951

50-
fn timeout(
52+
/// Will be invoked when the timeout ellapsed without the event the
53+
/// thread was blocking on having occurred.
54+
fn timeout<'mir>(
5155
self: Box<Self>,
5256
_ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
53-
) -> InterpResult<'tcx> {
54-
unreachable!(
55-
"timeout on a thread that was blocked without a timeout (or someone forgot to overwrite this method)"
57+
) -> InterpResult<'tcx>;
58+
}
59+
type DynUnblockCallback<'tcx> = Box<dyn UnblockCallback<'tcx> + 'tcx>;
60+
61+
#[macro_export]
62+
macro_rules! callback {
63+
(
64+
@capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
65+
@unblock = |$this:ident| $unblock:block
66+
) => {
67+
callback!(
68+
@capture<$tcx, $($lft),*> { $($name: $type),+ }
69+
@unblock = |$this| $unblock
70+
@timeout = |_this| {
71+
unreachable!(
72+
"timeout on a thread that was blocked without a timeout (or someone forgot to overwrite this method)"
73+
)
74+
}
5675
)
57-
}
76+
};
77+
(
78+
@capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
79+
@unblock = |$this:ident| $unblock:block
80+
@timeout = |$this_timeout:ident| $timeout:block
81+
) => {{
82+
struct Callback<$tcx, $($lft),*> {
83+
$($name: $type,)*
84+
_phantom: std::marker::PhantomData<&$tcx ()>,
85+
}
86+
87+
impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
88+
#[allow(unused_variables)]
89+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
90+
$(
91+
self.$name.visit_provenance(visit);
92+
)*
93+
}
94+
}
95+
96+
impl<$tcx, $($lft),*> UnblockCallback<$tcx> for Callback<$tcx, $($lft),*> {
97+
fn unblock<'mir>(self: Box<Self>, $this: &mut MiriInterpCx<'mir, $tcx>) -> InterpResult<$tcx> {
98+
#[allow(unused_variables)]
99+
let Callback { $($name,)* _phantom } = *self;
100+
$unblock
101+
}
102+
103+
fn timeout<'mir>(self: Box<Self>, $this_timeout: &mut MiriInterpCx<'mir, $tcx>) -> InterpResult<$tcx> {
104+
#[allow(unused_variables)]
105+
let Callback { $($name,)* _phantom } = *self;
106+
$timeout
107+
}
108+
}
109+
110+
Callback { $($name,)* _phantom: std::marker::PhantomData }
111+
}}
58112
}
59-
type DynUnblockCallback<'mir, 'tcx> = Box<dyn UnblockCallback<'mir, 'tcx> + 'tcx>;
60113

61114
/// A thread identifier.
62115
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -127,21 +180,17 @@ pub enum BlockReason {
127180
}
128181

129182
/// The state of a thread.
130-
enum ThreadState<'mir, 'tcx> {
183+
enum ThreadState<'tcx> {
131184
/// The thread is enabled and can be executed.
132185
Enabled,
133186
/// The thread is blocked on something.
134-
Blocked {
135-
reason: BlockReason,
136-
timeout: Option<Timeout>,
137-
callback: DynUnblockCallback<'mir, 'tcx>,
138-
},
187+
Blocked { reason: BlockReason, timeout: Option<Timeout>, callback: DynUnblockCallback<'tcx> },
139188
/// The thread has terminated its execution. We do not delete terminated
140189
/// threads (FIXME: why?).
141190
Terminated,
142191
}
143192

144-
impl<'mir, 'tcx> std::fmt::Debug for ThreadState<'mir, 'tcx> {
193+
impl<'tcx> std::fmt::Debug for ThreadState<'tcx> {
145194
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146195
match self {
147196
Self::Enabled => write!(f, "Enabled"),
@@ -152,7 +201,7 @@ impl<'mir, 'tcx> std::fmt::Debug for ThreadState<'mir, 'tcx> {
152201
}
153202
}
154203

155-
impl<'mir, 'tcx> ThreadState<'mir, 'tcx> {
204+
impl<'tcx> ThreadState<'tcx> {
156205
fn is_enabled(&self) -> bool {
157206
matches!(self, ThreadState::Enabled)
158207
}
@@ -180,7 +229,7 @@ enum ThreadJoinStatus {
180229

181230
/// A thread.
182231
pub struct Thread<'mir, 'tcx> {
183-
state: ThreadState<'mir, 'tcx>,
232+
state: ThreadState<'tcx>,
184233

185234
/// Name of the thread.
186235
thread_name: Option<Vec<u8>>,
@@ -582,26 +631,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
582631
self.block_thread(
583632
BlockReason::Join(joined_thread_id),
584633
None,
585-
Callback { joined_thread_id },
586-
);
587-
588-
struct Callback {
589-
joined_thread_id: ThreadId,
590-
}
591-
impl VisitProvenance for Callback {
592-
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
593-
}
594-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for Callback {
595-
fn unblock(
596-
self: Box<Self>,
597-
this: &mut MiriInterpCx<'mir, 'tcx>,
598-
) -> InterpResult<'tcx> {
599-
if let Some(data_race) = &mut this.machine.data_race {
600-
data_race.thread_joined(&this.machine.threads, self.joined_thread_id);
634+
callback!(
635+
@capture<'tcx> {
636+
joined_thread_id: ThreadId,
601637
}
602-
Ok(())
603-
}
604-
}
638+
@unblock = |this| {
639+
if let Some(data_race) = &mut this.machine.data_race {
640+
data_race.thread_joined(&this.machine.threads, joined_thread_id);
641+
}
642+
Ok(())
643+
}
644+
),
645+
);
605646
} else {
606647
// The thread has already terminated - establish happens-before
607648
if let Some(data_race) = data_race {
@@ -656,7 +697,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
656697
&mut self,
657698
reason: BlockReason,
658699
timeout: Option<Timeout>,
659-
callback: impl UnblockCallback<'mir, 'tcx> + 'tcx,
700+
callback: impl UnblockCallback<'tcx> + 'tcx,
660701
) {
661702
let state = &mut self.threads[self.active_thread].state;
662703
assert!(state.is_enabled());
@@ -963,7 +1004,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
9631004
&mut self,
9641005
reason: BlockReason,
9651006
timeout: Option<Timeout>,
966-
callback: impl UnblockCallback<'mir, 'tcx> + 'tcx,
1007+
callback: impl UnblockCallback<'tcx> + 'tcx,
9671008
) {
9681009
let this = self.eval_context_mut();
9691010
if !this.machine.communicate() && matches!(timeout, Some(Timeout::RealTime(..))) {

‎src/tools/miri/src/provenance_gc.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ pub trait VisitProvenance {
1010
fn visit_provenance(&self, visit: &mut VisitWith<'_>);
1111
}
1212

13+
// Trivial impls for types that do not contain any provenance
14+
macro_rules! no_provenance {
15+
($($ty:ident)+) => {
16+
$(
17+
impl VisitProvenance for $ty {
18+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
19+
}
20+
)+
21+
}
22+
}
23+
no_provenance!(i8 i16 i32 i64 isize u8 u16 u32 u64 usize ThreadId);
24+
1325
impl<T: VisitProvenance> VisitProvenance for Option<T> {
1426
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
1527
if let Some(x) = self {

‎src/tools/miri/src/shims/time.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
337337
.unwrap_or_else(|| now.checked_add(Duration::from_secs(3600)).unwrap());
338338
let timeout_time = Timeout::Monotonic(timeout_time);
339339

340-
this.block_thread(BlockReason::Sleep, Some(timeout_time), SleepCallback);
340+
this.block_thread(
341+
BlockReason::Sleep,
342+
Some(timeout_time),
343+
callback!(
344+
@capture<'tcx> {}
345+
@unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
346+
@timeout = |_this| { Ok(()) }
347+
),
348+
);
341349
Ok(0)
342350
}
343351

@@ -353,23 +361,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
353361
let timeout_time = this.machine.clock.now().checked_add(duration).unwrap();
354362
let timeout_time = Timeout::Monotonic(timeout_time);
355363

356-
this.block_thread(BlockReason::Sleep, Some(timeout_time), SleepCallback);
364+
this.block_thread(
365+
BlockReason::Sleep,
366+
Some(timeout_time),
367+
callback!(
368+
@capture<'tcx> {}
369+
@unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
370+
@timeout = |_this| { Ok(()) }
371+
),
372+
);
357373
Ok(())
358374
}
359375
}
360-
361-
struct SleepCallback;
362-
impl VisitProvenance for SleepCallback {
363-
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
364-
}
365-
impl<'mir, 'tcx: 'mir> UnblockCallback<'mir, 'tcx> for SleepCallback {
366-
fn timeout(self: Box<Self>, _this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
367-
Ok(())
368-
}
369-
fn unblock(
370-
self: Box<Self>,
371-
_this: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
372-
) -> InterpResult<'tcx> {
373-
panic!("a sleeping thread should only ever be woken up via the timeout")
374-
}
375-
}

‎src/tools/miri/src/shims/windows/sync.rs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,28 +76,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7676
}
7777

7878
// We have to block, and then try again when we are woken up.
79-
this.init_once_enqueue_and_block(id, Callback { id, pending_place, dest: dest.clone() });
79+
let dest = dest.clone();
80+
this.init_once_enqueue_and_block(
81+
id,
82+
callback!(
83+
@capture<'tcx> {
84+
id: InitOnceId,
85+
pending_place: MPlaceTy<'tcx, Provenance>,
86+
dest: MPlaceTy<'tcx, Provenance>,
87+
}
88+
@unblock = |this| {
89+
let ret = this.init_once_try_begin(id, &pending_place, &dest)?;
90+
assert!(ret, "we were woken up but init_once_try_begin still failed");
91+
Ok(())
92+
}
93+
),
94+
);
8095
return Ok(());
81-
82-
struct Callback<'tcx> {
83-
id: InitOnceId,
84-
pending_place: MPlaceTy<'tcx, Provenance>,
85-
dest: MPlaceTy<'tcx, Provenance>,
86-
}
87-
impl<'tcx> VisitProvenance for Callback<'tcx> {
88-
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
89-
let Callback { id: _, dest, pending_place } = self;
90-
pending_place.visit_provenance(visit);
91-
dest.visit_provenance(visit);
92-
}
93-
}
94-
impl<'mir, 'tcx> UnblockCallback<'mir, 'tcx> for Callback<'tcx> {
95-
fn unblock(self: Box<Self>, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
96-
let ret = this.init_once_try_begin(self.id, &self.pending_place, &self.dest)?;
97-
assert!(ret, "we were woken up but init_once_try_begin still failed");
98-
Ok(())
99-
}
100-
}
10196
}
10297

10398
fn InitOnceComplete(

0 commit comments

Comments
 (0)
Please sign in to comment.