Skip to content

Commit 89699b1

Browse files
Merge #1886
1886: Update use of libc::timespec to prepare for future libc version r=asomers a=wesleywiser 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`). See also rust-lang/libc#2088 Co-authored-by: Wesley Wiser <[email protected]>
2 parents 33a4d49 + 006fc6f commit 89699b1

File tree

1 file changed

+33
-35
lines changed

1 file changed

+33
-35
lines changed

src/sys/time.rs

+33-35
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
// The cast is not unnecessary on all platforms.
@@ -337,10 +335,10 @@ impl TimeSpec {
337335
/// Construct a new `TimeSpec` from its components
338336
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
339337
pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
340-
Self(timespec {
341-
tv_sec: seconds,
342-
tv_nsec: nanoseconds,
343-
})
338+
let mut ts = zero_init_timespec();
339+
ts.tv_sec = seconds;
340+
ts.tv_nsec = nanoseconds;
341+
Self(ts)
344342
}
345343

346344
fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
@@ -360,13 +358,13 @@ impl TimeSpec {
360358
self.0.tv_nsec
361359
}
362360

361+
#[cfg_attr(target_env = "musl", allow(deprecated))]
362+
// https://github.com/rust-lang/libc/issues/1848
363363
pub const fn from_duration(duration: Duration) -> Self {
364-
#[cfg_attr(target_env = "musl", allow(deprecated))]
365-
// https://github.com/rust-lang/libc/issues/1848
366-
TimeSpec(timespec {
367-
tv_sec: duration.as_secs() as time_t,
368-
tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t,
369-
})
364+
let mut ts = zero_init_timespec();
365+
ts.tv_sec = duration.as_secs() as time_t;
366+
ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
367+
TimeSpec(ts)
370368
}
371369

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

0 commit comments

Comments
 (0)