Skip to content
16 changes: 16 additions & 0 deletions libdd-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ pub mod unix_utils;
/// ```
pub trait MutexExt<T> {
fn lock_or_panic(&self) -> MutexGuard<'_, T>;

/// Acquires the lock, recovering the guard instead of panicking if poisoned.
/// Reserve for terminal teardown (`shutdown`/`Drop`); elsewhere prefer
/// [`MutexExt::lock_or_panic`] since poisoning there indicates a real bug.
///
/// Default implementation just delegates to `lock_or_panic` (a safe, behavior-
/// preserving default for existing implementors); `Mutex<T>`'s impl below is the
/// one that actually recovers.
fn lock_or_recover(&self) -> MutexGuard<'_, T> {
self.lock_or_panic()
}
}

impl<T> MutexExt<T> for Mutex<T> {
Expand All @@ -88,6 +99,11 @@ impl<T> MutexExt<T> for Mutex<T> {
#[allow(clippy::unwrap_used)]
self.lock().unwrap()
}

#[inline(always)]
fn lock_or_recover(&self) -> MutexGuard<'_, T> {
self.lock().unwrap_or_else(|poisoned| poisoned.into_inner())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PoisonError should not be used, we have no guarantee over the state in which the value was left.

@mabdinur mabdinur Jul 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I narrowed lock_or_recover to only the terminal teardown paths. Let me know if we should remove it all together (I can use parking_lot::Mutex instead)

}
}

/// Extension trait for `RwLock` to provide methods that acquire read/write locks, panicking if
Expand Down
5 changes: 3 additions & 2 deletions libdd-data-pipeline/src/trace_exporter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,11 @@ impl<
#[cfg(not(target_arch = "wasm32"))]
pub fn shutdown(self, timeout: Option<Duration>) -> Result<(), TraceExporterError>
where
R: BlockingRuntime,
R: BlockingRuntime + Send + Sync + 'static,
Self: Send,
{
let runtime = self.shared_runtime.clone();
runtime.block_on(self.shutdown_async(timeout))?
runtime.block_on_send(self.shutdown_async(timeout))?
}

/// Async version of [`Self::shutdown`].
Expand Down
Loading
Loading