@@ -95,11 +95,12 @@ mod tests;
95
95
// a backtrace or actually symbolizing it.
96
96
97
97
use crate :: backtrace_rs:: { self , BytesOrWideString } ;
98
+ use crate :: cell:: UnsafeCell ;
98
99
use crate :: env;
99
100
use crate :: ffi:: c_void;
100
101
use crate :: fmt;
101
102
use crate :: sync:: atomic:: { AtomicUsize , Ordering :: SeqCst } ;
102
- use crate :: sync:: Mutex ;
103
+ use crate :: sync:: Once ;
103
104
use crate :: sys_common:: backtrace:: { lock, output_filename} ;
104
105
use crate :: vec:: Vec ;
105
106
@@ -132,7 +133,7 @@ pub enum BacktraceStatus {
132
133
enum Inner {
133
134
Unsupported ,
134
135
Disabled ,
135
- Captured ( Mutex < Capture > ) ,
136
+ Captured ( LazilyResolvedCapture ) ,
136
137
}
137
138
138
139
struct Capture {
@@ -171,12 +172,11 @@ enum BytesOrWide {
171
172
172
173
impl fmt:: Debug for Backtrace {
173
174
fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
174
- let mut capture = match & self . inner {
175
+ let capture = match & self . inner {
175
176
Inner :: Unsupported => return fmt. write_str ( "<unsupported>" ) ,
176
177
Inner :: Disabled => return fmt. write_str ( "<disabled>" ) ,
177
- Inner :: Captured ( c) => c. lock ( ) . unwrap ( ) ,
178
+ Inner :: Captured ( c) => c. force ( ) ,
178
179
} ;
179
- capture. resolve ( ) ;
180
180
181
181
let frames = & capture. frames [ capture. actual_start ..] ;
182
182
@@ -331,7 +331,7 @@ impl Backtrace {
331
331
let inner = if frames. is_empty ( ) {
332
332
Inner :: Unsupported
333
333
} else {
334
- Inner :: Captured ( Mutex :: new ( Capture {
334
+ Inner :: Captured ( LazilyResolvedCapture :: new ( Capture {
335
335
actual_start : actual_start. unwrap_or ( 0 ) ,
336
336
frames,
337
337
resolved : false ,
@@ -355,12 +355,11 @@ impl Backtrace {
355
355
356
356
impl fmt:: Display for Backtrace {
357
357
fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
358
- let mut capture = match & self . inner {
358
+ let capture = match & self . inner {
359
359
Inner :: Unsupported => return fmt. write_str ( "unsupported backtrace" ) ,
360
360
Inner :: Disabled => return fmt. write_str ( "disabled backtrace" ) ,
361
- Inner :: Captured ( c) => c. lock ( ) . unwrap ( ) ,
361
+ Inner :: Captured ( c) => c. force ( ) ,
362
362
} ;
363
- capture. resolve ( ) ;
364
363
365
364
let full = fmt. alternate ( ) ;
366
365
let ( frames, style) = if full {
@@ -404,6 +403,33 @@ impl fmt::Display for Backtrace {
404
403
}
405
404
}
406
405
406
+ struct LazilyResolvedCapture {
407
+ sync : Once ,
408
+ capture : UnsafeCell < Capture > ,
409
+ }
410
+
411
+ impl LazilyResolvedCapture {
412
+ fn new ( capture : Capture ) -> Self {
413
+ LazilyResolvedCapture { sync : Once :: new ( ) , capture : UnsafeCell :: new ( capture) }
414
+ }
415
+
416
+ fn force ( & self ) -> & Capture {
417
+ self . sync . call_once ( || {
418
+ // SAFETY: This exclusive reference can't overlap with any others
419
+ // `Once` guarantees callers will block until this closure returns
420
+ // `Once` also guarantees only a single caller will enter this closure
421
+ unsafe { & mut * self . capture . get ( ) } . resolve ( ) ;
422
+ } ) ;
423
+
424
+ // SAFETY: This shared reference can't overlap with the exclusive reference above
425
+ unsafe { & * self . capture . get ( ) }
426
+ }
427
+ }
428
+
429
+ // SAFETY: Access to the inner value is synchronized using a thread-safe `Once`
430
+ // So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
431
+ unsafe impl Sync for LazilyResolvedCapture where Capture : Sync { }
432
+
407
433
impl Capture {
408
434
fn resolve ( & mut self ) {
409
435
// If we're already resolved, nothing to do!
0 commit comments