summary refs log tree commit diff
path: root/sys_util/src/clock.rs
diff options
context:
space:
mode:
authorMiriam Zimmerman <mutexlox@google.com>2019-01-15 16:22:07 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-01-24 00:51:49 -0800
commitd3144f7a52608d5295dd5bf8edc4f3d76ae4ad82 (patch)
tree9003b21dca3304b4663d73c288fb8b180eff151a /sys_util/src/clock.rs
parent39f93db2a4434d7c4126005024cc2f085af3bb43 (diff)
downloadcrosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.tar
crosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.tar.gz
crosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.tar.bz2
crosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.tar.lz
crosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.tar.xz
crosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.tar.zst
crosvm-d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82.zip
Add FakeClock and FakeTimerFd for use in tests.
Together, these allow tests to create a FakeTimerFd that they can
trigger at a particular point in the test code, without having to rely
on sleep()s or other racy methods.

BUG=None
TEST=Unit tests for FakeTimerFd + dependent CL.

Change-Id: I14381272a6d75bebcdedb0a329a017a2131a3482
Reviewed-on: https://chromium-review.googlesource.com/1413830
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Miriam Zimmerman <mutexlox@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'sys_util/src/clock.rs')
-rw-r--r--sys_util/src/clock.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/sys_util/src/clock.rs b/sys_util/src/clock.rs
new file mode 100644
index 0000000..5f6ce0c
--- /dev/null
+++ b/sys_util/src/clock.rs
@@ -0,0 +1,84 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Utility file to provide a fake clock object representing current time, and a timerfd driven by
+// that time.
+
+use std::time::{Duration, Instant};
+use std::os::unix::io::AsRawFd;
+use EventFd;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Clock(Instant);
+impl Clock {
+    pub fn new() -> Self {
+        Clock(Instant::now())
+    }
+
+    pub fn now(&self) -> Self {
+        Clock(Instant::now())
+    }
+
+    pub fn duration_since(&self, earlier: &Self) -> Duration {
+        self.0.duration_since(earlier.0)
+    }
+}
+
+const NS_PER_SEC : u64 = 1_000_000_000;
+/// A fake clock that can be used in tests to give exact control over the time.
+/// For a code example, see the tests in sys_util/src/timerfd.rs.
+#[derive(Debug)]
+pub struct FakeClock {
+    ns_since_epoch: u64,
+    deadlines: Vec<(u64, EventFd)>,
+}
+
+impl FakeClock {
+    pub fn new() -> Self {
+        FakeClock {
+            ns_since_epoch: 1547163599 * NS_PER_SEC,
+            deadlines: Vec::new(),
+        }
+    }
+
+    /// Get the current time, according to this clock.
+    pub fn now(&self) -> Self {
+        FakeClock {
+            ns_since_epoch: self.ns_since_epoch,
+            deadlines: Vec::new(),
+        }
+    }
+
+    ///  Get the current time in ns, according to this clock.
+    pub fn nanos(&self) -> u64 {
+        self.ns_since_epoch
+    }
+
+    /// Get the duration since |earlier|, assuming that earlier < self.
+    pub fn duration_since(&self, earlier: &Self) -> Duration {
+        let ns_diff = self.ns_since_epoch - earlier.ns_since_epoch;
+        Duration::new(ns_diff / NS_PER_SEC, (ns_diff % NS_PER_SEC) as u32)
+    }
+
+    /// Register the event fd for a notification when self's time is |deadline_ns|.
+    /// Drop any existing events registered to the same raw fd.
+    pub fn add_event_fd(&mut self, deadline_ns: u64, fd: EventFd) {
+        self.deadlines.retain(|&(_, ref old_fd)| {
+            fd.as_raw_fd() != old_fd.as_raw_fd()
+        });
+        self.deadlines.push((deadline_ns, fd));
+    }
+
+    pub fn add_ns(&mut self, ns: u64) {
+        self.ns_since_epoch += ns;
+        let time = self.ns_since_epoch;
+        self.deadlines.retain(|&(ns, ref fd)| {
+            let expired = ns <= time;
+            if expired {
+                fd.write(1).unwrap();
+            }
+            !expired
+        });
+    }
+}