Skip to content

Commit fc7e421

Browse files
committed
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::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 a75a349 commit fc7e421

File tree

1 file changed

+35
-35
lines changed

1 file changed

+35
-35
lines changed

src/sys/time.rs

+35-35
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ 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::zeroed()` is not yet a const fn (https://github.com/rust-lang/rust/issues/62061)
11+
// so we will instead initialize an array of the appropriate size to zero and then
12+
// transmute it to a timespec value.
13+
unsafe {
14+
std::mem::transmute([0u8; std::mem::size_of::<timespec>()])
15+
}
16+
}
17+
918
#[cfg(any(
1019
all(feature = "time", any(target_os = "android", target_os = "linux")),
1120
all(
@@ -20,7 +29,7 @@ use std::{cmp, fmt, ops};
2029
)
2130
))]
2231
pub(crate) mod timer {
23-
use crate::sys::time::TimeSpec;
32+
use crate::sys::time::{TimeSpec, zero_init_timespec};
2433
use bitflags::bitflags;
2534

2635
#[derive(Debug, Clone, Copy)]
@@ -29,14 +38,8 @@ pub(crate) mod timer {
2938
impl TimerSpec {
3039
pub const fn none() -> Self {
3140
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-
},
41+
it_interval: zero_init_timespec(),
42+
it_value: zero_init_timespec(),
4043
})
4144
}
4245
}
@@ -57,10 +60,7 @@ pub(crate) mod timer {
5760
fn from(expiration: Expiration) -> TimerSpec {
5861
match expiration {
5962
Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
60-
it_interval: libc::timespec {
61-
tv_sec: 0,
62-
tv_nsec: 0,
63-
},
63+
it_interval: zero_init_timespec(),
6464
it_value: *t.as_ref(),
6565
}),
6666
Expiration::IntervalDelayed(start, interval) => {
@@ -118,6 +118,7 @@ pub(crate) mod timer {
118118
libc::timespec {
119119
tv_sec: 0,
120120
tv_nsec: 0,
121+
..
121122
},
122123
it_value: ts,
123124
}) => Expiration::OneShot(ts.into()),
@@ -257,18 +258,17 @@ impl PartialOrd for TimeSpec {
257258

258259
impl TimeValLike for TimeSpec {
259260
#[inline]
261+
#[cfg_attr(target_env = "musl", allow(deprecated))]
262+
// https://github.com/rust-lang/libc/issues/1848
260263
fn seconds(seconds: i64) -> TimeSpec {
261264
assert!(
262265
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
263266
"TimeSpec out of bounds; seconds={}",
264267
seconds
265268
);
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-
})
269+
let mut ts = zero_init_timespec();
270+
ts.tv_sec = seconds as time_t;
271+
TimeSpec(ts)
272272
}
273273

274274
#[inline]
@@ -292,18 +292,18 @@ impl TimeValLike for TimeSpec {
292292

293293
/// Makes a new `TimeSpec` with given number of nanoseconds.
294294
#[inline]
295+
#[cfg_attr(target_env = "musl", allow(deprecated))]
296+
// https://github.com/rust-lang/libc/issues/1848
295297
fn nanoseconds(nanoseconds: i64) -> TimeSpec {
296298
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
297299
assert!(
298300
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
299301
"TimeSpec out of bounds"
300302
);
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-
})
303+
let mut ts = zero_init_timespec();
304+
ts.tv_sec = secs as time_t;
305+
ts.tv_nsec = nanos as timespec_tv_nsec_t;
306+
TimeSpec(ts)
307307
}
308308

309309
// The cast is not unnecessary on all platforms.
@@ -337,10 +337,10 @@ impl TimeSpec {
337337
/// Construct a new `TimeSpec` from its components
338338
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
339339
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-
})
340+
let mut ts = zero_init_timespec();
341+
ts.tv_sec = seconds;
342+
ts.tv_nsec = nanoseconds;
343+
Self(ts)
344344
}
345345

346346
fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
@@ -360,13 +360,13 @@ impl TimeSpec {
360360
self.0.tv_nsec
361361
}
362362

363+
#[cfg_attr(target_env = "musl", allow(deprecated))]
364+
// https://github.com/rust-lang/libc/issues/1848
363365
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-
})
366+
let mut ts = zero_init_timespec();
367+
ts.tv_sec = duration.as_secs() as time_t;
368+
ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
369+
TimeSpec(ts)
370370
}
371371

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

0 commit comments

Comments
 (0)