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::{ 9 os::unix::io::AsRawFd, 10 time::{Duration, Instant}, 11 }; 12 13 use super::EventFd; 14 15 #[derive(Debug, Copy, Clone)] 16 pub struct Clock(Instant); 17 impl Clock { new() -> Self18 pub fn new() -> Self { 19 Clock(Instant::now()) 20 } 21 now(&self) -> Self22 pub fn now(&self) -> Self { 23 Clock(Instant::now()) 24 } 25 duration_since(&self, earlier: &Self) -> Duration26 pub fn duration_since(&self, earlier: &Self) -> Duration { 27 self.0.duration_since(earlier.0) 28 } 29 elapsed(&self) -> Duration30 pub fn elapsed(&self) -> Duration { 31 self.0.elapsed() 32 } 33 checked_sub(&self, duration: Duration) -> Option<Self>34 pub fn checked_sub(&self, duration: Duration) -> Option<Self> { 35 Some(Clock(self.0.checked_sub(duration)?)) 36 } 37 } 38 39 impl Default for Clock { default() -> Self40 fn default() -> Self { 41 Self::new() 42 } 43 } 44 45 const NS_PER_SEC: u64 = 1_000_000_000; 46 /// A fake clock that can be used in tests to give exact control over the time. 47 /// For a code example, see the tests in sys_util/src/timerfd.rs. 48 #[derive(Debug)] 49 pub struct FakeClock { 50 ns_since_epoch: u64, 51 deadlines: Vec<(u64, EventFd)>, 52 } 53 54 impl FakeClock { new() -> Self55 pub fn new() -> Self { 56 FakeClock { 57 ns_since_epoch: 1_547_163_599 * NS_PER_SEC, 58 deadlines: Vec::new(), 59 } 60 } 61 62 /// Get the current time, according to this clock. now(&self) -> Self63 pub fn now(&self) -> Self { 64 FakeClock { 65 ns_since_epoch: self.ns_since_epoch, 66 deadlines: Vec::new(), 67 } 68 } 69 70 /// Get the current time in ns, according to this clock. nanos(&self) -> u6471 pub fn nanos(&self) -> u64 { 72 self.ns_since_epoch 73 } 74 75 /// Get the duration since |earlier|, assuming that earlier < self. duration_since(&self, earlier: &Self) -> Duration76 pub fn duration_since(&self, earlier: &Self) -> Duration { 77 let ns_diff = self.ns_since_epoch - earlier.ns_since_epoch; 78 Duration::new(ns_diff / NS_PER_SEC, (ns_diff % NS_PER_SEC) as u32) 79 } 80 81 /// Get the time that has elapsed since this clock was made. Always returns 0 on a FakeClock. elapsed(&self) -> Duration82 pub fn elapsed(&self) -> Duration { 83 self.now().duration_since(self) 84 } 85 checked_sub(&self, duration: Duration) -> Option<Self>86 pub fn checked_sub(&self, duration: Duration) -> Option<Self> { 87 Some(FakeClock { 88 ns_since_epoch: self 89 .ns_since_epoch 90 .checked_sub(duration.as_nanos() as u64)?, 91 deadlines: Vec::new(), 92 }) 93 } 94 95 /// Register the event fd for a notification when self's time is |deadline_ns|. 96 /// Drop any existing events registered to the same raw fd. add_event_fd(&mut self, deadline_ns: u64, fd: EventFd)97 pub fn add_event_fd(&mut self, deadline_ns: u64, fd: EventFd) { 98 self.deadlines 99 .retain(|(_, old_fd)| fd.as_raw_fd() != old_fd.as_raw_fd()); 100 self.deadlines.push((deadline_ns, fd)); 101 } 102 add_ns(&mut self, ns: u64)103 pub fn add_ns(&mut self, ns: u64) { 104 self.ns_since_epoch += ns; 105 let time = self.ns_since_epoch; 106 self.deadlines.retain(|(ns, fd)| { 107 let expired = *ns <= time; 108 if expired { 109 fd.write(1).unwrap(); 110 } 111 !expired 112 }); 113 } 114 } 115 116 impl Default for FakeClock { default() -> Self117 fn default() -> Self { 118 Self::new() 119 } 120 } 121