@@ -37,35 +37,41 @@ pub mod inner {
3737 // This could be a problem for programs that call instants at intervals greater
3838 // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
3939 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 ( ) ;
6574 }
66- let secs = seconds_upper | seconds_lower;
67- let nanos = old as u32 ;
68- ZERO . checked_add_duration ( & Duration :: new ( secs, nanos) ) . unwrap ( )
6975 }
7076 }
7177}
0 commit comments