Skip to content

Commit 9f7f00c

Browse files
committed
Allow suppressing panics.
This makes it possible to incrementally adopt tracing-mutex in a library shared by many binaries in the same project without having to fix all potential deadlocks in all binaries at once. The binaries that don't yet have proper lock hygeine can opt-out of real enforcement until their deadlocks are addressed.
1 parent 003f6a0 commit 9f7f00c

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ mod reporting;
116116
pub mod stdsync;
117117
pub mod util;
118118

119+
#[cfg(feature = "experimental")]
120+
pub use reporting::{set_panic_action, PanicAction};
121+
119122
thread_local! {
120123
/// Stack to track which locks are held
121124
///
@@ -188,7 +191,7 @@ impl MutexId {
188191
});
189192

190193
if let Some(cycle) = opt_cycle {
191-
panic!("{}", Dep::panic_message(&cycle))
194+
reporting::report_cycle(&cycle);
192195
}
193196

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

src/reporting.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use std::backtrace::Backtrace;
66
use std::borrow::Cow;
77
use std::fmt::Write;
88
use std::sync::Arc;
9+
use std::sync::atomic::AtomicU8;
10+
use std::sync::atomic::Ordering;
911

1012
#[cfg(feature = "backtraces")]
1113
pub type Dep = MutexDep<Arc<Backtrace>>;
@@ -15,12 +17,44 @@ pub type Dep = MutexDep<()>;
1517
// Base message to be reported when cycle is detected
1618
const BASE_MESSAGE: &str = "Found cycle in mutex dependency graph:";
1719

20+
/// Action to take when a cycle is detected.
21+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22+
#[repr(u8)]
23+
pub enum PanicAction {
24+
/// Panic when a cycle is detected.
25+
Panic = 0,
26+
/// Log the cycle to stderr but do not panic.
27+
#[cfg(feature = "experimental")]
28+
Log = 1,
29+
}
30+
31+
static PANIC_ACTION: AtomicU8 = AtomicU8::new(0);
32+
33+
/// Set the action to take when a cycle is detected.
34+
///
35+
/// This is useful for incrementally adopting tracing-mutex to a large codebase compiled with
36+
/// `panic=abort`, as it allows you to continue running your program even when a cycle is detected.
37+
#[cfg(feature = "experimental")]
38+
pub fn set_panic_action(action: PanicAction) {
39+
PANIC_ACTION.store(action as u8, Ordering::Relaxed);
40+
}
41+
42+
pub(crate) fn report_cycle(cycle: &[Dep]) {
43+
let message = Dep::message(cycle);
44+
let action = PANIC_ACTION.load(Ordering::Relaxed);
45+
if action == PanicAction::Panic as u8 {
46+
panic!("{message}");
47+
} else {
48+
eprintln!("{message}");
49+
}
50+
}
51+
1852
pub trait Reportable: Clone {
1953
/// Capture the current state
2054
fn capture() -> Self;
2155

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

2660
#[derive(Clone)]
@@ -35,7 +69,7 @@ impl Reportable for MutexDep<()> {
3569
Self(())
3670
}
3771

38-
fn panic_message(_trace: &[Self]) -> Cow<'static, str> {
72+
fn message(_trace: &[Self]) -> Cow<'static, str> {
3973
Cow::Borrowed(BASE_MESSAGE)
4074
}
4175
}
@@ -52,7 +86,7 @@ impl Reportable for MutexDep<Arc<Backtrace>> {
5286
Self(Arc::new(Backtrace::capture()))
5387
}
5488

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

5892
for entry in trace {

0 commit comments

Comments
 (0)