Skip to content

Commit 55fc552

Browse files
committed
Apply review changes, incrementing the clocks twice is an unnecessary hold-over from earlier versions so fixed.
1 parent 3268f56 commit 55fc552

25 files changed

+95
-40
lines changed

src/data_race.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@
3737
//! to a acquire load and a release store given the global sequentially consistent order
3838
//! of the schedule.
3939
//!
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+
//!
4058
//! FIXME:
4159
//! currently we have our own local copy of the currently active thread index and names, this is due
4260
//! 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> {
499517
}
500518

501519
/// 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
503521
/// only an atomic read occurs.
504522
fn atomic_compare_exchange_scalar(
505523
&mut self,
@@ -1136,9 +1154,6 @@ impl GlobalState {
11361154
// Now load the two clocks and configure the initial state.
11371155
let (current, created) = vector_clocks.pick2_mut(current_index, created_index);
11381156

1139-
// Advance the current thread before the synchronized operation.
1140-
current.increment_clock(current_index);
1141-
11421157
// Join the created with current, since the current threads
11431158
// previous actions happen-before the created thread.
11441159
created.join_with(current);
@@ -1167,14 +1182,12 @@ impl GlobalState {
11671182
.as_ref()
11681183
.expect("Joined with thread but thread has not terminated");
11691184

1170-
// Pre increment clocks before atomic operation.
1171-
current.increment_clock(current_index);
11721185

11731186
// The join thread happens-before the current thread
11741187
// so update the current vector clock.
11751188
current.clock.join(join_clock);
11761189

1177-
// Post increment clocks after atomic operation.
1190+
// Increment clocks after atomic operation.
11781191
current.increment_clock(current_index);
11791192

11801193
// Check the number of active threads, if the value is 1
@@ -1277,8 +1290,7 @@ impl GlobalState {
12771290
op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>,
12781291
) -> InterpResult<'tcx> {
12791292
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();
12821294
op(index, clocks)?;
12831295
let (_, mut clocks) = self.current_thread_state_mut();
12841296
clocks.increment_clock(index);
@@ -1303,16 +1315,18 @@ impl GlobalState {
13031315
/// `validate_lock_release` must happen before this.
13041316
pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) {
13051317
let (index, mut clocks) = self.load_thread_state_mut(thread);
1306-
clocks.increment_clock(index);
13071318
clocks.clock.join(&lock);
13081319
clocks.increment_clock(index);
13091320
}
13101321

13111322
/// Release a lock handle, express that this happens-before
13121323
/// 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.
13131328
pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) {
13141329
let (index, mut clocks) = self.load_thread_state_mut(thread);
1315-
clocks.increment_clock(index);
13161330
lock.clone_from(&clocks.clock);
13171331
clocks.increment_clock(index);
13181332
}
@@ -1321,9 +1335,11 @@ impl GlobalState {
13211335
/// any subsequent calls to `validate_lock_acquire` as well
13221336
/// as any previous calls to this function after any
13231337
/// `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.
13241341
pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) {
13251342
let (index, mut clocks) = self.load_thread_state_mut(thread);
1326-
clocks.increment_clock(index);
13271343
lock.join(&clocks.clock);
13281344
clocks.increment_clock(index);
13291345
}

src/shims/posix/sync.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,11 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>(
6262
mutex_op: OpTy<'tcx, Tag>,
6363
) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
6464
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
65+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
66+
// mutex implementation, it may not need to be atomic.
6567
ecx.read_scalar_at_offset_atomic(
6668
mutex_op, offset, ecx.machine.layouts.i32,
67-
AtomicReadOp::Acquire
69+
AtomicReadOp::Relaxed
6870
)
6971
}
7072

@@ -74,18 +76,23 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>(
7476
kind: impl Into<ScalarMaybeUninit<Tag>>,
7577
) -> InterpResult<'tcx, ()> {
7678
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
79+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
80+
// mutex implementation, it may not need to be atomic.
7781
ecx.write_scalar_at_offset_atomic(
78-
mutex_op, offset, kind, ecx.machine.layouts.i32,
79-
AtomicWriteOp::Release
82+
mutex_op, offset, kind, ecx.machine.layouts.i32,
83+
AtomicWriteOp::Relaxed
8084
)
8185
}
8286

