Skip to content

Commit

Permalink
Detect and work around TSan's lack of support for fences
Browse files Browse the repository at this point in the history
  • Loading branch information
thomcc committed Aug 8, 2021
1 parent 6e3c66e commit 4fd88be
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 5 deletions.
10 changes: 10 additions & 0 deletions core/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Automatically detect tsan in a way that's compatible with both stable (which
// doesn't support sanitizers) and nightly (which does). Works because build
// scripts gets `cfg` info, even if the cfg is unstable.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let santizer_list = std::env::var("CARGO_CFG_SANITIZE").unwrap_or_default();
if santizer_list.contains("thread") {
println!("cargo:rustc-cfg=tsan_enabled");
}
}
21 changes: 16 additions & 5 deletions core/src/word_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl WordLock {
match self.state.compare_exchange_weak(
state,
state | QUEUE_LOCKED_BIT,
Ordering::AcqRel,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => break,
Expand Down Expand Up @@ -230,15 +230,15 @@ impl WordLock {
match self.state.compare_exchange_weak(
state,
state & !QUEUE_LOCKED_BIT,
Ordering::AcqRel,
Ordering::Release,
Ordering::Relaxed,
) {
Ok(_) => return,
Err(x) => state = x,
}

// Need an acquire fence before reading the new queue
fence(Ordering::Acquire);
fence_acquire(&self.state);
continue;
}

Expand All @@ -249,7 +249,7 @@ impl WordLock {
match self.state.compare_exchange_weak(
state,
state & LOCKED_BIT,
Ordering::AcqRel,
Ordering::Release,
Ordering::Relaxed,
) {
Ok(_) => break,
Expand All @@ -263,7 +263,7 @@ impl WordLock {
continue;
} else {
// Need an acquire fence before reading the new queue
fence(Ordering::Acquire);
fence_acquire(&self.state);
continue 'outer;
}
}
Expand All @@ -286,6 +286,17 @@ impl WordLock {
}
}

// Thread-Sanitizer only has partial fence support, so when running under it, we
// try and avoid false positives by using a discarded acquire load instead.
#[inline]
fn fence_acquire(a: &AtomicUsize) {
if cfg!(tsan_enabled) {
let _ = a.load(Ordering::Acquire);
} else {
fence(Ordering::Acquire);
}
}

trait LockState {
fn is_locked(self) -> bool;
fn is_queue_locked(self) -> bool;
Expand Down

0 comments on commit 4fd88be

Please sign in to comment.