Skip to content

Commit a4e42ad

Browse files
committed
data_race: clarify and slightly refactor non-atomic handling
1 parent d32b158 commit a4e42ad

File tree

1 file changed

+50
-45
lines changed

1 file changed

+50
-45
lines changed

src/tools/miri/src/concurrency/data_race.rs

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -220,25 +220,22 @@ impl WriteType {
220220
/// for data-race detection.
221221
#[derive(Clone, PartialEq, Eq, Debug)]
222222
struct MemoryCellClocks {
223-
/// The vector-clock timestamp of the last write
224-
/// corresponding to the writing threads timestamp.
225-
write: VTimestamp,
226-
227-
/// The identifier of the vector index, corresponding to a thread
228-
/// that performed the last write operation.
229-
write_index: VectorIdx,
223+
/// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need
224+
/// a full `VClock` here, it's always a single thread and nothing synchronizes, so the effective
225+
/// clock is all-0 except for the thread that did the write.
226+
write: (VectorIdx, VTimestamp),
230227

231228
/// The type of operation that the write index represents,
232229
/// either newly allocated memory, a non-atomic write or
233230
/// a deallocation of memory.
234231
write_type: WriteType,
235232

236-
/// The vector-clock of the timestamp of the last read operation
237-
/// performed by a thread since the last write operation occurred.
238-
/// It is reset to zero on each write operation.
233+
/// The vector-clock of all non-atomic reads that happened since the last non-atomic write
234+
/// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to
235+
/// zero on each write operation.
239236
read: VClock,
240237

241-
/// Atomic acquire & release sequence tracking clocks.
238+
/// Atomic access, acquire, release sequence tracking clocks.
242239
/// For non-atomic memory in the common case this
243240
/// value is set to None.
244241
atomic_ops: Option<Box<AtomicMemoryCellClocks>>,
@@ -250,13 +247,24 @@ impl MemoryCellClocks {
250247
fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self {
251248
MemoryCellClocks {
252249
read: VClock::default(),
253-
write: alloc,
254-
write_index: alloc_index,
250+
write: (alloc_index, alloc),
255251
write_type: WriteType::Allocate,
256252
atomic_ops: None,
257253
}
258254
}
259255

256+
#[inline]
257+
fn write_was_before(&self, other: &VClock) -> bool {
258+
// This is the same as `self.write() <= other` but
259+
// without actually manifesting a clock for `self.write`.
260+
self.write.1 <= other[self.write.0]
261+
}
262+
263+
#[inline]
264+
fn write(&self) -> VClock {
265+
VClock::new_with_index(self.write.0, self.write.1)
266+
}
267+
260268
/// Load the internal atomic memory cells if they exist.
261269
#[inline]
262270
fn atomic(&self) -> Option<&AtomicMemoryCellClocks> {
@@ -376,7 +384,7 @@ impl MemoryCellClocks {
376384
log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks);
377385
let atomic = self.atomic_mut();
378386
atomic.read_vector.set_at_index(&thread_clocks.clock, index);
379-
if self.write <= thread_clocks.clock[self.write_index] { Ok(()) } else { Err(DataRace) }
387+
if self.write_was_before(&thread_clocks.clock) { Ok(()) } else { Err(DataRace) }
380388
}
381389

382390
/// Detect data-races with an atomic write, either with a non-atomic read or with
@@ -389,7 +397,7 @@ impl MemoryCellClocks {
389397
log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, thread_clocks);
390398
let atomic = self.atomic_mut();
391399
atomic.write_vector.set_at_index(&thread_clocks.clock, index);
392-
if self.write <= thread_clocks.clock[self.write_index] && self.read <= thread_clocks.clock {
400+
if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
393401
Ok(())
394402
} else {
395403
Err(DataRace)
@@ -408,7 +416,7 @@ impl MemoryCellClocks {
408416
if !current_span.is_dummy() {
409417
thread_clocks.clock[index].span = current_span;
410418
}
411-
if self.write <= thread_clocks.clock[self.write_index] {
419+
if self.write_was_before(&thread_clocks.clock) {
412420
let race_free = if let Some(atomic) = self.atomic() {
413421
atomic.write_vector <= thread_clocks.clock
414422
} else {
@@ -434,15 +442,14 @@ impl MemoryCellClocks {
434442
if !current_span.is_dummy() {
435443
thread_clocks.clock[index].span = current_span;
436444
}
437-
if self.write <= thread_clocks.clock[self.write_index] && self.read <= thread_clocks.clock {
445+
if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
438446
let race_free = if let Some(atomic) = self.atomic() {
439447
atomic.write_vector <= thread_clocks.clock
440448
&& atomic.read_vector <= thread_clocks.clock
441449
} else {
442450
true
443451
};
444-
self.write = thread_clocks.clock[index];
445-
self.write_index = index;
452+
self.write = (index, thread_clocks.clock[index]);
446453
self.write_type = write_type;
447454
if race_free {
448455
self.read.set_zero_vector();
@@ -790,37 +797,35 @@ impl VClockAlloc {
790797
) -> InterpResult<'tcx> {
791798
let (current_index, current_clocks) = global.current_thread_state(thread_mgr);
792799
let write_clock;
793-
let (other_action, other_thread, other_clock) = if mem_clocks.write
794-
> current_clocks.clock[mem_clocks.write_index]
795-
{
796-
// Convert the write action into the vector clock it
797-
// represents for diagnostic purposes.
798-
write_clock = VClock::new_with_index(mem_clocks.write_index, mem_clocks.write);
799-
(mem_clocks.write_type.get_descriptor(), mem_clocks.write_index, &write_clock)
800-
} else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &current_clocks.clock) {
801-
("Read", idx, &mem_clocks.read)
802-
} else if !is_atomic {
803-
if let Some(atomic) = mem_clocks.atomic() {
804-
if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &current_clocks.clock)
805-
{
806-
("Atomic Store", idx, &atomic.write_vector)
807-
} else if let Some(idx) =
808-
Self::find_gt_index(&atomic.read_vector, &current_clocks.clock)
809-
{
810-
("Atomic Load", idx, &atomic.read_vector)
800+
#[rustfmt::skip]
801+
let (other_action, other_thread, other_clock) =
802+
if mem_clocks.write.1 > current_clocks.clock[mem_clocks.write.0] {
803+
write_clock = mem_clocks.write();
804+
(mem_clocks.write_type.get_descriptor(), mem_clocks.write.0, &write_clock)
805+
} else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &current_clocks.clock) {
806+
("Read", idx, &mem_clocks.read)
807+
} else if !is_atomic {
808+
if let Some(atomic) = mem_clocks.atomic() {
809+
if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &current_clocks.clock)
810+
{
811+
("Atomic Store", idx, &atomic.write_vector)
812+
} else if let Some(idx) =
813+
Self::find_gt_index(&atomic.read_vector, &current_clocks.clock)
814+
{
815+
("Atomic Load", idx, &atomic.read_vector)
816+
} else {
817+
unreachable!(
818+
"Failed to report data-race for non-atomic operation: no race found"
819+
)
820+
}
811821
} else {
812822
unreachable!(
813-
"Failed to report data-race for non-atomic operation: no race found"
823+
"Failed to report data-race for non-atomic operation: no atomic component"
814824
)
815825
}
816826
} else {
817-
unreachable!(
818-
"Failed to report data-race for non-atomic operation: no atomic component"
819-
)
820-
}
821-
} else {
822-
unreachable!("Failed to report data-race for atomic operation")
823-
};
827+
unreachable!("Failed to report data-race for atomic operation")
828+
};
824829

825830
// Load elaborated thread information about the racing thread actions.
826831
let current_thread_info = global.print_thread_metadata(thread_mgr, current_index);

0 commit comments

Comments
 (0)