]> git.lizzy.rs Git - rust.git/blobdiff - library/std/src/backtrace.rs
remove pat2021
[rust.git] / library / std / src / backtrace.rs
index 7e8e0a621e31cf45bf8f8e68c4de6c11cb68887b..0aae4674b29423c763025113ecf236b8591f4dd4 100644 (file)
 // 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;
 
@@ -132,7 +133,7 @@ pub enum BacktraceStatus {
 enum Inner {
     Unsupported,
     Disabled,
-    Captured(Mutex<Capture>),
+    Captured(LazilyResolvedCapture),
 }
 
 struct Capture {
@@ -146,11 +147,14 @@ fn _assert<T: Send + Sync>() {}
     _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)]
@@ -171,12 +175,11 @@ enum BytesOrWide {
 
 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..];
 
@@ -196,6 +199,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+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
@@ -331,7 +342,7 @@ fn create(ip: usize) -> Backtrace {
         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,
@@ -353,14 +364,21 @@ pub fn status(&self) -> BacktraceStatus {
     }
 }
 
+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 {
@@ -404,6 +422,33 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+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!