Skip to content

Commit 8b226e6

Browse files
anpCQ Bot
authored andcommitted
[tracing-mutex] Allow suppressing panics for gradual rollout.
Applies bertptrs/tracing-mutex#53 in advance of an upstream release. Bug: 461821986 Change-Id: I72978485e5d16d90b1ebae59ee89377a792df05a Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1430716 Commit-Queue: Adam Perry <[email protected]> Reviewed-by: Erick Tryzelaar <[email protected]> Fuchsia-Auto-Submit: Adam Perry <[email protected]>
1 parent 61029c5 commit 8b226e6

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Show what a suppressed crash looks like.
2+
//!
3+
//! This shows what a traceback of a cycle detection looks like when panics are suppressed. It is
4+
//! expected to print the cycle when run in debug mode, because it might deadlock. In release mode,
5+
//! no tracing is used and the program may do any of the following:
6+
//!
7+
//! - Return a random valuation of `a`, `b`, and `c`. The implementation has a race-condition by
8+
//! design. I have observed (4, 3, 6), but also (6, 3, 5).
9+
//! - Deadlock forever.
10+
//!
11+
//! One can increase the SLEEP_TIME constant to increase the likelihood of a deadlock to occur. On
12+
//! my machine, 1ns of sleep time gives about a 50/50 chance of the program deadlocking.
13+
14+
use std::thread;
15+
use std::time::Duration;
16+
17+
use tracing_mutex::stdsync::Mutex;
18+
19+
fn main() {
20+
tracing_mutex::suppress_panics();
21+
22+
let a = Mutex::new(1);
23+
let b = Mutex::new(2);
24+
let c = Mutex::new(3);
25+
26+
// Increase this time to increase the likelihood of a deadlock.
27+
const SLEEP_TIME: Duration = Duration::from_nanos(1);
28+
29+
// Depending on random CPU performance, this section may deadlock, or may return a result. With
30+
// tracing enabled, the potential deadlock is always detected and a backtrace should be
31+
// produced.
32+
thread::scope(|s| {
33+
// Create an edge from a to b
34+
s.spawn(|| {
35+
let a = a.lock().unwrap();
36+
thread::sleep(SLEEP_TIME);
37+
*b.lock().unwrap() += *a;
38+
});
39+
40+
// Create an edge from b to c
41+
s.spawn(|| {
42+
let b = b.lock().unwrap();
43+
thread::sleep(SLEEP_TIME);
44+
*c.lock().unwrap() += *b;
45+
});
46+
47+
// Create an edge from c to a
48+
//
49+
// N.B. the program can deadlock on any of the three edges, as there is no guarantee which
50+
// thread will execute first. Nevertheless, any one of them is guaranteed to print with
51+
// tracing enabled.
52+
s.spawn(|| {
53+
let c = c.lock().unwrap();
54+
thread::sleep(SLEEP_TIME);
55+
*a.lock().unwrap() += *c;
56+
});
57+
});
58+
59+
println!(
60+
"{}, {}, {}",
61+
a.into_inner().unwrap(),
62+
b.into_inner().unwrap(),
63+
c.into_inner().unwrap()
64+
);
65+
}

third_party/rust_crates/forks/tracing-mutex-0.3.2/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
//! This conflicting dependency is not added to the graph, so future attempts at locking should
1616
//! succeed as normal.
1717
//!
18+
//! You can suppress panics by calling [`suppress_panics`]. This will cause the crate to print the
19+
//! cycle to stderr instead of panicking. This is useful for incrementally adopting tracing-mutex to
20+
//! a large codebase compiled with `panic=abort`, as it allows you to continue running your program
21+
//! even when a cycle is detected.
22+
//!
1823
//! # Structure
1924
//!
2025
//! Each module in this crate exposes wrappers for a specific base-mutex with dependency trakcing
@@ -116,6 +121,8 @@ mod reporting;
116121
pub mod stdsync;
117122
pub mod util;
118123

124+
pub use reporting::suppress_panics;
125+
119126
thread_local! {
120127
/// Stack to track which locks are held
121128
///
@@ -188,7 +195,7 @@ impl MutexId {
188195
});
189196

190197
if let Some(cycle) = opt_cycle {
191-
panic!("{}", Dep::panic_message(&cycle))
198+
reporting::report_cycle(&cycle);
192199
}
193200

194201
HELD_LOCKS.with(|locks| locks.borrow_mut().push(self.value()));

third_party/rust_crates/forks/tracing-mutex-0.3.2/src/reporting.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::backtrace::Backtrace;
66
use std::borrow::Cow;
77
use std::fmt::Write;
88
use std::sync::Arc;
9+
use std::sync::atomic::{AtomicBool, Ordering};
910

1011
#[cfg(feature = "backtraces")]
1112
pub type Dep = MutexDep<Arc<Backtrace>>;
@@ -15,12 +16,32 @@ pub type Dep = MutexDep<()>;
1516
// Base message to be reported when cycle is detected
1617
const BASE_MESSAGE: &str = "Found cycle in mutex dependency graph:";
1718

19+
static SHOULD_PANIC: AtomicBool = AtomicBool::new(true);
20+
21+
/// Call this early in main() to suppress panics when a cycle is detected and print the lock cycles
22+
/// to stderr instead.
23+
///
24+
/// This is not as useful a mechanism for detecting issues as a panic, but it is useful for
25+
/// incrementally rolling out usage of tracing-mutex to many programs that use a shared crate.
26+
pub fn suppress_panics() {
27+
SHOULD_PANIC.store(false, Ordering::Relaxed);
28+
}
29+
30+
pub(crate) fn report_cycle(cycle: &[Dep]) {
31+
let message = Dep::message(cycle);
32+
if SHOULD_PANIC.load(Ordering::Relaxed) {
33+
panic!("{message}");
34+
} else {
35+
eprintln!("{message}");
36+
}
37+
}
38+
1839
pub trait Reportable: Clone {
1940
/// Capture the current state
2041
fn capture() -> Self;
2142

2243
/// Format a trace of state for human readable consumption.
23-
fn panic_message(trace: &[Self]) -> Cow<'static, str>;
44+
fn message(trace: &[Self]) -> Cow<'static, str>;
2445
}
2546

2647
#[derive(Clone)]
@@ -35,7 +56,7 @@ impl Reportable for MutexDep<()> {
3556
Self(())
3657
}
3758

38-
fn panic_message(_trace: &[Self]) -> Cow<'static, str> {
59+
fn message(_trace: &[Self]) -> Cow<'static, str> {
3960
Cow::Borrowed(BASE_MESSAGE)
4061
}
4162
}
@@ -52,7 +73,7 @@ impl Reportable for MutexDep<Arc<Backtrace>> {
5273
Self(Arc::new(Backtrace::capture()))
5374
}
5475

55-
fn panic_message(trace: &[Self]) -> Cow<'static, str> {
76+
fn message(trace: &[Self]) -> Cow<'static, str> {
5677
let mut message = format!("{BASE_MESSAGE}\n");
5778

5879
for entry in trace {

0 commit comments

Comments
 (0)