1 | //! `Timespec` and related types, which are used by multiple public API |
2 | //! modules. |
3 | |
4 | #[cfg (not(fix_y2038))] |
5 | use crate::backend::c; |
6 | |
7 | /// `struct timespec` |
8 | #[cfg (not(fix_y2038))] |
9 | pub type Timespec = c::timespec; |
10 | |
11 | /// `struct timespec` |
12 | #[cfg (fix_y2038)] |
13 | #[derive (Debug, Clone, Copy)] |
14 | #[repr (C)] |
15 | pub struct Timespec { |
16 | /// Seconds. |
17 | pub tv_sec: Secs, |
18 | |
19 | /// Nanoseconds. Must be less than 1_000_000_000. |
20 | pub tv_nsec: Nsecs, |
21 | } |
22 | |
23 | /// A type for the `tv_sec` field of [`Timespec`]. |
24 | #[cfg (not(fix_y2038))] |
25 | #[allow (deprecated)] |
26 | pub type Secs = c::time_t; |
27 | |
28 | /// A type for the `tv_sec` field of [`Timespec`]. |
29 | #[cfg (fix_y2038)] |
30 | pub type Secs = i64; |
31 | |
32 | /// A type for the `tv_sec` field of [`Timespec`]. |
33 | #[cfg (any( |
34 | fix_y2038, |
35 | linux_raw, |
36 | all(libc, target_arch = "x86_64" , target_pointer_width = "32" ) |
37 | ))] |
38 | pub type Nsecs = i64; |
39 | |
40 | /// A type for the `tv_nsec` field of [`Timespec`]. |
41 | #[cfg (all( |
42 | not(fix_y2038), |
43 | libc, |
44 | not(all(target_arch = "x86_64" , target_pointer_width = "32" )) |
45 | ))] |
46 | pub type Nsecs = c::c_long; |
47 | |
48 | /// On 32-bit glibc platforms, `timespec` has anonymous padding fields, which |
49 | /// Rust doesn't support yet (see `unnamed_fields`), so we define our own |
50 | /// struct with explicit padding, with bidirectional `From` impls. |
51 | #[cfg (fix_y2038)] |
52 | #[repr (C)] |
53 | #[derive (Debug, Clone)] |
54 | pub(crate) struct LibcTimespec { |
55 | pub(crate) tv_sec: Secs, |
56 | |
57 | #[cfg (target_endian = "big" )] |
58 | padding: core::mem::MaybeUninit<u32>, |
59 | |
60 | pub(crate) tv_nsec: i32, |
61 | |
62 | #[cfg (target_endian = "little" )] |
63 | padding: core::mem::MaybeUninit<u32>, |
64 | } |
65 | |
66 | #[cfg (fix_y2038)] |
67 | impl From<LibcTimespec> for Timespec { |
68 | #[inline ] |
69 | fn from(t: LibcTimespec) -> Self { |
70 | Self { |
71 | tv_sec: t.tv_sec, |
72 | tv_nsec: t.tv_nsec as _, |
73 | } |
74 | } |
75 | } |
76 | |
77 | #[cfg (fix_y2038)] |
78 | impl From<Timespec> for LibcTimespec { |
79 | #[inline ] |
80 | fn from(t: Timespec) -> Self { |
81 | Self { |
82 | tv_sec: t.tv_sec, |
83 | tv_nsec: t.tv_nsec as _, |
84 | padding: core::mem::MaybeUninit::uninit(), |
85 | } |
86 | } |
87 | } |
88 | |
89 | #[test ] |
90 | fn test_sizes() { |
91 | assert_eq_size!(Secs, u64); |
92 | const_assert!(core::mem::size_of::<Timespec>() >= core::mem::size_of::<(u64, u32)>()); |
93 | const_assert!(core::mem::size_of::<Nsecs>() >= 4); |
94 | |
95 | let mut t: __kernel_timespec = Timespec { |
96 | tv_sec: 0, |
97 | tv_nsec: 0, |
98 | }; |
99 | |
100 | // `tv_nsec` needs to be able to hold nanoseconds up to a second. |
101 | t.tv_nsec = 999_999_999_u32 as _; |
102 | assert_eq!(t.tv_nsec as u64, 999_999_999_u64); |
103 | |
104 | // `tv_sec` needs to be able to hold more than 32-bits of seconds. |
105 | t.tv_sec = 0x1_0000_0000_u64 as _; |
106 | assert_eq!(t.tv_sec as u64, 0x1_0000_0000_u64); |
107 | } |
108 | |
109 | // Test that our workarounds are needed. |
110 | #[cfg (fix_y2038)] |
111 | #[test ] |
112 | #[allow (deprecated)] |
113 | fn test_fix_y2038() { |
114 | assert_eq_size!(libc::time_t, u32); |
115 | } |
116 | |