pub(crate) mod types;
pub(crate) use types::*;
pub(crate) mod logger;
pub(crate) mod graph;
pub(crate) mod detector;
#[allow(unused_imports)]
pub(crate) use detector::*;
pub mod thread;
pub(crate) mod locks;
pub mod stress;
#[allow(unused_imports)]
pub use stress::{StressConfig, StressMode};
use anyhow::Result;
#[cfg(feature = "logging-and-visualization")]
use logger::EventLogger;
pub struct Deloxide {
#[cfg(feature = "logging-and-visualization")]
log_path: Option<String>,
callback: Box<dyn Fn(DeadlockInfo) + Send + Sync + 'static>,
#[cfg(feature = "lock-order-graph")]
check_lock_order: bool,
#[cfg(feature = "stress-test")]
stress_mode: StressMode,
#[cfg(feature = "stress-test")]
stress_config: Option<StressConfig>,
}
impl Default for Deloxide {
fn default() -> Self {
Self::new()
}
}
impl Deloxide {
pub fn new() -> Self {
Deloxide {
#[cfg(feature = "logging-and-visualization")]
log_path: Some("deloxide.log".to_string()),
callback: Box::new(|info: DeadlockInfo| {
panic!(
"Deadlock detected: {}",
serde_json::to_string_pretty(&info).unwrap_or_else(|_| format!("{info:?}"))
);
}),
#[cfg(feature = "lock-order-graph")]
check_lock_order: true,
#[cfg(feature = "stress-test")]
stress_mode: StressMode::None,
#[cfg(feature = "stress-test")]
stress_config: None,
}
}
#[cfg(feature = "logging-and-visualization")]
pub fn with_log<P: AsRef<std::path::Path>>(mut self, path: P) -> Self {
self.log_path = Some(path.as_ref().to_string_lossy().into_owned());
self
}
#[cfg(feature = "logging-and-visualization")]
pub fn no_logging(mut self) -> Self {
self.log_path = None;
self
}
pub fn callback<F>(mut self, callback: F) -> Self
where
F: Fn(DeadlockInfo) + Send + Sync + 'static,
{
self.callback = Box::new(callback);
self
}
#[cfg(feature = "lock-order-graph")]
pub fn with_lock_order_checking(mut self) -> Self {
self.check_lock_order = true;
self
}
#[cfg(feature = "lock-order-graph")]
pub fn no_lock_order_checking(mut self) -> Self {
self.check_lock_order = false;
self
}
pub fn start(self) -> Result<()> {
#[cfg(feature = "logging-and-visualization")]
let logger = if let Some(log_path) = self.log_path {
Some(EventLogger::with_file(log_path)?)
} else {
None
};
let config = detector::DetectorConfig {
callback: self.callback,
#[cfg(feature = "lock-order-graph")]
check_lock_order: self.check_lock_order,
#[cfg(feature = "stress-test")]
stress_mode: self.stress_mode,
#[cfg(feature = "stress-test")]
stress_config: self.stress_config,
#[cfg(feature = "logging-and-visualization")]
logger,
};
detector::init_detector(config);
println!("{}", crate::BANNER);
Ok(())
}
#[cfg(feature = "stress-test")]
pub fn with_random_stress(mut self) -> Self {
self.stress_mode = StressMode::RandomPreemption;
if self.stress_config.is_none() {
self.stress_config = Some(StressConfig::default());
}
self
}
#[cfg(feature = "stress-test")]
pub fn with_component_stress(mut self) -> Self {
self.stress_mode = StressMode::ComponentBased;
if self.stress_config.is_none() {
self.stress_config = Some(StressConfig::default());
}
self
}
#[cfg(feature = "stress-test")]
pub fn with_stress_config(mut self, config: StressConfig) -> Self {
self.stress_config = Some(config);
self
}
}