authorgravatar for dev@sgregoratto.meStephen Gregoratto <dev@sgregoratto.me> 2025-08-07 18:00:26+10:00
committergravatar for dev@sgregoratto.meStephen Gregoratto <dev@sgregoratto.me> 2025-08-14 10:24:57+10:00
log6080f2d5eaf4eee89fe86b5dc014d50f609df466
tree693076a18b77c3ddc7c75187e0dd1d5c45a8c72c
parent6f60c8eca786e67d9a6dfb75de9e6c8f10d0f189

Linux: Use time64 syscalls when available

Newer 32-bit Linux targets like 32-bit RISC-V only use the 64-bit time ABI, with these syscalls having `time64` as their suffix. This is a stopgap solution in favor of a full audit of `std.os.linux` to prepare for #4726. See also #21440 for prior art.

1 files changed, 76 insertions(+), 25 deletions(-)

lib/std/os/linux.zig+76-25
......@@ -644,7 +644,13 @@ pub fn futimens(fd: i32, times: ?*const [2]timespec) usize {
644644}
645645
646646pub fn utimensat(dirfd: i32, path: ?[*:0]const u8, times: ?*const [2]timespec, flags: u32) usize {
647 return syscall4(.utimensat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(times), flags);
647 return syscall4(
648 if (@hasField(SYS, "utimensat")) .utimensat else .utimensat_time64,
649 @as(usize, @bitCast(@as(isize, dirfd))),
650 @intFromPtr(path),
651 @intFromPtr(times),
652 flags,
653 );
648654}
649655
650656pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize {
......@@ -686,19 +692,38 @@ pub const futex_param4 = extern union {
686692/// The futex_op parameter is a sub-command and flags. The sub-command
687693/// defines which of the subsequent paramters are relevant.
688694pub fn futex(uaddr: *const anyopaque, futex_op: FUTEX_OP, val: u32, val2timeout: futex_param4, uaddr2: ?*const anyopaque, val3: u32) usize {
689 return syscall6(.futex, @intFromPtr(uaddr), @as(u32, @bitCast(futex_op)), val, @intFromPtr(val2timeout.timeout), @intFromPtr(uaddr2), val3);
695 return syscall6(
696 if (@hasField(SYS, "futex")) .futex else .futex_time64,
697 @intFromPtr(uaddr),
698 @as(u32, @bitCast(futex_op)),
699 val,
700 @intFromPtr(val2timeout.timeout),
701 @intFromPtr(uaddr2),
702 val3,
703 );
690704}
691705
692706/// Three-argument variation of the v1 futex call. Only suitable for a
693707/// futex_op that ignores the remaining arguments (e.g., FUTUX_OP.WAKE).
694708pub fn futex_3arg(uaddr: *const anyopaque, futex_op: FUTEX_OP, val: u32) usize {
695 return syscall3(.futex, @intFromPtr(uaddr), @as(u32, @bitCast(futex_op)), val);
709 return syscall3(
710 if (@hasField(SYS, "futex")) .futex else .futex_time64,
711 @intFromPtr(uaddr),
712 @as(u32, @bitCast(futex_op)),
713 val,
714 );
696715}
697716
698717/// Four-argument variation on the v1 futex call. Only suitable for
699718/// futex_op that ignores the remaining arguments (e.g., FUTEX_OP.WAIT).
700719pub fn futex_4arg(uaddr: *const anyopaque, futex_op: FUTEX_OP, val: u32, timeout: ?*const timespec) usize {
701 return syscall4(.futex, @intFromPtr(uaddr), @as(u32, @bitCast(futex_op)), val, @intFromPtr(timeout));
720 return syscall4(
721 if (@hasField(SYS, "futex")) .futex else .futex_time64,
722 @intFromPtr(uaddr),
723 @as(u32, @bitCast(futex_op)),
724 val,
725 @intFromPtr(timeout),
726 );
702727}
703728
704729/// Given an array of `futex2_waitone`, wait on each uaddr.
......@@ -1054,28 +1079,32 @@ pub fn munlockall() usize {
10541079}
10551080
10561081pub fn poll(fds: [*]pollfd, n: nfds_t, timeout: i32) usize {
1057 if (@hasField(SYS, "poll")) {
1058 return syscall3(.poll, @intFromPtr(fds), n, @as(u32, @bitCast(timeout)));
1059 } else {
1060 return syscall5(
1061 .ppoll,
1062 @intFromPtr(fds),
1082 return if (@hasField(SYS, "poll"))
1083 return syscall3(.poll, @intFromPtr(fds), n, @as(u32, @bitCast(timeout)))
1084 else
1085 ppoll(
1086 fds,
10631087 n,
1064 @intFromPtr(if (timeout >= 0)
1065 &timespec{
1088 if (timeout >= 0)
1089 @constCast(&timespec{
10661090 .sec = @divTrunc(timeout, 1000),
10671091 .nsec = @rem(timeout, 1000) * 1000000,
1068 }
1092 })
10691093 else
1070 null),
1071 0,
1072 NSIG / 8,
1094 null,
1095 null,
10731096 );
1074 }
10751097}
10761098
10771099pub fn ppoll(fds: [*]pollfd, n: nfds_t, timeout: ?*timespec, sigmask: ?*const sigset_t) usize {
1078 return syscall5(.ppoll, @intFromPtr(fds), n, @intFromPtr(timeout), @intFromPtr(sigmask), NSIG / 8);
1100 return syscall5(
1101 if (@hasField(SYS, "ppoll")) .ppoll else .ppoll_time64,
1102 @intFromPtr(fds),
1103 n,
1104 @intFromPtr(timeout),
1105 @intFromPtr(sigmask),
1106 NSIG / 8,
1107 );
10791108}
10801109
10811110pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
......@@ -1599,7 +1628,11 @@ pub fn clock_gettime(clk_id: clockid_t, tp: *timespec) usize {
15991628 }
16001629 }
16011630 }
1602 return syscall2(.clock_gettime, @intFromEnum(clk_id), @intFromPtr(tp));
1631 return syscall2(
1632 if (@hasField(SYS, "clock_gettime")) .clock_gettime else .clock_gettime64,
1633 @intFromEnum(clk_id),
1634 @intFromPtr(tp),
1635 );
16031636}
16041637
16051638fn init_vdso_clock_gettime(clk: clockid_t, ts: *timespec) callconv(.c) usize {
......@@ -1613,16 +1646,24 @@ fn init_vdso_clock_gettime(clk: clockid_t, ts: *timespec) callconv(.c) usize {
16131646}
16141647
16151648pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
1616 return syscall2(.clock_getres, @as(usize, @bitCast(@as(isize, clk_id))), @intFromPtr(tp));
1649 return syscall2(
1650 if (@hasField(SYS, "clock_getres")) .clock_getres else .clock_getres_time64,
1651 @as(usize, @bitCast(@as(isize, clk_id))),
1652 @intFromPtr(tp),
1653 );
16171654}
16181655
16191656pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
1620 return syscall2(.clock_settime, @as(usize, @bitCast(@as(isize, clk_id))), @intFromPtr(tp));
1657 return syscall2(
1658 if (@hasField(SYS, "clock_settime")) .clock_settime else .clock_settime64,
1659 @as(usize, @bitCast(@as(isize, clk_id))),
1660 @intFromPtr(tp),
1661 );
16211662}
16221663
16231664pub fn clock_nanosleep(clockid: clockid_t, flags: TIMER, request: *const timespec, remain: ?*timespec) usize {
16241665 return syscall4(
1625 .clock_nanosleep,
1666 if (@hasField(SYS, "clock_nanosleep")) .clock_nanosleep else .clock_nanosleep_time64,
16261667 @intFromEnum(clockid),
16271668 @as(u32, @bitCast(flags)),
16281669 @intFromPtr(request),
......@@ -2021,7 +2062,7 @@ pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
20212062
20222063pub fn recvmmsg(fd: i32, msgvec: ?[*]mmsghdr, vlen: u32, flags: u32, timeout: ?*timespec) usize {
20232064 return syscall5(
2024 .recvmmsg,
2065 if (@hasField(SYS, "recvmmsg")) .recvmmsg else .recvmmsg_time64,
20252066 @as(usize, @bitCast(@as(isize, fd))),
20262067 @intFromPtr(msgvec),
20272068 vlen,
......@@ -2370,11 +2411,21 @@ pub const itimerspec = extern struct {
23702411};
23712412
23722413pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
2373 return syscall2(.timerfd_gettime, @bitCast(@as(isize, fd)), @intFromPtr(curr_value));
2414 return syscall2(
2415 if (@hasField(SYS, "timerfd_gettime")) .timerfd_gettime else .timerfd_gettime64,
2416 @bitCast(@as(isize, fd)),
2417 @intFromPtr(curr_value),
2418 );
23742419}
23752420
23762421pub fn timerfd_settime(fd: i32, flags: TFD.TIMER, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
2377 return syscall4(.timerfd_settime, @bitCast(@as(isize, fd)), @as(u32, @bitCast(flags)), @intFromPtr(new_value), @intFromPtr(old_value));
2422 return syscall4(
2423 if (@hasField(SYS, "timerfd_settime")) .timerfd_settime else .timerfd_settime64,
2424 @bitCast(@as(isize, fd)),
2425 @as(u32, @bitCast(flags)),
2426 @intFromPtr(new_value),
2427 @intFromPtr(old_value),
2428 );
23782429}
23792430
23802431// Flags for the 'setitimer' system call