37
37
//! to a acquire load and a release store given the global sequentially consistent order
38
38
//! of the schedule.
39
39
//!
40
+ //! The timestamps used in the data-race detector assign each sequence of non-atomic operations
41
+ //! followed by a single atomic or concurrent operation a single timestamp.
42
+ //! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread
43
+ //! This is because extra increment operations between the operations in the sequence are not
44
+ //! required for accurate reporting of data-race values.
45
+ //!
46
+ //! If the timestamp was not incremented after the atomic operation, then data-races would not be detected:
47
+ //! Example - this should report a data-race but does not:
48
+ //! t1: (x,0), atomic[release A], t1=(x+1, 0 ), write(var B),
49
+ //! t2: (0,y) , atomic[acquire A], t2=(x+1, y+1), ,write(var B)
50
+ //!
51
+ //! The timestamp is not incremented before an atomic operation, since the result is indistinguishable
52
+ //! from the value not being incremented.
53
+ //! t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x, _)
54
+ //! vs t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x+1, _)
55
+ //! Both result in the sequence on thread x up to and including the atomic release as happening
56
+ //! before the acquire.
57
+ //!
40
58
//! FIXME:
41
59
//! currently we have our own local copy of the currently active thread index and names, this is due
42
60
//! in part to the inability to access the current location of threads.active_thread inside the AllocExtra
@@ -499,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
499
517
}
500
518
501
519
/// Perform an atomic compare and exchange at a given memory location
502
- /// on success an atomic RMW operation is performed and on failure
520
+ /// On success an atomic RMW operation is performed and on failure
503
521
/// only an atomic read occurs.
504
522
fn atomic_compare_exchange_scalar (
505
523
& mut self ,
@@ -1136,9 +1154,6 @@ impl GlobalState {
1136
1154
// Now load the two clocks and configure the initial state.
1137
1155
let ( current, created) = vector_clocks. pick2_mut ( current_index, created_index) ;
1138
1156
1139
- // Advance the current thread before the synchronized operation.
1140
- current. increment_clock ( current_index) ;
1141
-
1142
1157
// Join the created with current, since the current threads
1143
1158
// previous actions happen-before the created thread.
1144
1159
created. join_with ( current) ;
@@ -1167,14 +1182,12 @@ impl GlobalState {
1167
1182
. as_ref ( )
1168
1183
. expect ( "Joined with thread but thread has not terminated" ) ;
1169
1184
1170
- // Pre increment clocks before atomic operation.
1171
- current. increment_clock ( current_index) ;
1172
1185
1173
1186
// The join thread happens-before the current thread
1174
1187
// so update the current vector clock.
1175
1188
current. clock . join ( join_clock) ;
1176
1189
1177
- // Post increment clocks after atomic operation.
1190
+ // Increment clocks after atomic operation.
1178
1191
current. increment_clock ( current_index) ;
1179
1192
1180
1193
// Check the number of active threads, if the value is 1
@@ -1277,8 +1290,7 @@ impl GlobalState {
1277
1290
op : impl FnOnce ( VectorIdx , RefMut < ' _ , ThreadClockSet > ) -> InterpResult < ' tcx > ,
1278
1291
) -> InterpResult < ' tcx > {
1279
1292
if self . multi_threaded . get ( ) {
1280
- let ( index, mut clocks) = self . current_thread_state_mut ( ) ;
1281
- clocks. increment_clock ( index) ;
1293
+ let ( index, clocks) = self . current_thread_state_mut ( ) ;
1282
1294
op ( index, clocks) ?;
1283
1295
let ( _, mut clocks) = self . current_thread_state_mut ( ) ;
1284
1296
clocks. increment_clock ( index) ;
@@ -1303,16 +1315,18 @@ impl GlobalState {
1303
1315
/// `validate_lock_release` must happen before this.
1304
1316
pub fn validate_lock_acquire ( & self , lock : & VClock , thread : ThreadId ) {
1305
1317
let ( index, mut clocks) = self . load_thread_state_mut ( thread) ;
1306
- clocks. increment_clock ( index) ;
1307
1318
clocks. clock . join ( & lock) ;
1308
1319
clocks. increment_clock ( index) ;
1309
1320
}
1310
1321
1311
1322
/// Release a lock handle, express that this happens-before
1312
1323
/// any subsequent calls to `validate_lock_acquire`.
1324
+ /// For normal locks this should be equivalent to `validate_lock_release_shared`
1325
+ /// since an acquire operation should have occured before, however
1326
+ /// for futex & cond-var operations this is not the case and this
1327
+ /// operation must be used.
1313
1328
pub fn validate_lock_release ( & self , lock : & mut VClock , thread : ThreadId ) {
1314
1329
let ( index, mut clocks) = self . load_thread_state_mut ( thread) ;
1315
- clocks. increment_clock ( index) ;
1316
1330
lock. clone_from ( & clocks. clock ) ;
1317
1331
clocks. increment_clock ( index) ;
1318
1332
}
@@ -1321,9 +1335,11 @@ impl GlobalState {
1321
1335
/// any subsequent calls to `validate_lock_acquire` as well
1322
1336
/// as any previous calls to this function after any
1323
1337
/// `validate_lock_release` calls.
1338
+ /// For normal locks this should be equivalent to `validate_lock_release`
1339
+ /// this function only exists for joining over the set of concurrent readers
1340
+ /// in a read-write lock and should not be used for anything else.
1324
1341
pub fn validate_lock_release_shared ( & self , lock : & mut VClock , thread : ThreadId ) {
1325
1342
let ( index, mut clocks) = self . load_thread_state_mut ( thread) ;
1326
- clocks. increment_clock ( index) ;
1327
1343
lock. join ( & clocks. clock ) ;
1328
1344
clocks. increment_clock ( index) ;
1329
1345
}
0 commit comments