8387
fn mutex_get_id<'mir, 'tcx: 'mir>(
8488
ecx: &MiriEvalContext<'mir, 'tcx>,
8589
mutex_op: OpTy<'tcx, Tag>,
8690
) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
91+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
92+
// mutex implementation, it may not need to be atomic.
8793
ecx.read_scalar_at_offset_atomic(
88-
mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Acquire
94+
mutex_op, 4, ecx.machine.layouts.u32,
95+
AtomicReadOp::Relaxed
8996
)
9097
}
9198

@@ -94,9 +101,11 @@ fn mutex_set_id<'mir, 'tcx: 'mir>(
94101
mutex_op: OpTy<'tcx, Tag>,
95102
id: impl Into<ScalarMaybeUninit<Tag>>,
96103
) -> InterpResult<'tcx, ()> {
104+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
105+
// mutex implementation, it may not need to be atomic.
97106
ecx.write_scalar_at_offset_atomic(
98107
mutex_op, 4, id, ecx.machine.layouts.u32,
99-
AtomicWriteOp::Release
108+
AtomicWriteOp::Relaxed
100109
)
101110
}
102111

@@ -126,10 +135,12 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>(
126135
fn rwlock_get_id<'mir, 'tcx: 'mir>(
127136
ecx: &MiriEvalContext<'mir, 'tcx>,
128137
rwlock_op: OpTy<'tcx, Tag>,
138+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
139+
// rw-lock implementation, it may not need to be atomic.
129140
) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
130141
ecx.read_scalar_at_offset_atomic(
131142
rwlock_op, 4, ecx.machine.layouts.u32,
132-
AtomicReadOp::Acquire
143+
AtomicReadOp::Relaxed
133144
)
134145
}
135146

@@ -138,9 +149,11 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>(
138149
rwlock_op: OpTy<'tcx, Tag>,
139150
id: impl Into<ScalarMaybeUninit<Tag>>,
140151
) -> InterpResult<'tcx, ()> {
152+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
153+
// rw-lock implementation, it may not need to be atomic.
141154
ecx.write_scalar_at_offset_atomic(
142155
rwlock_op, 4, id, ecx.machine.layouts.u32,
143-
AtomicWriteOp::Release
156+
AtomicWriteOp::Relaxed
144157
)
145158
}
146159

@@ -194,9 +207,11 @@ fn cond_get_id<'mir, 'tcx: 'mir>(
194207
ecx: &MiriEvalContext<'mir, 'tcx>,
195208
cond_op: OpTy<'tcx, Tag>,
196209
) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
210+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
211+
// cond-var implementation, it may not need to be atomic.
197212
ecx.read_scalar_at_offset_atomic(
198213
cond_op, 4, ecx.machine.layouts.u32,
199-
AtomicReadOp::Acquire
214+
AtomicReadOp::Relaxed
200215
)
201216
}
202217

@@ -205,9 +220,11 @@ fn cond_set_id<'mir, 'tcx: 'mir>(
205220
cond_op: OpTy<'tcx, Tag>,
206221
id: impl Into<ScalarMaybeUninit<Tag>>,
207222
) -> InterpResult<'tcx, ()> {
223+
//FIXME: this has been made atomic to fix data-race reporting inside the internal
224+
// cond-var implementation, it may not need to be atomic.
208225
ecx.write_scalar_at_offset_atomic(
209226
cond_op, 4, id, ecx.machine.layouts.u32,
210-
AtomicWriteOp::Release
227+
AtomicWriteOp::Relaxed
211228
)
212229
}
213230

src/shims/posix/thread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1515
let this = self.eval_context_mut();
1616

1717
this.tcx.sess.warn(
18-
"thread support is experimental, no weak memory effects are currently emulated.",
18+
"thread support is experimental and incomplete: weak memory effects are not emulated."
1919
);
2020

2121
// Create the new thread

