Auto merge of #3631 - RalfJung:blocking-refactor, r=RalfJung · rust-lang/rust@0963353
@@ -47,7 +47,7 @@ use std::{
4747};
48484949use rustc_ast::Mutability;
50-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
50+use rustc_data_structures::fx::FxHashSet;
5151use rustc_index::{Idx, IndexVec};
5252use rustc_middle::{mir, ty::Ty};
5353use rustc_span::Span;
@@ -822,6 +822,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
822822assert!(!old, "cannot nest allow_data_races");
823823}
824824}
825+826+/// Returns the `release` clock of the current thread.
827+ /// Other threads can acquire this clock in the future to establish synchronization
828+ /// with this program point.
829+ fn release_clock<'a>(&'a self) -> Option<Ref<'a, VClock>>
830+where
831+'mir: 'a,
832+{
833+let this = self.eval_context_ref();
834+Some(this.machine.data_race.as_ref()?.release_clock(&this.machine.threads))
835+}
836+837+/// Acquire the given clock into the current thread, establishing synchronization with
838+ /// the moment when that clock snapshot was taken via `release_clock`.
839+ fn acquire_clock(&self, clock: &VClock) {
840+let this = self.eval_context_ref();
841+if let Some(data_race) = &this.machine.data_race {
842+ data_race.acquire_clock(clock, &this.machine.threads);
843+}
844+}
825845}
826846827847/// Vector clock metadata for a logical memory allocation.
@@ -1412,13 +1432,6 @@ pub struct GlobalState {
14121432 /// active vector-clocks catch up with the threads timestamp.
14131433 reuse_candidates: RefCell<FxHashSet<VectorIdx>>,
141414341415-/// This contains threads that have terminated, but not yet joined
1416- /// and so cannot become re-use candidates until a join operation
1417- /// occurs.
1418- /// The associated vector index will be moved into re-use candidates
1419- /// after the join operation occurs.
1420- terminated_threads: RefCell<FxHashMap<ThreadId, VectorIdx>>,
1421-14221435/// The timestamp of last SC fence performed by each thread
14231436 last_sc_fence: RefCell<VClock>,
14241437@@ -1446,7 +1459,6 @@ impl GlobalState {
14461459vector_info: RefCell::new(IndexVec::new()),
14471460thread_info: RefCell::new(IndexVec::new()),
14481461reuse_candidates: RefCell::new(FxHashSet::default()),
1449-terminated_threads: RefCell::new(FxHashMap::default()),
14501462last_sc_fence: RefCell::new(VClock::default()),
14511463last_sc_write: RefCell::new(VClock::default()),
14521464track_outdated_loads: config.track_outdated_loads,
@@ -1480,8 +1492,6 @@ impl GlobalState {
14801492fn find_vector_index_reuse_candidate(&self) -> Option<VectorIdx> {
14811493let mut reuse = self.reuse_candidates.borrow_mut();
14821494let vector_clocks = self.vector_clocks.borrow();
1483-let vector_info = self.vector_info.borrow();
1484-let terminated_threads = self.terminated_threads.borrow();
14851495for &candidate in reuse.iter() {
14861496let target_timestamp = vector_clocks[candidate].clock[candidate];
14871497if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| {
@@ -1491,9 +1501,7 @@ impl GlobalState {
1491150114921502// The vector represents a thread that has terminated and hence cannot
14931503// report a data-race with the candidate index.
1494-let thread_id = vector_info[clock_idx];
1495-let vector_terminated =
1496- reuse.contains(&clock_idx) || terminated_threads.contains_key(&thread_id);
1504+let vector_terminated = reuse.contains(&clock_idx);
1497150514981506// The vector index cannot report a race with the candidate index
14991507// and hence allows the candidate index to be re-used.
@@ -1583,55 +1591,38 @@ impl GlobalState {
15831591 /// thread (the joinee, the thread that someone waited on) and the current thread (the joiner,
15841592 /// the thread who was waiting).
15851593 #[inline]
1586-pub fn thread_joined(
1587-&mut self,
1588-thread_mgr: &ThreadManager<'_, '_>,
1589-joiner: ThreadId,
1590-joinee: ThreadId,
1591-) {
1592-let clocks_vec = self.vector_clocks.get_mut();
1593-let thread_info = self.thread_info.get_mut();
1594-1595-// Load the vector clock of the current thread.
1596-let current_index = thread_info[joiner]
1597-.vector_index
1598-.expect("Performed thread join on thread with no assigned vector");
1599-let current = &mut clocks_vec[current_index];
1594+pub fn thread_joined(&mut self, threads: &ThreadManager<'_, '_>, joinee: ThreadId) {
1595+let thread_info = self.thread_info.borrow();
1596+let thread_info = &thread_info[joinee];
1600159716011598// Load the associated vector clock for the terminated thread.
1602-let join_clock = thread_info[joinee]
1599+let join_clock = thread_info
16031600.termination_vector_clock
16041601.as_ref()
1605-.expect("Joined with thread but thread has not terminated");
1606-1607-// The join thread happens-before the current thread
1608-// so update the current vector clock.
1609-// Is not a release operation so the clock is not incremented.
1610- current.clock.join(join_clock);
1602+.expect("joined with thread but thread has not terminated");
1603+// Acquire that into the current thread.
1604+self.acquire_clock(join_clock, threads);
1611160516121606// Check the number of live threads, if the value is 1
16131607// then test for potentially disabling multi-threaded execution.
1614-if thread_mgr.get_live_thread_count() == 1 {
1615-// May potentially be able to disable multi-threaded execution.
1616-let current_clock = &clocks_vec[current_index];
1617-if clocks_vec
1618-.iter_enumerated()
1619-.all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx])
1620-{
1621-// All thread terminations happen-before the current clock
1622-// therefore no data-races can be reported until a new thread
1623-// is created, so disable multi-threaded execution.
1624-self.multi_threaded.set(false);
1608+// This has to happen after `acquire_clock`, otherwise there'll always
1609+// be some thread that has not synchronized yet.
1610+if let Some(current_index) = thread_info.vector_index {
1611+if threads.get_live_thread_count() == 1 {
1612+let vector_clocks = self.vector_clocks.get_mut();
1613+// May potentially be able to disable multi-threaded execution.
1614+let current_clock = &vector_clocks[current_index];
1615+if vector_clocks
1616+.iter_enumerated()
1617+.all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx])
1618+{
1619+// All thread terminations happen-before the current clock
1620+// therefore no data-races can be reported until a new thread
1621+// is created, so disable multi-threaded execution.
1622+self.multi_threaded.set(false);
1623+}
16251624}
16261625}
1627-1628-// If the thread is marked as terminated but not joined
1629-// then move the thread to the re-use set.
1630-let termination = self.terminated_threads.get_mut();
1631-if let Some(index) = termination.remove(&joinee) {
1632-let reuse = self.reuse_candidates.get_mut();
1633- reuse.insert(index);
1634-}
16351626}
1636162716371628/// On thread termination, the vector-clock may re-used
@@ -1642,29 +1633,18 @@ impl GlobalState {
16421633 /// This should be called strictly before any calls to
16431634 /// `thread_joined`.
16441635 #[inline]
1645-pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>, current_span: Span) {
1636+pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>) {
1637+let current_thread = thread_mgr.active_thread();
16461638let current_index = self.active_thread_index(thread_mgr);
164716391648-// Increment the clock to a unique termination timestamp.
1649-let vector_clocks = self.vector_clocks.get_mut();
1650-let current_clocks = &mut vector_clocks[current_index];
1651- current_clocks.increment_clock(current_index, current_span);
1652-1653-// Load the current thread id for the executing vector.
1654-let vector_info = self.vector_info.get_mut();
1655-let current_thread = vector_info[current_index];
1656-1657-// Load the current thread metadata, and move to a terminated
1658-// vector state. Setting up the vector clock all join operations
1659-// will use.
1660-let thread_info = self.thread_info.get_mut();
1661-let current = &mut thread_info[current_thread];
1662- current.termination_vector_clock = Some(current_clocks.clock.clone());
1640+// Store the terminaion clock.
1641+let terminaion_clock = self.release_clock(thread_mgr).clone();
1642+self.thread_info.get_mut()[current_thread].termination_vector_clock =
1643+Some(terminaion_clock);
166316441664-// Add this thread as a candidate for re-use after a thread join
1665-// occurs.
1666-let termination = self.terminated_threads.get_mut();
1667- termination.insert(current_thread, current_index);
1645+// Add this thread's clock index as a candidate for re-use.
1646+let reuse = self.reuse_candidates.get_mut();
1647+ reuse.insert(current_index);
16681648}
1669164916701650/// Attempt to perform a synchronized operation, this
@@ -1702,23 +1682,29 @@ impl GlobalState {
17021682format!("thread `{thread_name}`")
17031683}
170416841705-/// Acquire the given clock into the given thread, establishing synchronization with
1685+/// Acquire the given clock into the current thread, establishing synchronization with
17061686 /// the moment when that clock snapshot was taken via `release_clock`.
17071687 /// As this is an acquire operation, the thread timestamp is not
17081688 /// incremented.
1709- pub fn acquire_clock(&self, lock: &VClock, thread: ThreadId) {
1689+ pub fn acquire_clock<'mir, 'tcx>(&self, clock: &VClock, threads: &ThreadManager<'mir, 'tcx>) {
1690+let thread = threads.active_thread();
17101691let (_, mut clocks) = self.thread_state_mut(thread);
1711- clocks.clock.join(lock);
1692+ clocks.clock.join(clock);
17121693}
171316941714-/// Returns the `release` clock of the given thread.
1695+/// Returns the `release` clock of the current thread.
17151696 /// Other threads can acquire this clock in the future to establish synchronization
17161697 /// with this program point.
1717- pub fn release_clock(&self, thread: ThreadId, current_span: Span) -> Ref<'_, VClock> {
1698+ pub fn release_clock<'mir, 'tcx>(
1699+&self,
1700+threads: &ThreadManager<'mir, 'tcx>,
1701+) -> Ref<'_, VClock> {
1702+let thread = threads.active_thread();
1703+let span = threads.active_thread_ref().current_span();
17181704// We increment the clock each time this happens, to ensure no two releases
17191705// can be confused with each other.
17201706let (index, mut clocks) = self.thread_state_mut(thread);
1721- clocks.increment_clock(index, current_span);
1707+ clocks.increment_clock(index, span);
17221708drop(clocks);
17231709// To return a read-only view, we need to release the RefCell
17241710// and borrow it again.
@@ -1757,7 +1743,7 @@ impl GlobalState {
17571743&self,
17581744thread_mgr: &ThreadManager<'_, '_>,
17591745) -> (VectorIdx, Ref<'_, ThreadClockSet>) {
1760-self.thread_state(thread_mgr.get_active_thread_id())
1746+self.thread_state(thread_mgr.active_thread())
17611747}
1762174817631749/// Load the current vector clock in use and the current set of thread clocks
@@ -1767,14 +1753,14 @@ impl GlobalState {
17671753&self,
17681754thread_mgr: &ThreadManager<'_, '_>,
17691755) -> (VectorIdx, RefMut<'_, ThreadClockSet>) {
1770-self.thread_state_mut(thread_mgr.get_active_thread_id())
1756+self.thread_state_mut(thread_mgr.active_thread())
17711757}
1772175817731759/// Return the current thread, should be the same
17741760 /// as the data-race active thread.
17751761 #[inline]
17761762fn active_thread_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx {
1777-let active_thread_id = thread_mgr.get_active_thread_id();
1763+let active_thread_id = thread_mgr.active_thread();
17781764self.thread_index(active_thread_id)
17791765}
17801766