ui_battlefield: a queued battleground's time waited is the time since the status plus the wire's waited ms, computed forwards so no Instant precedes the clock's origin (#628)
A queued battleground's time waited was computed backwards: `*at - Duration::from_millis(waited)`, with `waited` the server's u32 milliseconds. On Windows, std's `Instant` is a `Duration` from the performance counter's origin, near boot, so a wait longer than the machine's uptime panics there. On macOS and Linux, `Instant` is a signed timespec and the subtraction cannot panic; the issue's platform note overstated that. The time waited is now taken forwards, as `now.saturating_duration_since(*at) + waited`. That is the same value the reference's `[slot+0x1c] = now − Δ`, read back as `now − stamp`, gives, and the old formula's value everywhere it did not panic. `a_waited_span_longer_than_any_uptime_reads_forwards` pins a 49.7-day wait reading forwards and saturating at the getter's u32. `the_slot_view_reduces_the_clocks` still gives 7 000 ms for 5 s waited plus 2 s since. Built and gated on macOS; the Windows target was not built. Fixes #615 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
61f17d46c3
commit
45825b0609
@@ -153,11 +153,12 @@ fn slot_view(
|
||||
let deadline = *at + std::time::Duration::from_millis(u64::from(delta));
|
||||
view.port_expiration_ms = ms(deadline.saturating_duration_since(now));
|
||||
}
|
||||
// Status 1: the raw estimate, and `[slot+0x1c] = now − Δ` read back as `now − stamp`.
|
||||
// Status 1: the raw estimate, and `[slot+0x1c] = now − Δ` read back as `now − stamp`, which is
|
||||
// the time since the status plus Δ, taken forwards so no `Instant` precedes the clock's origin.
|
||||
if let Some((estimate, waited)) = status.queued {
|
||||
view.estimated_wait_ms = estimate;
|
||||
let stamp = *at - std::time::Duration::from_millis(u64::from(waited));
|
||||
view.time_waited_ms = ms(now.saturating_duration_since(stamp));
|
||||
let since = now.saturating_duration_since(*at);
|
||||
view.time_waited_ms = ms(since + std::time::Duration::from_millis(u64::from(waited)));
|
||||
}
|
||||
view
|
||||
}
|
||||
@@ -389,6 +390,26 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_waited_span_longer_than_any_uptime_reads_forwards() {
|
||||
let at = Instant::now();
|
||||
let mut queued = status(0, 489, 1);
|
||||
queued.queued = Some((0, u32::MAX));
|
||||
let v = slot_view(Some(&(queued.clone(), at)), None, at);
|
||||
assert_eq!(
|
||||
v.time_waited_ms,
|
||||
u32::MAX,
|
||||
"49.7 days waited, no stamp needed"
|
||||
);
|
||||
let later = at + std::time::Duration::from_secs(9);
|
||||
let v = slot_view(Some(&(queued, at)), None, later);
|
||||
assert_eq!(
|
||||
v.time_waited_ms,
|
||||
u32::MAX,
|
||||
"saturates as the getter's u32 does"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_slot_view_reduces_the_clocks() {
|
||||
let at = Instant::now();
|
||||
|
||||
Reference in New Issue
Block a user