Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update use of libc::timespec to prepare for future libc version #1886

Merged
merged 1 commit into from
Nov 28, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 33 additions & 35 deletions src/sys/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ use std::convert::From;
use std::time::Duration;
use std::{cmp, fmt, ops};

const fn zero_init_timespec() -> timespec {
// `std::mem::MaybeUninit::zeroed()` is not yet a const fn
// (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of
// the appropriate size to zero and then transmute it to a timespec value.
unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) }
}

#[cfg(any(
all(feature = "time", any(target_os = "android", target_os = "linux")),
all(
Expand All @@ -20,7 +27,7 @@ use std::{cmp, fmt, ops};
)
))]
pub(crate) mod timer {
use crate::sys::time::TimeSpec;
use crate::sys::time::{zero_init_timespec, TimeSpec};
use bitflags::bitflags;

#[derive(Debug, Clone, Copy)]
Expand All @@ -29,14 +36,8 @@ pub(crate) mod timer {
impl TimerSpec {
pub const fn none() -> Self {
Self(libc::itimerspec {
it_interval: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
it_value: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
it_interval: zero_init_timespec(),
it_value: zero_init_timespec(),
})
}
}
Expand All @@ -57,10 +58,7 @@ pub(crate) mod timer {
fn from(expiration: Expiration) -> TimerSpec {
match expiration {
Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
it_interval: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
it_interval: zero_init_timespec(),
it_value: *t.as_ref(),
}),
Expiration::IntervalDelayed(start, interval) => {
Expand Down Expand Up @@ -118,6 +116,7 @@ pub(crate) mod timer {
libc::timespec {
tv_sec: 0,
tv_nsec: 0,
..
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the function of this line? Are you programming defensively, just in case freebsd, netbsd, dragonfly, or illumos grow some padding fields too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's required once Rust starts targeting musl 1.2 as i686-unknown-linux-musl will have a padding field:

$ cargo +e392e7b50913d5cb6e2c08d70cdeb72e56d289f9 build --target i686-unknown-linux-musl
   Compiling libc v0.2.137 (https://github.com/wesleywiser/libc?branch=musl-1.2#3049e59a)
   Compiling nix v0.25.0 (/tmp/nix)
error: pattern requires `..` due to inaccessible fields
   --> src/sys/time.rs:116:25
    |
116 | /                         libc::timespec {
117 | |                             tv_sec: 0,
118 | |                             tv_nsec: 0,
119 | |                         },
    | |_________________________^
    |
help: ignore the inaccessible and unused fields
    |
118 |                             tv_nsec: 0, ..,
    |                                       ++++

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, my bad. I saw that #[cfg()] block on line 100 and thought that it applied here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, thanks for the quick reviews! 🙂

},
it_value: ts,
}) => Expiration::OneShot(ts.into()),
Expand Down Expand Up @@ -257,18 +256,17 @@ impl PartialOrd for TimeSpec {

impl TimeValLike for TimeSpec {
#[inline]
#[cfg_attr(target_env = "musl", allow(deprecated))]
// https://github.com/rust-lang/libc/issues/1848
fn seconds(seconds: i64) -> TimeSpec {
assert!(
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
"TimeSpec out of bounds; seconds={}",
seconds
);
#[cfg_attr(target_env = "musl", allow(deprecated))]
// https://github.com/rust-lang/libc/issues/1848
TimeSpec(timespec {
tv_sec: seconds as time_t,
tv_nsec: 0,
})
let mut ts = zero_init_timespec();
ts.tv_sec = seconds as time_t;
TimeSpec(ts)
}

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

/// Makes a new `TimeSpec` with given number of nanoseconds.
#[inline]
#[cfg_attr(target_env = "musl", allow(deprecated))]
// https://github.com/rust-lang/libc/issues/1848
fn nanoseconds(nanoseconds: i64) -> TimeSpec {
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
assert!(
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
"TimeSpec out of bounds"
);
#[cfg_attr(target_env = "musl", allow(deprecated))]
// https://github.com/rust-lang/libc/issues/1848
TimeSpec(timespec {
tv_sec: secs as time_t,
tv_nsec: nanos as timespec_tv_nsec_t,
})
let mut ts = zero_init_timespec();
ts.tv_sec = secs as time_t;
ts.tv_nsec = nanos as timespec_tv_nsec_t;
TimeSpec(ts)
}

// The cast is not unnecessary on all platforms.
Expand Down Expand Up @@ -337,10 +335,10 @@ impl TimeSpec {
/// Construct a new `TimeSpec` from its components
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
Self(timespec {
tv_sec: seconds,
tv_nsec: nanoseconds,
})
let mut ts = zero_init_timespec();
ts.tv_sec = seconds;
ts.tv_nsec = nanoseconds;
Self(ts)
}

fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
Expand All @@ -360,13 +358,13 @@ impl TimeSpec {
self.0.tv_nsec
}

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

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