data_race: vector indices can be reused immediately when the thread i… · rust-lang/rust@e6bb468
@@ -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;
@@ -1432,13 +1432,6 @@ pub struct GlobalState {
14321432 /// active vector-clocks catch up with the threads timestamp.
14331433 reuse_candidates: RefCell<FxHashSet<VectorIdx>>,
143414341435-/// This contains threads that have terminated, but not yet joined
1436- /// and so cannot become re-use candidates until a join operation
1437- /// occurs.
1438- /// The associated vector index will be moved into re-use candidates
1439- /// after the join operation occurs.
1440- terminated_threads: RefCell<FxHashMap<ThreadId, VectorIdx>>,
1441-14421435/// The timestamp of last SC fence performed by each thread
14431436 last_sc_fence: RefCell<VClock>,
14441437@@ -1466,7 +1459,6 @@ impl GlobalState {
14661459vector_info: RefCell::new(IndexVec::new()),
14671460thread_info: RefCell::new(IndexVec::new()),
14681461reuse_candidates: RefCell::new(FxHashSet::default()),
1469-terminated_threads: RefCell::new(FxHashMap::default()),
14701462last_sc_fence: RefCell::new(VClock::default()),
14711463last_sc_write: RefCell::new(VClock::default()),
14721464track_outdated_loads: config.track_outdated_loads,
@@ -1500,8 +1492,6 @@ impl GlobalState {
15001492fn find_vector_index_reuse_candidate(&self) -> Option<VectorIdx> {
15011493let mut reuse = self.reuse_candidates.borrow_mut();
15021494let vector_clocks = self.vector_clocks.borrow();
1503-let vector_info = self.vector_info.borrow();
1504-let terminated_threads = self.terminated_threads.borrow();
15051495for &candidate in reuse.iter() {
15061496let target_timestamp = vector_clocks[candidate].clock[candidate];
15071497if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| {
@@ -1511,9 +1501,7 @@ impl GlobalState {
1511150115121502// The vector represents a thread that has terminated and hence cannot
15131503// report a data-race with the candidate index.
1514-let thread_id = vector_info[clock_idx];
1515-let vector_terminated =
1516- reuse.contains(&clock_idx) || terminated_threads.contains_key(&thread_id);
1504+let vector_terminated = reuse.contains(&clock_idx);
1517150515181506// The vector index cannot report a race with the candidate index
15191507// and hence allows the candidate index to be re-used.
@@ -1603,55 +1591,38 @@ impl GlobalState {
16031591 /// thread (the joinee, the thread that someone waited on) and the current thread (the joiner,
16041592 /// the thread who was waiting).
16051593 #[inline]
1606-pub fn thread_joined(
1607-&mut self,
1608-thread_mgr: &ThreadManager<'_, '_>,
1609-joiner: ThreadId,
1610-joinee: ThreadId,
1611-) {
1612-let clocks_vec = self.vector_clocks.get_mut();
1613-let thread_info = self.thread_info.get_mut();
1614-1615-// Load the vector clock of the current thread.
1616-let current_index = thread_info[joiner]
1617-.vector_index
1618-.expect("Performed thread join on thread with no assigned vector");
1619-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];
1620159716211598// Load the associated vector clock for the terminated thread.
1622-let join_clock = thread_info[joinee]
1599+let join_clock = thread_info
16231600.termination_vector_clock
16241601.as_ref()
1625-.expect("Joined with thread but thread has not terminated");
1626-1627-// The join thread happens-before the current thread
1628-// so update the current vector clock.
1629-// Is not a release operation so the clock is not incremented.
1630- 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);
1631160516321606// Check the number of live threads, if the value is 1
16331607// then test for potentially disabling multi-threaded execution.
1634-if thread_mgr.get_live_thread_count() == 1 {
1635-// May potentially be able to disable multi-threaded execution.
1636-let current_clock = &clocks_vec[current_index];
1637-if clocks_vec
1638-.iter_enumerated()
1639-.all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx])
1640-{
1641-// All thread terminations happen-before the current clock
1642-// therefore no data-races can be reported until a new thread
1643-// is created, so disable multi-threaded execution.
1644-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+}
16451624}
16461625}
1647-1648-// If the thread is marked as terminated but not joined
1649-// then move the thread to the re-use set.
1650-let termination = self.terminated_threads.get_mut();
1651-if let Some(index) = termination.remove(&joinee) {
1652-let reuse = self.reuse_candidates.get_mut();
1653- reuse.insert(index);
1654-}
16551626}
1656162716571628/// On thread termination, the vector-clock may re-used
@@ -1663,29 +1634,17 @@ impl GlobalState {
16631634 /// `thread_joined`.
16641635 #[inline]
16651636pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>) {
1637+let current_thread = thread_mgr.active_thread();
16661638let current_index = self.active_thread_index(thread_mgr);
166716391668-// Increment the clock to a unique termination timestamp.
1669-let vector_clocks = self.vector_clocks.get_mut();
1670-let current_clocks = &mut vector_clocks[current_index];
1671- current_clocks
1672-.increment_clock(current_index, thread_mgr.active_thread_ref().current_span());
1673-1674-// Load the current thread id for the executing vector.
1675-let vector_info = self.vector_info.get_mut();
1676-let current_thread = vector_info[current_index];
1677-1678-// Load the current thread metadata, and move to a terminated
1679-// vector state. Setting up the vector clock all join operations
1680-// will use.
1681-let thread_info = self.thread_info.get_mut();
1682-let current = &mut thread_info[current_thread];
1683- current.termination_vector_clock = Some(current_clocks.clock.clone());
1684-1685-// Add this thread as a candidate for re-use after a thread join
1686-// occurs.
1687-let termination = self.terminated_threads.get_mut();
1688- termination.insert(current_thread, current_index);
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);
1644+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);
16891648}
1690164916911650/// Attempt to perform a synchronized operation, this