// a backtrace or actually symbolizing it.
use crate::backtrace_rs::{self, BytesOrWideString};
+use crate::cell::UnsafeCell;
use crate::env;
use crate::ffi::c_void;
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sync::Mutex;
+use crate::sync::Once;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
enum Inner {
Unsupported,
Disabled,
- Captured(Mutex<Capture>),
+ Captured(LazilyResolvedCapture),
}
struct Capture {
_assert::<Backtrace>();
}
-struct BacktraceFrame {
+/// A single frame of a backtrace.
+#[unstable(feature = "backtrace_frames", issue = "79676")]
+pub struct BacktraceFrame {
frame: RawFrame,
symbols: Vec<BacktraceSymbol>,
}
+#[derive(Debug)]
enum RawFrame {
Actual(backtrace_rs::Frame),
#[cfg(test)]
impl fmt::Debug for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut capture = match &self.inner {
+ let capture = match &self.inner {
Inner::Unsupported => return fmt.write_str("<unsupported>"),
Inner::Disabled => return fmt.write_str("<disabled>"),
- Inner::Captured(c) => c.lock().unwrap(),
+ Inner::Captured(c) => c.force(),
};
- capture.resolve();
let frames = &capture.frames[capture.actual_start..];
}
}
+impl fmt::Debug for BacktraceFrame {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut dbg = fmt.debug_list();
+ dbg.entries(&self.symbols);
+ dbg.finish()
+ }
+}
+
impl fmt::Debug for BacktraceSymbol {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280
let inner = if frames.is_empty() {
Inner::Unsupported
} else {
- Inner::Captured(Mutex::new(Capture {
+ Inner::Captured(LazilyResolvedCapture::new(Capture {
actual_start: actual_start.unwrap_or(0),
frames,
resolved: false,
}
}
+impl<'a> Backtrace {
+ /// Returns an iterator over the backtrace frames.
+ #[unstable(feature = "backtrace_frames", issue = "79676")]
+ pub fn frames(&'a self) -> &'a [BacktraceFrame] {
+ if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] }
+ }
+}
+
impl fmt::Display for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut capture = match &self.inner {
+ let capture = match &self.inner {
Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
Inner::Disabled => return fmt.write_str("disabled backtrace"),
- Inner::Captured(c) => c.lock().unwrap(),
+ Inner::Captured(c) => c.force(),
};
- capture.resolve();
let full = fmt.alternate();
let (frames, style) = if full {
}
}
+struct LazilyResolvedCapture {
+ sync: Once,
+ capture: UnsafeCell<Capture>,
+}
+
+impl LazilyResolvedCapture {
+ fn new(capture: Capture) -> Self {
+ LazilyResolvedCapture { sync: Once::new(), capture: UnsafeCell::new(capture) }
+ }
+
+ fn force(&self) -> &Capture {
+ self.sync.call_once(|| {
+ // SAFETY: This exclusive reference can't overlap with any others
+ // `Once` guarantees callers will block until this closure returns
+ // `Once` also guarantees only a single caller will enter this closure
+ unsafe { &mut *self.capture.get() }.resolve();
+ });
+
+ // SAFETY: This shared reference can't overlap with the exclusive reference above
+ unsafe { &*self.capture.get() }
+ }
+}
+
+// SAFETY: Access to the inner value is synchronized using a thread-safe `Once`
+// So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
+unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
+
impl Capture {
fn resolve(&mut self) {
// If we're already resolved, nothing to do!