@@ -220,25 +220,22 @@ impl WriteType {
220220/// for data-race detection.
221221#[ derive( Clone , PartialEq , Eq , Debug ) ]
222222struct 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