base: unix: timer: factor out timerfd_settime call

Deduplicate the unsafe block and the update of interval into a helper
function so that reset() and clear() can be greatly simplified.

BUG=None
TEST=tools/presubmit --all

Change-Id: Ic0210bc3dd2239b575d47f718709333bce842509
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3653256
Reviewed-by: Anton Romanov <romanton@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
diff --git a/base/src/sys/unix/timer.rs b/base/src/sys/unix/timer.rs
index 2cd1cb4..154aa8d 100644
--- a/base/src/sys/unix/timer.rs
+++ b/base/src/sys/unix/timer.rs
@@ -43,17 +43,15 @@
         })
     }
 
-    /// Sets the timer to expire after `dur`.  If `interval` is not `None` 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<()> {
+    // Calls `timerfd_settime()` and stores the new value of `interval`.
+    fn set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()> {
         // The posix implementation of timer does not need self.interval, but we
         // save it anyways to keep a consistent interface.
         self.interval = interval;
 
         let spec = libc::itimerspec {
             it_interval: duration_to_timespec(interval.unwrap_or_default()),
-            it_value: duration_to_timespec(dur),
+            it_value: duration_to_timespec(dur.unwrap_or_default()),
         };
 
         // Safe because this doesn't modify any memory and we check the return value.
@@ -65,6 +63,18 @@
         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
+    /// 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)
+    }
+
+    /// Disarms the timer.
+    pub fn clear(&mut self) -> Result<()> {
+        self.set_time(None, None)
+    }
+
     /// Waits until the timer expires or an optional wait timeout expires, whichever happens first.
     ///
     /// # Returns
@@ -154,22 +164,6 @@
         }
     }
 
-    /// Disarms the timer.
-    pub fn clear(&mut self) -> Result<()> {
-        // Safe because we are zero-initializing a struct with only primitive member fields.
-        let spec: libc::itimerspec = unsafe { mem::zeroed() };
-
-        // Safe because this doesn't modify any memory and we check the return value.
-        let ret = unsafe { timerfd_settime(self.as_raw_descriptor(), 0, &spec, ptr::null_mut()) };
-        if ret < 0 {
-            return errno_result();
-        }
-
-        self.interval = None;
-
-        Ok(())
-    }
-
     /// Returns the resolution of timers on the host.
     pub fn resolution() -> Result<Duration> {
         // Safe because we are zero-initializing a struct with only primitive member fields.