@@ -37,35 +37,41 @@ pub mod inner {
37
37
// This could be a problem for programs that call instants at intervals greater
38
38
// than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
39
39
let packed = ( secs << 32 ) | nanos;
40
- let old = mono. load ( Relaxed ) ;
41
-
42
- if old == UNINITIALIZED || packed. wrapping_sub ( old) < u64:: MAX / 2 {
43
- mono. store ( packed, Relaxed ) ;
44
- raw
45
- } else {
46
- // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
47
- // passed in value and the 64bits loaded from the atomic
48
- let seconds_lower = old >> 32 ;
49
- let mut seconds_upper = secs & 0xffff_ffff_0000_0000 ;
50
- if secs & 0xffff_ffff > seconds_lower {
51
- // Backslide caused the lower 32bit of the seconds part to wrap.
52
- // This must be the case because the seconds part is larger even though
53
- // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
54
- //
55
- // We assume that backslides are smaller than 2^32 seconds
56
- // which means we need to add 1 to the upper half to restore it.
57
- //
58
- // Example:
59
- // most recent observed time: 0xA1_0000_0000_0000_0000u128
60
- // bits stored in AtomicU64: 0x0000_0000_0000_0000u64
61
- // backslide by 1s
62
- // caller time is 0xA0_ffff_ffff_0000_0000u128
63
- // -> we can fix up the upper half time by adding 1 << 32
64
- seconds_upper = seconds_upper. wrapping_add ( 0x1_0000_0000 ) ;
40
+ let mut old = mono. load ( Relaxed ) ;
41
+ loop {
42
+ if old == UNINITIALIZED || packed. wrapping_sub ( old) < u64:: MAX / 2 {
43
+ match mono. compare_exchange_weak ( old, packed, Relaxed , Relaxed ) {
44
+ Ok ( _) => return raw,
45
+ Err ( x) => {
46
+ old = x;
47
+ continue ;
48
+ }
49
+ }
50
+ } else {
51
+ // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
52
+ // passed in value and the 64bits loaded from the atomic
53
+ let seconds_lower = old >> 32 ;
54
+ let mut seconds_upper = secs & 0xffff_ffff_0000_0000 ;
55
+ if secs & 0xffff_ffff > seconds_lower {
56
+ // Backslide caused the lower 32bit of the seconds part to wrap.
57
+ // This must be the case because the seconds part is larger even though
58
+ // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
59
+ //
60
+ // We assume that backslides are smaller than 2^32 seconds
61
+ // which means we need to add 1 to the upper half to restore it.
62
+ //
63
+ // Example:
64
+ // most recent observed time: 0xA1_0000_0000_0000_0000u128
65
+ // bits stored in AtomicU64: 0x0000_0000_0000_0000u64
66
+ // backslide by 1s
67
+ // caller time is 0xA0_ffff_ffff_0000_0000u128
68
+ // -> we can fix up the upper half time by adding 1 << 32
69
+ seconds_upper = seconds_upper. wrapping_add ( 0x1_0000_0000 ) ;
70
+ }
71
+ let secs = seconds_upper | seconds_lower;
72
+ let nanos = old as u32 ;
73
+ return ZERO . checked_add_duration ( & Duration :: new ( secs, nanos) ) . unwrap ( ) ;
65
74
}
66
- let secs = seconds_upper | seconds_lower;
67
- let nanos = old as u32 ;
68
- ZERO . checked_add_duration ( & Duration :: new ( secs, nanos) ) . unwrap ( )
69
75
}
70
76
}
71
77
}
0 commit comments