base: timer: handle 0 interval explicitly

Make it official that setting a Timer's interval to 0 is the same as
setting it to None, meaning it will not be periodic. Fixed the windows
timer to behave this way again, and updated Timer docstring.

Also updated APIC timer to use None for interval which is clearer.

Bug: b:248612697
Test: tested with UserspaceIrqChip in dynamic tick mode
Change-Id: I57713c3ace345a8c64b9219a8e60f36c54a9481c
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3925006
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Colin Downs-Razouk <colindr@google.com>
This commit is contained in:
Colin Downs-Razouk 2022-09-28 16:36:00 -07:00 committed by crosvm LUCI
parent ba9c9e2e1e
commit e0de18a6a5
5 changed files with 19 additions and 12 deletions

View file

@ -69,8 +69,8 @@ impl Timer {
Ok(())
}
/// Sets the timer to expire after `dur`. If `interval` is not `None` it represents
/// the period for repeated expirations after the initial expiration. Otherwise
/// Sets the timer to expire after `dur`. If `interval` is not `None` and non-zero it
/// represents the period for repeated expirations after the initial expiration. Otherwise
/// the timer will expire just once. Cancels any existing duration and repeating interval.
pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
self.set_time(Some(dur), interval)

View file

@ -89,9 +89,16 @@ impl Timer {
-((dur.as_secs() * 10_000_000 + (dur.subsec_nanos() as u64) / 100) as i64),
);
let period: i32 = match interval {
// Period is in ms, and 0ms means non-periodic, so we convert to ms and
// make sure it's non-zero.
Some(int) => std::cmp::max(1, int.as_millis() as i32),
Some(int) => {
if int.is_zero() {
// Duration of zero implies non-periodic, which means setting period
// to 0ms.
0
} else {
// Otherwise, convert to ms and make sure it's >=1ms.
std::cmp::max(1, int.as_millis() as i32)
}
}
// Period of 0ms=non-periodic.
None => 0,
};

View file

@ -88,8 +88,8 @@ impl FakeTimer {
}
}
/// Sets the timer to expire after `dur`. If `interval` is not `None` it represents
/// the period for repeated expirations after the initial expiration. Otherwise
/// Sets the timer to expire after `dur`. If `interval` is not `None` and non-zero it
/// represents the period for repeated expirations after the initial expiration. Otherwise
/// the timer will expire just once. Cancels any existing duration and repeating interval.
pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
let mut guard = self.clock.lock();

View file

@ -44,8 +44,8 @@ impl TimerAsync {
Ok(())
}
/// Sets the timer to expire after `dur`. If `interval` is not `None` it represents
/// the period for repeated expirations after the initial expiration. Otherwise
/// Sets the timer to expire after `dur`. If `interval` is not `None` and non-zero it
/// represents the period for repeated expirations after the initial expiration. Otherwise
/// the timer will expire just once. Cancels any existing duration and repeating interval.
pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> SysResult<()> {
self.io_source.as_source_mut().reset(dur, interval)

View file

@ -632,8 +632,8 @@ impl Apic {
let length = self.cycle_length * initial_count * self.get_timer_divide_control();
let mode = self.get_reg(Reg::LOCAL_TIMER) & TIMER_MODE_MASK;
let (duration, interval) = match mode {
TIMER_MODE_ONE_SHOT => (length, ZERO_DURATION),
TIMER_MODE_PERIODIC => (length, length),
TIMER_MODE_ONE_SHOT => (length, None),
TIMER_MODE_PERIODIC => (length, Some(length)),
TIMER_MODE_TSC_DEADLINE => {
warn!("APIC TSC-deadline timer not supported");
return;
@ -645,7 +645,7 @@ impl Apic {
};
self.last_tick = Instant::now();
if let Err(e) = self.timer.reset(duration, Some(interval)) {
if let Err(e) = self.timer.reset(duration, interval) {
error!(
"Failed to reset APIC timer to duration={:?} interval={:?}: {}",
duration, interval, e