timer: Fixup alarm tick calculation
To avoid overflow errors for large clock rates let's divide the time
before we multiply it.
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
diff --git a/src/timer.rs b/src/timer.rs
index 6634282..ae60b07 100644
--- a/src/timer.rs
+++ b/src/timer.rs
@@ -143,8 +143,27 @@
pub fn set_alarm(&mut self, duration: Duration<isize>) -> TockResult<Alarm, SetAlarmError> {
let now = self.get_current_clock();
- let alarm_instant =
- now.num_ticks() as usize + (duration.ms() as usize * self.clock_frequency.hz()) / 1000;
+ let freq = self.clock_frequency.hz();
+ let duration_ms = duration.ms() as usize;
+ let ticks = match duration_ms.checked_mul(freq) {
+ Some(x) => x / 1000,
+ None => {
+ // Divide the largest of the two operands by 1000, to improve precision of the
+ // result.
+ if duration_ms > freq {
+ match (duration_ms / 1000).checked_mul(freq) {
+ Some(y) => y,
+ None => return Err(TockValue::Expected(SetAlarmError::DurationTooLong)),
+ }
+ } else {
+ match (freq / 1000).checked_mul(duration_ms) {
+ Some(y) => y,
+ None => return Err(TockValue::Expected(SetAlarmError::DurationTooLong)),
+ }
+ }
+ }
+ };
+ let alarm_instant = now.num_ticks() as usize + ticks;
let alarm_id =
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::SET_ALARM, alarm_instant, 0) };
@@ -212,6 +231,7 @@
#[derive(Clone, Copy, Debug)]
pub enum SetAlarmError {
NoMemoryAvailable,
+ DurationTooLong,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]