Skip to content

Commit 46479c1

Browse files
wesleywiserrtzoeller
authored andcommitted
Update use of libc::timespec to prepare for future libc version
In a future release of the `libc` crate, `libc::timespec` will contain private padding fields on `*-linux-musl` targets and so the struct will no longer be able to be created using the literal initialization syntax. Update places where `libc::timespec` is created to first zero initialize the value and then update the `tv_sec` and `tv_nsec` fields manually. Many of these places are in `const fn`s so a helper function `zero_init_timespec()` is introduced to help with this as `std::mem::MaybeUninit::zeroed()` is not a `const` function. Some matches on `libc::timespec` are also updated to include a trailing `..` pattern which works when `libc::timespec` has additional, private fields as well as when it does not (like for `x86_64-unknown-linux-gnu`).
1 parent 1b1342b commit 46479c1

File tree

1 file changed

+33
-35
lines changed

1 file changed

+33
-35
lines changed

src/sys/time.rs

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ use std::convert::From;
66
use std::time::Duration;
77
use std::{cmp, fmt, ops};
88

9+
const fn zero_init_timespec() -> timespec {
10+
// `std::mem::MaybeUninit::zeroed()` is not yet a const fn
11+
// (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of
12+
// the appropriate size to zero and then transmute it to a timespec value.
13+
unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) }
14+
}
15+
916
#[cfg(any(
1017
all(feature = "time", any(target_os = "android", target_os = "linux")),
1118
all(
@@ -20,7 +27,7 @@ use std::{cmp, fmt, ops};
2027
)
2128
))]
2229
pub(crate) mod timer {
23-
use crate::sys::time::TimeSpec;
30+
use crate::sys::time::{zero_init_timespec, TimeSpec};
2431
use bitflags::bitflags;
2532

2633
#[derive(Debug, Clone, Copy)]
@@ -29,14 +36,8 @@ pub(crate) mod timer {
2936
impl TimerSpec {
3037
pub const fn none() -> Self {
3138
Self(libc::itimerspec {
32-
it_interval: libc::timespec {
33-
tv_sec: 0,
34-
tv_nsec: 0,
35-
},
36-
it_value: libc::timespec {
37-
tv_sec: 0,
38-
tv_nsec: 0,
39-
},
39+
it_interval: zero_init_timespec(),
40+
it_value: zero_init_timespec(),
4041
})
4142
}
4243
}
@@ -57,10 +58,7 @@ pub(crate) mod timer {
5758
fn from(expiration: Expiration) -> TimerSpec {
5859
match expiration {
5960
Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
60-
it_interval: libc::timespec {
61-
tv_sec: 0,
62-
tv_nsec: 0,
63-
},
61+
it_interval: zero_init_timespec(),
6462
it_value: *t.as_ref(),
6563
}),
6664
Expiration::IntervalDelayed(start, interval) => {
@@ -118,6 +116,7 @@ pub(crate) mod timer {
118116
libc::timespec {
119117
tv_sec: 0,
120118
tv_nsec: 0,
119+
..
121120
},
122121
it_value: ts,
123122
}) => Expiration::OneShot(ts.into()),
@@ -257,18 +256,17 @@ impl PartialOrd for TimeSpec {
257256

258257
impl TimeValLike for TimeSpec {
259258
#[inline]
259+
#[cfg_attr(target_env = "musl", allow(deprecated))]
260+
// https://github.com/rust-lang/libc/issues/1848
260261
fn seconds(seconds: i64) -> TimeSpec {
261262
assert!(
262263
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
263264
"TimeSpec out of bounds; seconds={}",
264265
seconds
265266
);
266-
#[cfg_attr(target_env = "musl", allow(deprecated))]
267-
// https://github.com/rust-lang/libc/issues/1848
268-
TimeSpec(timespec {
269-
tv_sec: seconds as time_t,
270-
tv_nsec: 0,
271-
})
267+
let mut ts = zero_init_timespec();
268+
ts.tv_sec = seconds as time_t;
269+
TimeSpec(ts)
272270
}
273271

274272
#[inline]
@@ -292,18 +290,18 @@ impl TimeValLike for TimeSpec {
292290

293291
/// Makes a new `TimeSpec` with given number of nanoseconds.
294292
#[inline]
293+
#[cfg_attr(target_env = "musl", allow(deprecated))]
294+
// https://github.com/rust-lang/libc/issues/1848
295295
fn nanoseconds(nanoseconds: i64) -> TimeSpec {
296296
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
297297
assert!(
298298
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
299299
"TimeSpec out of bounds"
300300
);
301-
#[cfg_attr(target_env = "musl", allow(deprecated))]
302-
// https://github.com/rust-lang/libc/issues/1848
303-
TimeSpec(timespec {
304-
tv_sec: secs as time_t,
305-
tv_nsec: nanos as timespec_tv_nsec_t,
306-
})
301+
let mut ts = zero_init_timespec();
302+
ts.tv_sec = secs as time_t;
303+
ts.tv_nsec = nanos as timespec_tv_nsec_t;
304+
TimeSpec(ts)
307305
}
308306

309307
fn num_seconds(&self) -> i64 {
@@ -333,10 +331,10 @@ impl TimeSpec {
333331
/// Construct a new `TimeSpec` from its components
334332
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
335333
pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
336-
Self(timespec {
337-
tv_sec: seconds,
338-
tv_nsec: nanoseconds,
339-
})
334+
let mut ts = zero_init_timespec();
335+
ts.tv_sec = seconds;
336+
ts.tv_nsec = nanoseconds;
337+
Self(ts)
340338
}
341339

342340
fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
@@ -356,13 +354,13 @@ impl TimeSpec {
356354
self.0.tv_nsec
357355
}
358356

357+
#[cfg_attr(target_env = "musl", allow(deprecated))]
358+
// https://github.com/rust-lang/libc/issues/1848
359359
pub const fn from_duration(duration: Duration) -> Self {
360-
#[cfg_attr(target_env = "musl", allow(deprecated))]
361-
// https://github.com/rust-lang/libc/issues/1848
362-
TimeSpec(timespec {
363-
tv_sec: duration.as_secs() as time_t,
364-
tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t,
365-
})
360+
let mut ts = zero_init_timespec();
361+
ts.tv_sec = duration.as_secs() as time_t;
362+
ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
363+
TimeSpec(ts)
366364
}
367365

368366
pub const fn from_timespec(timespec: timespec) -> Self {

0 commit comments

Comments
 (0)