Skip to content

Commit b53e0b2

Browse files
authored
Support the timerfd API on FreeBSD. (#978)
* Support the timerfd API on FreeBSD. FreeBSD has recently added support for Linux's timerfd API. Enable rustix's timerfd API on FreeBSD as well. * Support FreeBSD < 14. * NetBSD and illumos support. * Work around an illumos oddity in the timerfd test. * Don't fail the timerfd tests on FreeBSD versions that lack timerfd. * NetBSD and illumos bits are now an upstream libc PR.
1 parent a8c68d2 commit b53e0b2

File tree

9 files changed

+267
-36
lines changed

9 files changed

+267
-36
lines changed

src/backend/libc/c.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,60 @@ pub(crate) use __fsid_t as fsid_t;
519519
#[cfg(target_os = "android")]
520520
pub(crate) const MAP_DROPPABLE: c_int = bitcast!(linux_raw_sys::general::MAP_DROPPABLE);
521521

522+
// FreeBSD added `timerfd_*` in FreeBSD 14. NetBSD added then in NetBSD 10.
523+
#[cfg(all(feature = "time", any(target_os = "freebsd", target_os = "netbsd")))]
524+
syscall!(pub(crate) fn timerfd_create(
525+
clockid: c_int,
526+
flags: c_int
527+
) via SYS_timerfd_create -> c_int);
528+
#[cfg(all(feature = "time", any(target_os = "freebsd", target_os = "netbsd")))]
529+
syscall!(pub(crate) fn timerfd_gettime(
530+
fd: c_int,
531+
curr_value: *mut itimerspec
532+
) via SYS_timerfd_gettime -> c_int);
533+
#[cfg(all(feature = "time", any(target_os = "freebsd", target_os = "netbsd")))]
534+
syscall!(pub(crate) fn timerfd_settime(
535+
fd: c_int,
536+
flags: c_int,
537+
new_value: *const itimerspec,
538+
old_value: *mut itimerspec
539+
) via SYS_timerfd_settime -> c_int);
540+
541+
#[cfg(all(feature = "time", target_os = "illumos"))]
542+
extern "C" {
543+
pub(crate) fn timerfd_create(clockid: c_int, flags: c_int) -> c_int;
544+
pub(crate) fn timerfd_gettime(fd: c_int, curr_value: *mut itimerspec) -> c_int;
545+
pub(crate) fn timerfd_settime(
546+
fd: c_int,
547+
flags: c_int,
548+
new_value: *const itimerspec,
549+
old_value: *mut itimerspec,
550+
) -> c_int;
551+
}
552+
553+
// illumos and NetBSD timerfd support.
554+
// Submitted upstream in <https://github.com/rust-lang/libc/pull/4333>.
555+
556+
// <https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/uts/common/sys/timerfd.h#34>
557+
#[cfg(all(feature = "time", target_os = "illumos"))]
558+
pub(crate) const TFD_CLOEXEC: i32 = 0o2000000;
559+
#[cfg(all(feature = "time", target_os = "illumos"))]
560+
pub(crate) const TFD_NONBLOCK: i32 = 0o4000;
561+
#[cfg(all(feature = "time", target_os = "illumos"))]
562+
pub(crate) const TFD_TIMER_ABSTIME: i32 = 1 << 0;
563+
#[cfg(all(feature = "time", target_os = "illumos"))]
564+
pub(crate) const TFD_TIMER_CANCEL_ON_SET: i32 = 1 << 1;
565+
566+
// <https://nxr.netbsd.org/xref/src/sys/sys/timerfd.h#44>
567+
#[cfg(all(feature = "time", target_os = "netbsd"))]
568+
pub(crate) const TFD_CLOEXEC: i32 = O_CLOEXEC;
569+
#[cfg(all(feature = "time", target_os = "netbsd"))]
570+
pub(crate) const TFD_NONBLOCK: i32 = O_NONBLOCK;
571+
#[cfg(all(feature = "time", target_os = "netbsd"))]
572+
pub(crate) const TFD_TIMER_ABSTIME: i32 = O_WRONLY;
573+
#[cfg(all(feature = "time", target_os = "netbsd"))]
574+
pub(crate) const TFD_TIMER_CANCEL_ON_SET: i32 = O_RDWR;
575+
522576
#[cfg(test)]
523577
mod tests {
524578
use super::*;

src/backend/libc/time/syscalls.rs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
33
use crate::backend::c;
44
use crate::backend::conv::ret;
5-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
5+
#[cfg(any(
6+
linux_kernel,
7+
target_os = "freebsd",
8+
target_os = "fuchsia",
9+
target_os = "illumos",
10+
target_os = "netbsd"
11+
))]
612
#[cfg(any(all(target_env = "gnu", fix_y2038), not(fix_y2038)))]
713
use crate::backend::time::types::LibcItimerspec;
814
#[cfg(not(target_os = "wasi"))]
@@ -21,7 +27,13 @@ use crate::timespec::as_libc_timespec_ptr;
2127
use crate::timespec::LibcTimespec;
2228
use crate::timespec::Timespec;
2329
use core::mem::MaybeUninit;
24-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
30+
#[cfg(any(
31+
linux_kernel,
32+
target_os = "freebsd",
33+
target_os = "fuchsia",
34+
target_os = "illumos",
35+
target_os = "netbsd"
36+
))]
2537
use {
2638
crate::backend::conv::{borrowed_fd, ret_owned_fd},
2739
crate::fd::{BorrowedFd, OwnedFd},
@@ -34,10 +46,10 @@ weak!(fn __clock_gettime64(c::clockid_t, *mut LibcTimespec) -> c::c_int);
3446
weak!(fn __clock_settime64(c::clockid_t, *const LibcTimespec) -> c::c_int);
3547
#[cfg(all(target_env = "gnu", fix_y2038))]
3648
weak!(fn __clock_getres64(c::clockid_t, *mut LibcTimespec) -> c::c_int);
37-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
49+
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
3850
#[cfg(all(target_env = "gnu", fix_y2038))]
3951
weak!(fn __timerfd_gettime64(c::c_int, *mut LibcItimerspec) -> c::c_int);
40-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
52+
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
4153
#[cfg(all(target_env = "gnu", fix_y2038))]
4254
weak!(fn __timerfd_settime64(c::c_int, c::c_int, *const LibcItimerspec, *mut LibcItimerspec) -> c::c_int);
4355

@@ -172,7 +184,7 @@ pub(crate) fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timesp
172184
return Err(io::Errno::INVAL);
173185
}
174186

