1use linux_uapi::itimerval;
6use starnix_uapi::errors::{Errno, error};
7use starnix_uapi::{itimerspec, timespec, timeval};
8use static_assertions::const_assert_eq;
9
10const MICROS_PER_SECOND: i64 = 1000 * 1000;
11pub const NANOS_PER_SECOND: i64 = 1000 * 1000 * 1000;
12
13pub const SCHEDULER_CLOCK_HZ: i64 = 100;
18
19const_assert_eq!(NANOS_PER_SECOND % SCHEDULER_CLOCK_HZ, 0);
20const NANOS_PER_SCHEDULER_TICK: i64 = NANOS_PER_SECOND / SCHEDULER_CLOCK_HZ;
21
22pub fn timeval_from_time<T: zx::Timeline>(time: zx::Instant<T>) -> timeval {
23 let nanos = time.into_nanos();
24 timeval { tv_sec: nanos / NANOS_PER_SECOND, tv_usec: (nanos % NANOS_PER_SECOND) / 1000 }
25}
26
27pub fn timeval_from_duration<T: zx::Timeline>(duration: zx::Duration<T>) -> timeval {
28 let nanos = duration.into_nanos();
29 timeval { tv_sec: nanos / NANOS_PER_SECOND, tv_usec: (nanos % NANOS_PER_SECOND) / 1000 }
30}
31
32pub fn timespec_from_time<T: zx::Timeline>(time: zx::Instant<T>) -> timespec {
33 let nanos = time.into_nanos();
34 timespec { tv_sec: nanos / NANOS_PER_SECOND, tv_nsec: nanos % NANOS_PER_SECOND }
35}
36
37pub fn timespec_from_duration<T: zx::Timeline>(duration: zx::Duration<T>) -> timespec {
38 let nanos = duration.into_nanos();
39 timespec { tv_sec: nanos / NANOS_PER_SECOND, tv_nsec: nanos % NANOS_PER_SECOND }
40}
41
42pub fn duration_from_timespec<T: zx::Timeline>(ts: timespec) -> Result<zx::Duration<T>, Errno> {
43 if ts.tv_nsec >= NANOS_PER_SECOND {
44 return error!(EINVAL);
45 }
46 if ts.tv_sec < 0 || ts.tv_nsec < 0 {
47 return error!(EINVAL);
48 }
49 Ok(zx::Duration::from_seconds(ts.tv_sec) + zx::Duration::from_nanos(ts.tv_nsec))
50}
51
52pub fn duration_from_timeval<T: zx::Timeline>(tv: timeval) -> Result<zx::Duration<T>, Errno> {
53 if tv.tv_usec < 0 || tv.tv_usec >= MICROS_PER_SECOND {
54 return error!(EDOM);
55 }
56 Ok(zx::Duration::from_seconds(tv.tv_sec) + zx::Duration::from_micros(tv.tv_usec))
57}
58
59pub fn duration_from_poll_timeout(timeout_ms: i32) -> Result<zx::MonotonicDuration, Errno> {
60 if timeout_ms == -1 {
61 return Ok(zx::MonotonicDuration::INFINITE);
62 }
63
64 if timeout_ms < 0 {
65 return error!(EINVAL);
66 }
67
68 Ok(zx::MonotonicDuration::from_millis(timeout_ms.into()))
69}
70
71pub fn itimerspec_from_itimerval(tv: itimerval) -> itimerspec {
72 itimerspec {
73 it_interval: timespec_from_timeval(tv.it_interval),
74 it_value: timespec_from_timeval(tv.it_value),
75 }
76}
77
78pub fn timespec_from_timeval(tv: timeval) -> timespec {
79 timespec { tv_sec: tv.tv_sec, tv_nsec: tv.tv_usec * 1000 }
80}
81
82pub fn time_from_timeval<T: zx::Timeline + Copy>(tv: timeval) -> Result<zx::Instant<T>, Errno> {
83 let duration = duration_from_timeval::<T>(tv)?;
84 if duration.into_nanos() < 0 { error!(EINVAL) } else { Ok(zx::Instant::ZERO + duration) }
85}
86
87pub fn time_from_timespec<T: zx::Timeline>(ts: timespec) -> Result<zx::Instant<T>, Errno> {
90 let duration = duration_from_timespec::<T>(ts)?;
91 Ok(zx::Instant::ZERO + duration)
92}
93
94pub fn timespec_is_zero(ts: timespec) -> bool {
95 ts.tv_sec == 0 && ts.tv_nsec == 0
96}
97
98pub fn itimerspec_from_deadline_interval<T: zx::Timeline>(
100 deadline: zx::Instant<T>,
101 interval: zx::MonotonicDuration,
102) -> itimerspec {
103 itimerspec {
104 it_interval: timespec_from_duration(interval),
105 it_value: timespec_from_time(deadline),
106 }
107}
108
109pub fn duration_to_scheduler_clock(duration: zx::MonotonicDuration) -> i64 {
110 duration.into_nanos() / NANOS_PER_SCHEDULER_TICK
111}
112
113#[cfg(test)]
114mod test {
115 use super::*;
116
117 const NANOS_PER_MICRO: i64 = 1000;
118
119 #[::fuchsia::test]
120 fn test_itimerspec() {
121 let deadline = zx::MonotonicInstant::from_nanos(2 * NANOS_PER_SECOND + 50);
122 let interval = zx::MonotonicDuration::from_nanos(1000);
123 let time_spec = itimerspec_from_deadline_interval(deadline, interval);
124 assert_eq!(time_spec.it_value.tv_sec, 2);
125 assert_eq!(time_spec.it_value.tv_nsec, 50);
126 assert_eq!(time_spec.it_interval.tv_nsec, 1000);
127 }
128
129 #[::fuchsia::test]
130 fn test_time_from_timespec() {
131 let time_spec = timespec { tv_sec: 100, tv_nsec: 100 };
132 let time: zx::MonotonicInstant =
133 time_from_timespec(time_spec).expect("failed to create time from time spec");
134 assert_eq!(time.into_nanos(), 100 * NANOS_PER_SECOND + 100);
135 }
136
137 #[::fuchsia::test]
138 fn test_invalid_time_from_timespec() {
139 let time_spec = timespec { tv_sec: 100, tv_nsec: NANOS_PER_SECOND * 2 };
140 assert_eq!(time_from_timespec::<zx::MonotonicTimeline>(time_spec), error!(EINVAL));
141
142 let time_spec = timespec { tv_sec: 1, tv_nsec: -1 };
143 assert_eq!(time_from_timespec::<zx::MonotonicTimeline>(time_spec), error!(EINVAL));
144
145 let time_spec = timespec { tv_sec: -1, tv_nsec: 1 };
146 assert_eq!(time_from_timespec::<zx::MonotonicTimeline>(time_spec), error!(EINVAL));
147 }
148
149 #[::fuchsia::test]
150 fn test_time_from_timeval() {
151 let tv = timeval { tv_sec: 100, tv_usec: 100 };
152 let time: zx::MonotonicInstant =
153 time_from_timeval(tv).expect("failed to create time from time spec");
154 assert_eq!(time.into_nanos(), 100 * NANOS_PER_SECOND + 100 * NANOS_PER_MICRO);
155 }
156
157 #[::fuchsia::test]
158 fn test_invalid_time_from_timeval() {
159 let tv = timeval { tv_sec: 100, tv_usec: MICROS_PER_SECOND * 2 };
160 assert_eq!(time_from_timeval::<zx::MonotonicTimeline>(tv), error!(EDOM));
161
162 let tv = timeval { tv_sec: 1, tv_usec: -1 };
163 assert_eq!(time_from_timeval::<zx::MonotonicTimeline>(tv), error!(EDOM));
164
165 let tv = timeval { tv_sec: -1, tv_usec: 1 };
166 assert_eq!(time_from_timeval::<zx::MonotonicTimeline>(tv), error!(EINVAL));
167 }
168}