1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
//---------------------------------------------------------------------------------------------------- Use
use crate::time::{
Time,
TimeFull,
Htop,
};
//---------------------------------------------------------------------------------------------------- Uptime Trait
/// System uptime
///
/// This trait represents structures that are viable containers for holding and
/// displaying system uptime, notably, everything in the `readable::time` module.
///
/// `readable::run` types do not implement this trait as
/// they have a relatively low upper limit of `99` hours.
///
/// This trait is sealed and can only be implemented internally on `readable` types.
pub trait Uptime: private::Sealed {
/// This function creates a `Self` from the live system uptime and can be used on:
/// - Windows
/// - macOS
/// - BSDs
/// - Linux
///
/// If the underlying call fails (unlikely) this function will return an `unknown` variant.
///
/// ## Example
/// ```rust
/// # use readable::time::*;
/// // Introduce trait into scope.
/// use readable::Uptime;
///
/// // Capture the _current_ system uptime,
/// // and format it into a `Time`.
/// std::thread::sleep(std::time::Duration::from_secs(1));
/// let mut time: Time = Time::uptime();
/// # // Get around CI.
/// # let time = 1;
/// assert!(time >= 1);
/// ```
fn uptime() -> Self;
/// This takes an existing instance of `Self` and mutates
/// it if the current system uptime is different than the `self` value.
///
/// E.g:
/// 1. `Self::uptime()` is called
/// 2. A few seconds passes
/// 3. `Self::uptime_mut()` is called
/// 4. The above will mutate `self` to reflect the new uptime
///
/// This returns the input `&mut self` for method chaining.
fn uptime_mut(&mut self) -> &mut Self;
}
//---------------------------------------------------------------------------------------------------- Uptime Impl
mod private {
use super::*;
pub trait Sealed {}
impl Sealed for Time {}
impl Sealed for TimeFull {}
impl Sealed for Htop {}
}
macro_rules! impl_uptime {
($($time:ty),*) => {
$(
impl Uptime for $time {
#[inline]
fn uptime() -> Self {
Self::from(uptime_inner())
}
fn uptime_mut(&mut self) -> &mut Self {
let inner = uptime_inner();
if inner != self.inner() {
*self = Self::from(inner);
}
self
}
}
)*
};
}
impl_uptime!(Time, TimeFull, Htop);
//---------------------------------------------------------------------------------------------------- Uptime Function
#[inline]
// SAFETY: we're calling C.
fn uptime_inner() -> u32 {
#[cfg(target_os = "windows")]
{
let milliseconds = unsafe { windows::Win32::System::SystemInformation::GetTickCount64() };
return (milliseconds as f64 / 1000.0) as u32;
}
#[cfg(all(target_os = "unix", not(target_os = "linux")))]
{
use std::time::{Duration,SystemTime};
let mut request = [libc::CTL_KERN, libc::KERN_BOOTTIME];
let mut timeval = libc::timeval {
tv_sec: 0,
tv_nsec: 0,
};
let mut size: libc::size_t = std::mem::size_of_val(&timeval);
let err = unsafe { libc::sysctl(
&mut request[0],
2,
&mut timeval as _,
&mut size,
std::ptr::null_mut(),
0,
)};
if err == 0 {
if let Ok(mut sys) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
return sys - Duration::from_secs(timeval.tv_sec as u64);
}
}
}
#[cfg(target_os = "linux")]
{
let mut timespec = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
let ptr = std::ptr::addr_of_mut!(timespec);
// Get time, ignore return error.
unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, ptr) };
// Time is set if no error, else
// our default `0` is returned.
return timespec.tv_sec as u32;
}
0
}