175-
#[cfg(linux_kernel)]
187+
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
176188
DynamicClockId::RealtimeAlarm => c::CLOCK_REALTIME_ALARM,
177189

178190
#[cfg(linux_kernel)]
@@ -298,12 +310,24 @@ fn clock_settime_old(id: ClockId, timespec: Timespec) -> io::Result<()> {
298310
unsafe { ret(c::clock_settime(id as c::clockid_t, &old_timespec)) }
299311
}
300312

301-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
313+
#[cfg(any(
314+
linux_kernel,
315+
target_os = "freebsd",
316+
target_os = "fuchsia",
317+
target_os = "illumos",
318+
target_os = "netbsd"
319+
))]
302320
pub(crate) fn timerfd_create(id: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> {
303321
unsafe { ret_owned_fd(c::timerfd_create(id as c::clockid_t, bitflags_bits!(flags))) }
304322
}
305323

306-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
324+
#[cfg(any(
325+
linux_kernel,
326+
target_os = "freebsd",
327+
target_os = "fuchsia",
328+
target_os = "illumos",
329+
target_os = "netbsd"
330+
))]
307331
pub(crate) fn timerfd_settime(
308332
fd: BorrowedFd<'_>,
309333
flags: TimerfdTimerFlags,
@@ -345,7 +369,13 @@ pub(crate) fn timerfd_settime(
345369
}
346370
}
347371

348-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
372+
#[cfg(any(
373+
linux_kernel,
374+
target_os = "freebsd",
375+
target_os = "fuchsia",
376+
target_os = "illumos",
377+
target_os = "netbsd"
378+
))]
349379
#[cfg(fix_y2038)]
350380
fn timerfd_settime_old(
351381
fd: BorrowedFd<'_>,
@@ -412,7 +442,13 @@ fn timerfd_settime_old(
412442
})
413443
}
414444

415-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
445+
#[cfg(any(
446+
linux_kernel,
447+
target_os = "freebsd",
448+
target_os = "fuchsia",
449+
target_os = "illumos",
450+
target_os = "netbsd"
451+
))]
416452
pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
417453
// Old 32-bit version: libc has `timerfd_gettime` but it is not y2038 safe
418454
// by default. But there may be a `__timerfd_gettime64` we can use.
@@ -443,7 +479,13 @@ pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
443479
}
444480
}
445481

446-
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
482+
#[cfg(any(
483+
linux_kernel,
484+
target_os = "freebsd",
485+
target_os = "fuchsia",
486+
target_os = "illumos",
487+
target_os = "netbsd"
488+
))]
447489
#[cfg(fix_y2038)]
448490
fn timerfd_gettime_old(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
449491
let mut old_result = MaybeUninit::<c::itimerspec>::uninit();

0 commit comments

Comments
 (0)