tests/compile-fail/data_race/dangling_thread_async_race.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ fn main() {
2929
sleep(Duration::from_millis(100));
3030

3131
// Spawn and immediately join a thread
32-
// to execute the join code-path
33-
// and ensure that data-race detection
34-
// remains enabled
32+
// to execute the join code-path
33+
// and ensure that data-race detection
34+
// remains enabled nevertheless.
3535
spawn(|| ()).join().unwrap();
3636

3737
let join2 = unsafe {

tests/compile-fail/data_race/dangling_thread_race.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ fn main() {
2929
sleep(Duration::from_millis(100));
3030

3131
// Spawn and immediately join a thread
32-
// to execute the join code-path
33-
// and ensure that data-race detection
34-
// remains enabled
32+
// to execute the join code-path
33+
// and ensure that data-race detection
34+
// remains enabled nevertheless.
3535
spawn(|| ()).join().unwrap();
3636

3737

tests/compile-fail/data_race/enable_after_join_to_main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ unsafe impl<T> Send for EvilSend<T> {}
99
unsafe impl<T> Sync for EvilSend<T> {}
1010

1111
pub fn main() {
12-
// Enable and the join with multiple threads
12+
// Enable and then join with multiple threads.
1313
let t1 = spawn(|| ());
1414
let t2 = spawn(|| ());
1515
let t3 = spawn(|| ());
@@ -19,7 +19,7 @@ pub fn main() {
1919
t3.join().unwrap();
2020
t4.join().unwrap();
2121

22-
// Perform write-write data race detection
22+
// Perform write-write data race detection.
2323
let mut a = 0u32;
2424
let b = &mut a as *mut u32;
2525
let c = EvilSend(b);

tests/compile-fail/data_race/relax_acquire_race.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ pub fn main() {
1616
let b = &mut a as *mut u32;
1717
let c = EvilSend(b);
1818

19+
// Note: this is scheduler-dependent
20+
// the operations need to occur in
21+
// order:
22+
// 1. store release : 1
23+
// 2. load acquire : 1
24+
// 3. store relaxed : 2
25+
// 4. load acquire : 2
1926
unsafe {
2027
let j1 = spawn(move || {
2128
*c.0 = 1;

tests/compile-fail/data_race/release_seq_race.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ pub fn main() {
1818
let b = &mut a as *mut u32;
1919
let c = EvilSend(b);
2020

21+
// Note: this is scheduler-dependent
22+
// the operations need to occur in
23+
// order, the sleep operations currently
24+
// force the desired ordering:
25+
// 1. store release : 1
26+
// 2. store relaxed : 2
27+
// 3. store relaxed : 3
28+
// 4. load acquire : 3
2129
unsafe {
2230
let j1 = spawn(move || {
2331
*c.0 = 1;

tests/compile-fail/data_race/rmw_race.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ pub fn main() {
1616
let b = &mut a as *mut u32;
1717
let c = EvilSend(b);
1818

19+
// Note: this is scheduler-dependent
20+
// the operations need to occur in
21+
// order:
22+
// 1. store release : 1
23+
// 2. RMW relaxed : 1 -> 2
24+
// 3. store relaxed : 3
25+
// 4. load acquire : 3
1926
unsafe {
2027
let j1 = spawn(move || {
2128
*c.0 = 1;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

tests/run-pass/concurrency/disable_data_race_detector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn main() {
1919
});
2020

2121
let j2 = spawn(move || {
22-
*c.0 = 64; //~ ERROR Data race
22+
*c.0 = 64; //~ ERROR Data race (but not detected as the detector is disabled)
2323
});
2424

2525
j1.join().unwrap();
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

tests/run-pass/concurrency/simple.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

33
thread '<unnamed>' panicked at 'Hello!', $DIR/simple.rs:54:9
44
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

tests/run-pass/libc.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

tests/run-pass/panic/concurrent-panic.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning: thread support is experimental, no weak memory effects are currently emulated.
1+
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
22

33
Thread 1 starting, will block on mutex
44
Thread 1 reported it has started

0 commit comments

Comments
 (0)