From 5d17ae85146283e4ab49f4e4458c8c7a0dee2b72 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 15 Jun 2024 18:08:09 +0200 Subject: [PATCH 1/2] std.posix: remove unchecked std.os.linux usage Using std.os.linux directly in e.g. std.posix.timerfd_create() causes the function to compile but silently fail at runtime when targeting any OS other than Linux. To catch errors like this at compile time, std.os.linux must only be directly accessed within std.posix where there has been a comptime check that the target os is in fact Linux. --- lib/std/c/linux.zig | 15 +++++++++++++++ lib/std/posix.zig | 26 +++++++++++++------------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig index 1a3c63451502..436f42de3b00 100644 --- a/lib/std/c/linux.zig +++ b/lib/std/c/linux.zig @@ -52,6 +52,7 @@ pub const T = linux.T; pub const TCP = linux.TCP; pub const TCSA = linux.TCSA; pub const VDSO = linux.VDSO; +pub const TFD = linux.TFD; pub const W = linux.W; pub const W_OK = linux.W_OK; pub const X_OK = linux.X_OK; @@ -68,6 +69,7 @@ pub const fd_t = linux.fd_t; pub const gid_t = linux.gid_t; pub const ifreq = linux.ifreq; pub const ino_t = linux.ino_t; +pub const itimerspec = linux.itimerspec; pub const mcontext_t = linux.mcontext_t; pub const mode_t = linux.mode_t; pub const msghdr = linux.msghdr; @@ -75,6 +77,7 @@ pub const msghdr_const = linux.msghdr_const; pub const nfds_t = linux.nfds_t; pub const nlink_t = linux.nlink_t; pub const off_t = linux.off_t; +pub const perf_event_attr = linux.perf_event_attr; pub const pid_t = linux.pid_t; pub const pollfd = linux.pollfd; pub const rlim_t = linux.rlim_t; @@ -344,3 +347,15 @@ pub const dirent64 = struct { type: u8, name: [256]u8, }; + +// Neither glibc nor musl provide a wrapper function for this syscall +pub const perf_event_open = linux.perf_event_open; + +pub extern "c" fn timerfd_create(clockid: c_int, flags: c_int) c_int; +pub extern "c" fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const itimerspec, + old_value: ?*itimerspec, +) c_int; +pub extern "c" fn timerfd_gettime(fd: c_int, curr_value: *itimerspec) c_int; diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 167c945abf87..2d3ba85134d1 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -3968,7 +3968,7 @@ pub const EpollCtlError = error{ FileDescriptorIncompatibleWithEpoll, } || UnexpectedError; -pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: ?*linux.epoll_event) EpollCtlError!void { +pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: ?*system.epoll_event) EpollCtlError!void { const rc = system.epoll_ctl(epfd, op, fd, event); switch (errno(rc)) { .SUCCESS => return, @@ -3988,7 +3988,7 @@ pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: ?*linux.epoll_event) EpollC /// Waits for an I/O event on an epoll file descriptor. /// Returns the number of file descriptors ready for the requested I/O, /// or zero if no file descriptor became ready during the requested timeout milliseconds. -pub fn epoll_wait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize { +pub fn epoll_wait(epfd: i32, events: []system.epoll_event, timeout: i32) usize { while (true) { // TODO get rid of the @intCast const rc = system.epoll_wait(epfd, events.ptr, @intCast(events.len), timeout); @@ -7142,13 +7142,13 @@ pub const PerfEventOpenError = error{ } || UnexpectedError; pub fn perf_event_open( - attr: *linux.perf_event_attr, + attr: *system.perf_event_attr, pid: pid_t, cpu: i32, group_fd: fd_t, flags: usize, ) PerfEventOpenError!fd_t { - const rc = linux.perf_event_open(attr, pid, cpu, group_fd, flags); + const rc = system.perf_event_open(attr, pid, cpu, group_fd, flags); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .@"2BIG" => return error.TooBig, @@ -7182,8 +7182,8 @@ pub const TimerFdCreateError = error{ pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError; pub const TimerFdSetError = TimerFdGetError || error{Canceled}; -pub fn timerfd_create(clokid: i32, flags: linux.TFD) TimerFdCreateError!fd_t { - const rc = linux.timerfd_create(clokid, flags); +pub fn timerfd_create(clokid: i32, flags: system.TFD) TimerFdCreateError!fd_t { + const rc = system.timerfd_create(clokid, @bitCast(flags)); return switch (errno(rc)) { .SUCCESS => @intCast(rc), .INVAL => unreachable, @@ -7198,11 +7198,11 @@ pub fn timerfd_create(clokid: i32, flags: linux.TFD) TimerFdCreateError!fd_t { pub fn timerfd_settime( fd: i32, - flags: linux.TFD.TIMER, - new_value: *const linux.itimerspec, - old_value: ?*linux.itimerspec, + flags: system.TFD.TIMER, + new_value: *const system.itimerspec, + old_value: ?*system.itimerspec, ) TimerFdSetError!void { - const rc = linux.timerfd_settime(fd, flags, new_value, old_value); + const rc = system.timerfd_settime(fd, @bitCast(flags), new_value, old_value); return switch (errno(rc)) { .SUCCESS => {}, .BADF => error.InvalidHandle, @@ -7213,9 +7213,9 @@ pub fn timerfd_settime( }; } -pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec { - var curr_value: linux.itimerspec = undefined; - const rc = linux.timerfd_gettime(fd, &curr_value); +pub fn timerfd_gettime(fd: i32) TimerFdGetError!system.itimerspec { + var curr_value: system.itimerspec = undefined; + const rc = system.timerfd_gettime(fd, &curr_value); return switch (errno(rc)) { .SUCCESS => return curr_value, .BADF => error.InvalidHandle, From 40e1a83286db668e28cf4ab190ffd173b7bd0989 Mon Sep 17 00:00:00 2001 From: Jan Hendrik Farr Date: Sun, 16 Jun 2024 00:34:12 +0200 Subject: [PATCH 2/2] freebsd: add timerfd_create, timerfd_settime, and timerfd_gettime --- lib/std/c/freebsd.zig | 32 ++++++++++++++++++++++++++++++++ lib/std/posix.zig | 12 ++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index a60f5de525ee..7ab1041ba3db 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -352,6 +352,38 @@ pub const Stat = extern struct { } }; +pub extern "c" fn timerfd_create(clockid: c_int, flags: c_int) c_int; + +pub extern "c" fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const itimerspec, + old_value: ?*itimerspec, +) c_int; + +pub extern "c" fn timerfd_gettime(fd: c_int, curr_value: *itimerspec) c_int; + +const TFD_TIMER = packed struct(u32) { + ABSTIME: bool = false, + CANCEL_ON_SET: bool = false, + _: u30 = 0, +}; + +pub const TFD = packed struct(u32) { + _0: u2 = 0, + NONBLOCK: bool = false, + _3: u17 = 0, + CLOEXEC: bool = false, + _: u11 = 0, + + pub const TIMER = TFD_TIMER; +}; + +pub const itimerspec = extern struct { + it_interval: timespec, + it_value: timespec, +}; + pub const timespec = extern struct { tv_sec: isize, tv_nsec: isize, diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 2d3ba85134d1..1b463f19f395 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -7171,6 +7171,8 @@ pub fn perf_event_open( } } +pub const TFD = system.TFD; + pub const TimerFdCreateError = error{ AccessDenied, ProcessFdQuotaExceeded, @@ -7196,11 +7198,13 @@ pub fn timerfd_create(clokid: i32, flags: system.TFD) TimerFdCreateError!fd_t { }; } +pub const itimerspec = system.itimerspec; + pub fn timerfd_settime( fd: i32, flags: system.TFD.TIMER, - new_value: *const system.itimerspec, - old_value: ?*system.itimerspec, + new_value: *const itimerspec, + old_value: ?*itimerspec, ) TimerFdSetError!void { const rc = system.timerfd_settime(fd, @bitCast(flags), new_value, old_value); return switch (errno(rc)) { @@ -7213,8 +7217,8 @@ pub fn timerfd_settime( }; } -pub fn timerfd_gettime(fd: i32) TimerFdGetError!system.itimerspec { - var curr_value: system.itimerspec = undefined; +pub fn timerfd_gettime(fd: i32) TimerFdGetError!itimerspec { + var curr_value: itimerspec = undefined; const rc = system.timerfd_gettime(fd, &curr_value); return switch (errno(rc)) { .SUCCESS => return curr_value,