@@ -89,12 +89,13 @@ mod tests;
89
89
// a backtrace or actually symbolizing it.
90
90
91
91
use crate :: backtrace_rs:: { self , BytesOrWideString } ;
92
+ use crate :: cell:: UnsafeCell ;
92
93
use crate :: env;
93
94
use crate :: ffi:: c_void;
94
95
use crate :: fmt;
95
96
use crate :: panic:: UnwindSafe ;
96
97
use crate :: sync:: atomic:: { AtomicUsize , Ordering :: Relaxed } ;
97
- use crate :: sync:: LazyLock ;
98
+ use crate :: sync:: Once ;
98
99
use crate :: sys_common:: backtrace:: { lock, output_filename} ;
99
100
use crate :: vec:: Vec ;
100
101
@@ -133,14 +134,20 @@ pub enum BacktraceStatus {
133
134
enum Inner {
134
135
Unsupported ,
135
136
Disabled ,
136
- Captured ( LazyLock < Capture , LazyResolve > ) ,
137
+ Captured ( LazilyResolvedCapture ) ,
137
138
}
138
139
139
140
struct Capture {
140
141
actual_start : usize ,
142
+ resolved : bool ,
141
143
frames : Vec < BacktraceFrame > ,
142
144
}
143
145
146
+ fn _assert_send_sync ( ) {
147
+ fn _assert < T : Send + Sync > ( ) { }
148
+ _assert :: < Backtrace > ( ) ;
149
+ }
150
+
144
151
/// A single frame of a backtrace.
145
152
#[ unstable( feature = "backtrace_frames" , issue = "79676" ) ]
146
153
pub struct BacktraceFrame {
@@ -173,7 +180,7 @@ impl fmt::Debug for Backtrace {
173
180
let capture = match & self . inner {
174
181
Inner :: Unsupported => return fmt. write_str ( "<unsupported>" ) ,
175
182
Inner :: Disabled => return fmt. write_str ( "<disabled>" ) ,
176
- Inner :: Captured ( c) => & * * c ,
183
+ Inner :: Captured ( c) => c . force ( ) ,
177
184
} ;
178
185
179
186
let frames = & capture. frames [ capture. actual_start ..] ;
@@ -341,10 +348,11 @@ impl Backtrace {
341
348
let inner = if frames. is_empty ( ) {
342
349
Inner :: Unsupported
343
350
} else {
344
- Inner :: Captured ( LazyLock :: new ( lazy_resolve ( Capture {
351
+ Inner :: Captured ( LazilyResolvedCapture :: new ( Capture {
345
352
actual_start : actual_start. unwrap_or ( 0 ) ,
346
353
frames,
347
- } ) ) )
354
+ resolved : false ,
355
+ } ) )
348
356
} ;
349
357
350
358
Backtrace { inner }
@@ -369,7 +377,7 @@ impl<'a> Backtrace {
369
377
#[ must_use]
370
378
#[ unstable( feature = "backtrace_frames" , issue = "79676" ) ]
371
379
pub fn frames ( & ' a self ) -> & ' a [ BacktraceFrame ] {
372
- if let Inner :: Captured ( c) = & self . inner { & c. frames } else { & [ ] }
380
+ if let Inner :: Captured ( c) = & self . inner { & c. force ( ) . frames } else { & [ ] }
373
381
}
374
382
}
375
383
@@ -379,7 +387,7 @@ impl fmt::Display for Backtrace {
379
387
let capture = match & self . inner {
380
388
Inner :: Unsupported => return fmt. write_str ( "unsupported backtrace" ) ,
381
389
Inner :: Disabled => return fmt. write_str ( "disabled backtrace" ) ,
382
- Inner :: Captured ( c) => & * * c ,
390
+ Inner :: Captured ( c) => c . force ( ) ,
383
391
} ;
384
392
385
393
let full = fmt. alternate ( ) ;
@@ -423,15 +431,46 @@ impl fmt::Display for Backtrace {
423
431
}
424
432
}
425
433
426
- type LazyResolve = impl FnOnce ( ) -> Capture + UnwindSafe ;
434
+ struct LazilyResolvedCapture {
435
+ sync : Once ,
436
+ capture : UnsafeCell < Capture > ,
437
+ }
438
+
439
+ impl LazilyResolvedCapture {
440
+ fn new ( capture : Capture ) -> Self {
441
+ LazilyResolvedCapture { sync : Once :: new ( ) , capture : UnsafeCell :: new ( capture) }
442
+ }
443
+
444
+ fn force ( & self ) -> & Capture {
445
+ self . sync . call_once ( || {
446
+ // SAFETY: This exclusive reference can't overlap with any others
447
+ // `Once` guarantees callers will block until this closure returns
448
+ // `Once` also guarantees only a single caller will enter this closure
449
+ unsafe { & mut * self . capture . get ( ) } . resolve ( ) ;
450
+ } ) ;
451
+
452
+ // SAFETY: This shared reference can't overlap with the exclusive reference above
453
+ unsafe { & * self . capture . get ( ) }
454
+ }
455
+ }
456
+
457
+ // SAFETY: Access to the inner value is synchronized using a thread-safe `Once`
458
+ // So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
459
+ unsafe impl Sync for LazilyResolvedCapture where Capture : Sync { }
460
+
461
+ impl Capture {
462
+ fn resolve ( & mut self ) {
463
+ // If we're already resolved, nothing to do!
464
+ if self . resolved {
465
+ return ;
466
+ }
467
+ self . resolved = true ;
427
468
428
- fn lazy_resolve ( mut capture : Capture ) -> LazyResolve {
429
- move || {
430
469
// Use the global backtrace lock to synchronize this as it's a
431
470
// requirement of the `backtrace` crate, and then actually resolve
432
471
// everything.
433
472
let _lock = lock ( ) ;
434
- for frame in capture . frames . iter_mut ( ) {
473
+ for frame in self . frames . iter_mut ( ) {
435
474
let symbols = & mut frame. symbols ;
436
475
let frame = match & frame. frame {
437
476
RawFrame :: Actual ( frame) => frame,
@@ -452,8 +491,6 @@ fn lazy_resolve(mut capture: Capture) -> LazyResolve {
452
491
} ) ;
453
492
}
454
493
}
455
-
456
- capture
457
494
}
458
495
}
459
496
0 commit comments