未验证 提交 e73ee1dd 编写于 作者: D Dylan DPC 提交者: GitHub

Rollup merge of #80736 - KodrAus:feat/lazy-resolve, r=dtolnay

use Once instead of Mutex to manage capture resolution

For #78299

This allows us to return borrows of the captured backtrace frames that are tied to a borrow of the Backtrace itself, instead of to some short-lived Mutex guard.

We could alternatively share `&Mutex<Capture>`s and lock on-demand, but then we could potentially forget to call `resolve()` before working with the capture. It also makes it semantically clearer what synchronization is needed on the capture.

cc `@seanchen1991` `@rust-lang/project-error-handling`
......@@ -95,11 +95,12 @@
// 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 {
......@@ -171,12 +172,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..];
......@@ -331,7 +331,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,
......@@ -355,12 +355,11 @@ pub fn status(&self) -> BacktraceStatus {
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 +403,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!
......
......@@ -3,7 +3,7 @@
#[test]
fn test_debug() {
let backtrace = Backtrace {
inner: Inner::Captured(Mutex::new(Capture {
inner: Inner::Captured(LazilyResolvedCapture::new(Capture {
actual_start: 1,
resolved: true,
frames: vec![
......@@ -54,4 +54,7 @@ fn test_debug() {
\n]";
assert_eq!(format!("{:#?}", backtrace), expected);
// Format the backtrace a second time, just to make sure lazily resolved state is stable
assert_eq!(format!("{:#?}", backtrace), expected);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册