1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Utility file to provide a fake clock object representing current time, and a timerfd driven by 6 // that time. 7 8 use std::os::unix::io::AsRawFd; 9 use std::time::{Duration, Instant}; 10 11 use crate::EventFd; 12 13 #[derive(Debug, Copy, Clone)] 14 pub struct Clock(Instant); 15 impl Clock { new() -> Self16 pub fn new() -> Self { 17 Clock(Instant::now()) 18 } 19 now(&self) -> Self20 pub fn now(&self) -> Self { 21 Clock(Instant::now()) 22 } 23 duration_since(&self, earlier: &Self) -> Duration24 pub fn duration_since(&self, earlier: &Self) -> Duration { 25 self.0.duration_since(earlier.0) 26 } 27 elapsed(&self) -> Duration28 pub fn elapsed(&self) -> Duration { 29 self.0.elapsed() 30 } 31 checked_sub(&self, duration: Duration) -> Option<Self>32 pub fn checked_sub(&self, duration: Duration) -> Option<Self> { 33 Some(Clock(self.0.checked_sub(duration)?)) 34 } 35 } 36 37 impl Default for Clock { default() -> Self38 fn default() -> Self { 39 Self::new() 40 } 41 } 42 43 const NS_PER_SEC: u64 = 1_000_000_000; 44 /// A fake clock that can be used in tests to give exact control over the time. 45 /// For a code example, see the tests in sys_util/src/timerfd.rs. 46 #[derive(Debug)] 47 pub struct FakeClock { 48 ns_since_epoch: u64, 49 deadlines: Vec<(u64, EventFd)>, 50 } 51 52 impl FakeClock { new() -> Self53 pub fn new() -> Self { 54 FakeClock { 55 ns_since_epoch: 1_547_163_599 * NS_PER_SEC, 56 deadlines: Vec::new(), 57 } 58 } 59 60 /// Get the current time, according to this clock. now(&self) -> Self61 pub fn now(&self) -> Self { 62 FakeClock { 63 ns_since_epoch: self.ns_since_epoch, 64 deadlines: Vec::new(), 65 } 66 } 67 68 /// Get the current time in ns, according to this clock. nanos(&self) -> u6469 pub fn nanos(&self) -> u64 { 70 self.ns_since_epoch 71 } 72 73 /// Get the duration since |earlier|, assuming that earlier < self. duration_since(&self, earlier: &Self) -> Duration74 pub fn duration_since(&self, earlier: &Self) -> Duration { 75 let ns_diff = self.ns_since_epoch - earlier.ns_since_epoch; 76 Duration::new(ns_diff / NS_PER_SEC, (ns_diff % NS_PER_SEC) as u32) 77 } 78 79 /// Get the time that has elapsed since this clock was made. Always returns 0 on a FakeClock. elapsed(&self) -> Duration80 pub fn elapsed(&self) -> Duration { 81 self.now().duration_since(self) 82 } 83 checked_sub(&self, duration: Duration) -> Option<Self>84 pub fn checked_sub(&self, duration: Duration) -> Option<Self> { 85 Some(FakeClock { 86 ns_since_epoch: self 87 .ns_since_epoch 88 .checked_sub(duration.as_nanos() as u64)?, 89 deadlines: Vec::new(), 90 }) 91 } 92 93 /// Register the event fd for a notification when self's time is |deadline_ns|. 94 /// Drop any existing events registered to the same raw fd. add_event_fd(&mut self, deadline_ns: u64, fd: EventFd)95 pub fn add_event_fd(&mut self, deadline_ns: u64, fd: EventFd) { 96 self.deadlines 97 .retain(|(_, old_fd)| fd.as_raw_fd() != old_fd.as_raw_fd()); 98 self.deadlines.push((deadline_ns, fd)); 99 } 100 add_ns(&mut self, ns: u64)101 pub fn add_ns(&mut self, ns: u64) { 102 self.ns_since_epoch += ns; 103 let time = self.ns_since_epoch; 104 self.deadlines.retain(|(ns, fd)| { 105 let expired = *ns <= time; 106 if expired { 107 fd.write(1).unwrap(); 108 } 109 !expired 110 }); 111 } 112 } 113 114 impl Default for FakeClock { default() -> Self115 fn default() -> Self { 116 Self::new() 117 } 118 } 119