1
1
use std:: {
2
2
fmt:: { self , Display , Formatter } ,
3
- sync:: atomic:: { AtomicU64 , Ordering } ,
3
+ sync:: atomic:: { AtomicBool , AtomicU64 , Ordering } ,
4
4
} ;
5
5
6
- use once_cell:: sync:: OnceCell ;
7
-
8
6
use crate :: events:: Event ;
9
7
10
8
#[ derive( Debug ) ]
@@ -24,8 +22,7 @@ impl Display for SkipReason {
24
22
}
25
23
26
24
static EVENTS_SKIPPED_BEFORE_MAIN : AtomicU64 = AtomicU64 :: new ( 0 ) ;
27
-
28
- static WARNED_AFTER_MAIN : OnceCell < ( ) > = OnceCell :: new ( ) ;
25
+ static WARNED_AFTER_MAIN : AtomicBool = AtomicBool :: new ( false ) ;
29
26
30
27
/// Notify the user if any [`Event`]s were skipped before `main`.
31
28
///
@@ -45,14 +42,22 @@ pub(super) fn skip_event(event: Event, reason: SkipReason) {
45
42
use SkipReason :: * ;
46
43
match reason {
47
44
BeforeMain => {
45
+ // # Async-signal-safety: atomic increments are safe.
48
46
EVENTS_SKIPPED_BEFORE_MAIN . fetch_add ( 1 , Ordering :: Relaxed ) ;
49
47
}
50
48
AfterMain => {
51
- // This is after `main`, so it's safe to use things like `eprintln!`,
52
- // which uses `ReentrantMutex` internally, which may use `pthread` mutexes.
53
- WARNED_AFTER_MAIN . get_or_init ( || {
49
+ // # Async-signal-safety: not really signal-safe, but if we
50
+ // get a signal after `main` ends, we're probably fine.
51
+ // The allocator should have enough free memory by now
52
+ // to not need to call `mmap`.
53
+ if !WARNED_AFTER_MAIN . swap ( true , Ordering :: Relaxed ) {
54
+ // WARNED_AFTER_MAIN was previously `false` but we swapped it,
55
+ // which will happen exactly once per run so we can print now.
54
56
eprintln ! ( "skipping {reason}" ) ;
55
- } ) ;
57
+ }
58
+ // TODO: It would be nice to get rid of the two `eprintln`s here
59
+ // so we can guarantee signal safety, but then we would get no
60
+ // debugging output.
56
61
eprintln ! ( "skipped event after `main`: {:?}" , event. kind) ;
57
62
}
58
63
} ;
0 commit comments