mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +00:00
fix potential race in AtomicU64 time monotonizer
This commit is contained in:
parent
2b5ddf36fd
commit
2b512cc329
@ -37,35 +37,41 @@ pub mod inner {
|
|||||||
// This could be a problem for programs that call instants at intervals greater
|
// This could be a problem for programs that call instants at intervals greater
|
||||||
// than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
|
// than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
|
||||||
let packed = (secs << 32) | nanos;
|
let packed = (secs << 32) | nanos;
|
||||||
let old = mono.load(Relaxed);
|
let mut old = mono.load(Relaxed);
|
||||||
|
loop {
|
||||||
if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 {
|
if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 {
|
||||||
mono.store(packed, Relaxed);
|
match mono.compare_exchange_weak(old, packed, Relaxed, Relaxed) {
|
||||||
raw
|
Ok(_) => return raw,
|
||||||
} else {
|
Err(x) => {
|
||||||
// Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
|
old = x;
|
||||||
// passed in value and the 64bits loaded from the atomic
|
continue;
|
||||||
let seconds_lower = old >> 32;
|
}
|
||||||
let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
|
}
|
||||||
if secs & 0xffff_ffff > seconds_lower {
|
} else {
|
||||||
// Backslide caused the lower 32bit of the seconds part to wrap.
|
// Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
|
||||||
// This must be the case because the seconds part is larger even though
|
// passed in value and the 64bits loaded from the atomic
|
||||||
// we are in the backslide branch, i.e. the seconds count should be smaller or equal.
|
let seconds_lower = old >> 32;
|
||||||
//
|
let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
|
||||||
// We assume that backslides are smaller than 2^32 seconds
|
if secs & 0xffff_ffff > seconds_lower {
|
||||||
// which means we need to add 1 to the upper half to restore it.
|
// Backslide caused the lower 32bit of the seconds part to wrap.
|
||||||
//
|
// This must be the case because the seconds part is larger even though
|
||||||
// Example:
|
// we are in the backslide branch, i.e. the seconds count should be smaller or equal.
|
||||||
// most recent observed time: 0xA1_0000_0000_0000_0000u128
|
//
|
||||||
// bits stored in AtomicU64: 0x0000_0000_0000_0000u64
|
// We assume that backslides are smaller than 2^32 seconds
|
||||||
// backslide by 1s
|
// which means we need to add 1 to the upper half to restore it.
|
||||||
// caller time is 0xA0_ffff_ffff_0000_0000u128
|
//
|
||||||
// -> we can fix up the upper half time by adding 1 << 32
|
// Example:
|
||||||
seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
|
// most recent observed time: 0xA1_0000_0000_0000_0000u128
|
||||||
|
// bits stored in AtomicU64: 0x0000_0000_0000_0000u64
|
||||||
|
// backslide by 1s
|
||||||
|
// caller time is 0xA0_ffff_ffff_0000_0000u128
|
||||||
|
// -> we can fix up the upper half time by adding 1 << 32
|
||||||
|
seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
|
||||||
|
}
|
||||||
|
let secs = seconds_upper | seconds_lower;
|
||||||
|
let nanos = old as u32;
|
||||||
|
return ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap();
|
||||||
}
|
}
|
||||||
let secs = seconds_upper | seconds_lower;
|
|
||||||
let nanos = old as u32;
|
|
||||||
ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user