]> git.lizzy.rs Git - rust.git/commitdiff
Destroy store buffers on non-racy non-atomic accesses
authorAndy Wang <cbeuw.andy@gmail.com>
Tue, 24 May 2022 21:03:04 +0000 (22:03 +0100)
committerAndy Wang <cbeuw.andy@gmail.com>
Mon, 6 Jun 2022 18:15:58 +0000 (19:15 +0100)
src/concurrency/allocation_map.rs
src/concurrency/data_race.rs
src/concurrency/weak_memory.rs
src/machine.rs

index 2524389c0be834683c62230e2627dec8c056a37e..62469dcaf43a873f800bbd8ac978a179151bfc0e 100644 (file)
@@ -125,6 +125,14 @@ pub fn insert_at_pos(&mut self, pos: Position, range: AllocRange, data: T) {
             debug_assert!(range.end() <= self.v[pos + 1].range.start);
         }
     }
+
+    pub fn remove_pos_range(&mut self, pos_range: Range<Position>) {
+        self.v.drain(pos_range);
+    }
+
+    pub fn remove_from_pos(&mut self, pos: Position) {
+        self.v.remove(pos);
+    }
 }
 
 impl<T> Index<Position> for AllocationMap<T> {
index 7ac2ed615a11fb62bbdb80e681e2a0c10e52b00d..2483bcdf49a2890e238a1b82da19b9b90b67768f 100644 (file)
@@ -1200,6 +1200,10 @@ fn race_detecting(&self) -> bool {
         self.multi_threaded.get() && !self.ongoing_atomic_access.get()
     }
 
+    pub fn ongoing_atomic_access(&self) -> bool {
+        self.ongoing_atomic_access.get()
+    }
+
     // Try to find vector index values that can potentially be re-used
     // by a new thread instead of a new vector index being created.
     fn find_vector_index_reuse_candidate(&self) -> Option<VectorIdx> {
index 51092478c3fd9f0cd3ea4b8c26c82fb0fb235868..7d8d7da6dc4e7fee55dae274950e0c71db6b1666 100644 (file)
 //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20
 //! disallows.
 //!
-//! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore
-//! possible for this implementation to generate behaviours never observable when the same program is compiled and
-//! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible
-//! relaxed memory model that supports all atomic operation existing in Rust. The closest one is
+//! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s
+//! std::atomic<T> API). It is therefore possible for this implementation to generate behaviours never observable when the
+//! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes
+//! an implementable and C++20-compatible relaxed memory model that supports all atomic operation existing in Rust. The closest one is
 //! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf)
 //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code).
 //!
@@ -117,6 +117,26 @@ pub fn new_allocation() -> Self {
         Self { store_buffers: RefCell::new(AllocationMap::new()) }
     }
 
+    /// When a non-atomic access happens on a location that has been atomically accessed
+    /// before without data race, we can determine that the non-atomic access fully happens
+    /// before all the prior atomic accesses so the location no longer needs to exhibit
+    /// any weak memory behaviours until further atomic accesses.
+    pub fn destroy_atomicity<'tcx>(&self, range: AllocRange) {
+        let mut buffers = self.store_buffers.borrow_mut();
+        let access_type = buffers.access_type(range);
+        match access_type {
+            AccessType::PerfectlyOverlapping(pos) => {
+                buffers.remove_from_pos(pos);
+            }
+            AccessType::ImperfectlyOverlapping(pos_range) => {
+                buffers.remove_pos_range(pos_range);
+            }
+            AccessType::Empty(_) => {
+                // Do nothing
+            }
+        }
+    }
+
     /// Gets a store buffer associated with an atomic object in this allocation
     /// Or creates one with the specified initial value
     fn get_or_create_store_buffer<'tcx>(
index 41c852747ad7e04174deb2ef9e814b520e41db34..6dc2a75b69fd7016aa8a1eddd92dce698d714b87 100644 (file)
@@ -738,10 +738,17 @@ fn memory_read(
                 range,
                 machine.stacked_borrows.as_ref().unwrap(),
                 machine.current_span(),
-            )
-        } else {
-            Ok(())
+            )?;
         }
+        if let Some(weak_memory) = &alloc_extra.weak_memory {
+            if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() {
+                // This is a non-atomic access. And if we are accessing a previously atomically
+                // accessed location without racing with them, then the location no longer needs
+                // to exhibit weak-memory behaviours until a fresh atomic access happens
+                weak_memory.destroy_atomicity(range);
+            }
+        }
+        Ok(())
     }
 
     #[inline(always)]
@@ -762,10 +769,14 @@ fn memory_written(
                 range,
                 machine.stacked_borrows.as_ref().unwrap(),
                 machine.current_span(),
-            )
-        } else {
-            Ok(())
+            )?;
         }
+        if let Some(weak_memory) = &alloc_extra.weak_memory {
+            if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() {
+                weak_memory.destroy_atomicity(range);
+            }
+        }
+        Ok(())
     }
 
     #[inline(always)]