Skip to main content

relibc/header/bits_timespec/
mod.rs

1use crate::{
2    header::time::NANOSECONDS,
3    platform::types::{c_long, time_t},
4};
5
6/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
7#[allow(non_camel_case_types)]
8#[repr(C)]
9#[derive(Clone, Default, Debug)]
10pub struct timespec {
11    /// Whole seconds.
12    pub tv_sec: time_t,
13    /// Nanoseconds.
14    pub tv_nsec: c_long,
15}
16
17impl timespec {
18    // TODO: Write test
19
20    /// similar logic with timeradd
21    #[allow(clippy::should_implement_trait)] // not to confuse std::ops::Add
22    pub fn add(base: &timespec, interval: &timespec) -> Option<timespec> {
23        let delta_sec = base.tv_sec.checked_add(interval.tv_sec)?;
24        let delta_nsec = base.tv_nsec.checked_add(interval.tv_nsec)?;
25
26        if delta_sec < 0 || delta_nsec < 0 {
27            return None;
28        }
29
30        Some(Self {
31            tv_sec: delta_sec + (delta_nsec / NANOSECONDS) as time_t,
32            tv_nsec: delta_nsec % NANOSECONDS,
33        })
34    }
35    /// similar logic with timersub
36    pub fn subtract(later: &timespec, earlier: &timespec) -> Option<timespec> {
37        let delta_sec = later.tv_sec.checked_sub(earlier.tv_sec)?;
38        let delta_nsec = later.tv_nsec.checked_sub(earlier.tv_nsec)?;
39
40        let time = if delta_nsec < 0 {
41            let roundup_sec = -delta_nsec / NANOSECONDS + 1;
42            timespec {
43                tv_sec: delta_sec - (roundup_sec as time_t),
44                tv_nsec: roundup_sec * NANOSECONDS - delta_nsec,
45            }
46        } else {
47            timespec {
48                tv_sec: delta_sec + (delta_nsec / NANOSECONDS) as time_t,
49                tv_nsec: delta_nsec % NANOSECONDS,
50            }
51        };
52
53        if time.tv_sec < 0 {
54            // https://man7.org/linux/man-pages/man2/settimeofday.2.html
55            // caller should return EINVAL
56            return None;
57        }
58
59        Some(time)
60    }
61    pub fn is_zero(&self) -> bool {
62        self.tv_nsec == 0 && self.tv_sec == 0
63    }
64}
65
66#[cfg(target_os = "redox")]
67impl<'a> From<&'a syscall::TimeSpec> for timespec {
68    fn from(value: &'a syscall::TimeSpec) -> Self {
69        Self {
70            tv_sec: value.tv_sec as _,
71            tv_nsec: value.tv_nsec as _,
72        }
73    }
74}
75
76#[cfg(target_os = "redox")]
77impl<'a> From<&'a timespec> for syscall::TimeSpec {
78    fn from(tp: &timespec) -> Self {
79        Self {
80            tv_sec: tp.tv_sec as _,
81            tv_nsec: tp.tv_nsec as _,
82        }
83    }
84}