@@ -35,6 +35,10 @@ macro_rules! declare_id {
35
35
}
36
36
}
37
37
38
+ impl $crate::VisitProvenance for $name {
39
+ fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
40
+ }
41
+
38
42
impl Idx for $name {
39
43
fn new(idx: usize) -> Self {
40
44
// We use 0 as a sentinel value (see the comment above) and,
@@ -258,6 +262,25 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
258
262
Ok(new_index)
259
263
}
260
264
}
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
+ }
261
284
}
262
285
263
286
// Public interface to synchronization primitives. Please note that in most
@@ -384,29 +407,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
384
407
assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
385
408
let thread = this.active_thread();
386
409
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
+ );
410
427
}
411
428
412
429
#[inline]
@@ -500,27 +517,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
500
517
let thread = this.active_thread();
501
518
assert!(this.rwlock_is_write_locked(id), "read-queueing on not write locked rwlock");
502
519
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
+ );
524
536
}
525
537
526
538
/// Lock by setting the writer that owns the lock.
@@ -588,27 +600,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
588
600
assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock");
589
601
let thread = this.active_thread();
590
602
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
+ );
612
619
}
613
620
614
621
/// Is the conditional variable awaited?
@@ -648,71 +655,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
648
655
this.block_thread(
649
656
BlockReason::Condvar(condvar),
650
657
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>,
685
665
}
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)
697
677
}
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(());
716
689
}
717
690
718
691
/// 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> {
755
728
this.block_thread(
756
729
BlockReason::Futex { addr },
757
730
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>,
783
738
}
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
+ );
802
761
}
803
762
804
763
/// Returns whether anything was woken.
0 commit comments