linux_api/
time.rs

1use linux_syscall::Result as LinuxSyscallResult;
2use linux_syscall::Result64;
3use linux_syscall::syscall;
4use num_enum::{IntoPrimitive, TryFromPrimitive};
5
6use crate::bindings;
7use crate::const_conversions;
8use crate::errno::Errno;
9
10pub use bindings::linux___kernel_clockid_t;
11
12/// Clocks
13#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
14// clock_gettime syscall takes clockid_t, which is i32:
15// ```
16// kernel/time/posix-timers.c:SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
17// include/linux/types.h:typedef __kernel_clockid_t        clockid_t;
18// include/uapi/asm-generic/posix_types.h:typedef int              __kernel_clockid_t;
19// ```
20#[repr(i32)]
21#[allow(non_camel_case_types)]
22pub enum ClockId {
23    CLOCK_REALTIME = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_REALTIME),
24    CLOCK_MONOTONIC = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_MONOTONIC),
25    CLOCK_PROCESS_CPUTIME_ID =
26        const_conversions::i32_from_u32(bindings::LINUX_CLOCK_PROCESS_CPUTIME_ID),
27    CLOCK_THREAD_CPUTIME_ID =
28        const_conversions::i32_from_u32(bindings::LINUX_CLOCK_THREAD_CPUTIME_ID),
29    CLOCK_MONOTONIC_RAW = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_MONOTONIC_RAW),
30    CLOCK_REALTIME_COARSE = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_REALTIME_COARSE),
31    CLOCK_MONOTONIC_COARSE =
32        const_conversions::i32_from_u32(bindings::LINUX_CLOCK_MONOTONIC_COARSE),
33    CLOCK_BOOTTIME = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_BOOTTIME),
34    CLOCK_REALTIME_ALARM = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_REALTIME_ALARM),
35    CLOCK_BOOTTIME_ALARM = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_BOOTTIME_ALARM),
36    CLOCK_SGI_CYCLE = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_SGI_CYCLE),
37    CLOCK_TAI = const_conversions::i32_from_u32(bindings::LINUX_CLOCK_TAI),
38}
39
40bitflags::bitflags! {
41    /// Valid flags passed to `clock_nanosleep(2)`.
42    #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
43    pub struct ClockNanosleepFlags: i32 {
44        const TIMER_ABSTIME = const_conversions::i32_from_u32(bindings::LINUX_TIMER_ABSTIME);
45    }
46}
47
48/// Interval timers
49#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
50// getitimer takes `int`:
51// ```
52// kernel/time/itimer.c:SYSCALL_DEFINE2(getitimer, int, which, struct __kernel_old_itimerval __user *, value)
53// ```
54#[repr(i32)]
55#[allow(non_camel_case_types)]
56pub enum ITimerId {
57    ITIMER_REAL = const_conversions::i32_from_u32(bindings::LINUX_ITIMER_REAL),
58    ITIMER_VIRTUAL = const_conversions::i32_from_u32(bindings::LINUX_ITIMER_VIRTUAL),
59    ITIMER_PROF = const_conversions::i32_from_u32(bindings::LINUX_ITIMER_PROF),
60}
61
62pub use bindings::linux_timespec;
63#[allow(non_camel_case_types)]
64pub type timespec = linux_timespec;
65unsafe impl shadow_pod::Pod for timespec {}
66unsafe impl vasi::VirtualAddressSpaceIndependent for timespec {}
67
68pub use bindings::linux___kernel_timespec;
69#[allow(non_camel_case_types)]
70pub type kernel_timespec = linux___kernel_timespec;
71unsafe impl shadow_pod::Pod for kernel_timespec {}
72unsafe impl vasi::VirtualAddressSpaceIndependent for kernel_timespec {}
73
74pub use bindings::linux_timeval;
75#[allow(non_camel_case_types)]
76pub type timeval = linux_timeval;
77unsafe impl shadow_pod::Pod for timeval {}
78unsafe impl vasi::VirtualAddressSpaceIndependent for timeval {}
79
80pub use bindings::linux___kernel_old_timeval;
81#[allow(non_camel_case_types)]
82pub type kernel_old_timeval = linux___kernel_old_timeval;
83unsafe impl shadow_pod::Pod for kernel_old_timeval {}
84unsafe impl vasi::VirtualAddressSpaceIndependent for kernel_old_timeval {}
85
86pub fn clock_gettime_raw(clockid: linux___kernel_clockid_t) -> Result<timespec, Errno> {
87    let mut t = shadow_pod::zeroed();
88    unsafe { syscall!(linux_syscall::SYS_clock_gettime, clockid, &mut t) }
89        .check()
90        .map_err(Errno::from)?;
91    Ok(t)
92}
93
94pub fn clock_gettime(clockid: ClockId) -> Result<timespec, Errno> {
95    clock_gettime_raw(clockid.into())
96}
97
98pub use bindings::linux_itimerspec;
99#[allow(non_camel_case_types)]
100pub type itimerspec = linux_itimerspec;
101unsafe impl shadow_pod::Pod for itimerspec {}
102unsafe impl vasi::VirtualAddressSpaceIndependent for itimerspec {}
103
104pub use bindings::linux_itimerval;
105#[allow(non_camel_case_types)]
106pub type itimerval = linux_itimerval;
107unsafe impl shadow_pod::Pod for itimerval {}
108unsafe impl vasi::VirtualAddressSpaceIndependent for itimerval {}
109
110pub use bindings::linux___kernel_old_itimerval;
111#[allow(non_camel_case_types)]
112pub type kernel_old_itimerval = linux___kernel_old_itimerval;
113unsafe impl shadow_pod::Pod for kernel_old_itimerval {}
114unsafe impl vasi::VirtualAddressSpaceIndependent for kernel_old_itimerval {}
115
116/// Raw `alarm` syscall. Permits u64 arg and return value for generality with
117/// the general syscall ABI, but note that the `alarm` syscall definition itself
118/// uses u32.
119pub fn alarm_raw(secs: u64) -> Result<u64, Errno> {
120    unsafe { syscall!(linux_syscall::SYS_alarm, secs) }
121        .try_u64()
122        .map_err(Errno::from)
123}
124
125/// Make an `alarm` syscall.
126pub fn alarm(secs: u32) -> Result<u32, Errno> {
127    let res = alarm_raw(secs.into())?;
128    // The syscall defines the return type as u32, so it *should* always be
129    // convertible to u32.
130    Ok(res.try_into().unwrap())
131}
132
133/// Make a `getitimer` syscall.
134///
135/// # Safety
136///
137/// `curr_value` must be safe for the kernel to write to.
138//
139// Kernel decl:
140// ```
141// kernel/time/itimer.c:SYSCALL_DEFINE2(getitimer, int, which, struct __kernel_old_itimerval __user *, value)
142// ```
143pub unsafe fn getitimer_raw(
144    which: core::ffi::c_int,
145    curr_value: *mut kernel_old_itimerval,
146) -> Result<(), Errno> {
147    unsafe { syscall!(linux_syscall::SYS_getitimer, which, curr_value) }
148        .check()
149        .map_err(Errno::from)
150}
151
152/// Make a `getitimer` syscall.
153pub fn getitimer(which: ITimerId, curr_value: &mut kernel_old_itimerval) -> Result<(), Errno> {
154    unsafe { getitimer_raw(which.into(), curr_value) }
155}
156
157/// Make a `setitimer` syscall.
158///
159/// # Safety
160///
161/// `old_value` must be safe for the kernel to write to, or NULL.
162///
163/// An invalid or inaccessible `new_value` *isn't* a safety violation, but may
164/// cause the syscall to fail e.g. with `EFAULT`.
165pub unsafe fn setitimer_raw(
166    which: core::ffi::c_int,
167    new_value: *const kernel_old_itimerval,
168    old_value: *mut kernel_old_itimerval,
169) -> Result<(), Errno> {
170    unsafe { syscall!(linux_syscall::SYS_setitimer, which, new_value, old_value) }
171        .check()
172        .map_err(Errno::from)
173}
174
175/// Make a `setitimer` syscall.
176pub fn setitimer(
177    which: ITimerId,
178    new_value: &kernel_old_itimerval,
179    old_value: Option<&mut kernel_old_itimerval>,
180) -> Result<(), Errno> {
181    let old_value = old_value
182        .map(core::ptr::from_mut)
183        .unwrap_or(core::ptr::null_mut());
184    unsafe { setitimer_raw(which.into(), new_value, old_value) }
185}
186
187mod export {
188    use super::*;
189
190    #[unsafe(no_mangle)]
191    pub unsafe extern "C-unwind" fn linux_clock_gettime(
192        clockid: i32,
193        res: *mut linux_timespec,
194    ) -> i64 {
195        let t = match clock_gettime_raw(clockid) {
196            Ok(t) => t,
197            Err(e) => return e.to_negated_i64(),
198        };
199        assert!(!res.is_null());
200        unsafe { res.write(t) }
201        0
202    }
203}