From 537cb49eb241521bf58df8510c1c86aea60eb84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:27:07 +0200 Subject: [PATCH 1/8] std.os.linux: Define the Stat struct for riscv32. The kernel does define the struct, it just doesn't use it. Yet both glibc and musl expose it directly as their public stat struct, and std.c takes it from std.os.linux. So just define it after all. --- lib/std/os/linux/riscv32.zig | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/std/os/linux/riscv32.zig b/lib/std/os/linux/riscv32.zig index 08288d45e5..457d7e50b4 100644 --- a/lib/std/os/linux/riscv32.zig +++ b/lib/std/os/linux/riscv32.zig @@ -212,8 +212,37 @@ pub const msghdr_const = extern struct { flags: i32, }; -/// No `Stat` structure on this platform, only `Statx`. -pub const Stat = void; +// The `stat` definition used by the Linux kernel. +pub const Stat = extern struct { + dev: dev_t, + ino: ino_t, + mode: mode_t, + nlink: nlink_t, + uid: uid_t, + gid: gid_t, + rdev: dev_t, + __pad: usize, + size: off_t, + blksize: blksize_t, + __pad2: i32, + blocks: blkcnt_t, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [2]u32, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } +}; pub const Elf_Symndx = u32; From 6364995d3f40efa96bec905c43182e3d4bbaea08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:25:48 +0200 Subject: [PATCH 2/8] std.os.linux: Also use kernel_timespec for riscv32 when libc is linked. Both glibc and musl use time64 as the base ABI for riscv32. This fixes the `sleep` test in `std.time` hanging forever due to the libc functions reading bogus values. --- lib/std/os/linux.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index df9d491a5e..82593d6169 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -7452,7 +7452,7 @@ pub const kernel_timespec = extern struct { }; // https://github.com/ziglang/zig/issues/4726#issuecomment-2190337877 -pub const timespec = if (!builtin.link_libc and native_arch == .riscv32) kernel_timespec else extern struct { +pub const timespec = if (native_arch == .riscv32) kernel_timespec else extern struct { sec: isize, nsec: isize, }; From 68bb788df57d6725c783adb2b9018cc7db789dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:25:08 +0200 Subject: [PATCH 3/8] std.os.linux: Make nanosleep() a compile error on riscv32. This should eventually be converted to the void/{} pattern along with the other syscalls that are compile errors for riscv32. --- lib/std/os/linux.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 82593d6169..90298bc7cd 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1465,7 +1465,9 @@ pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize { } pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { - return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem)); + if (native_arch == .riscv32) { + @compileError("No nanosleep syscall on this architecture."); + } else return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem)); } pub fn pause() usize { From 804319799586961052a9e4f283ad94d5018ce5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:24:55 +0200 Subject: [PATCH 4/8] std.os.linux: Add clock_nanosleep() syscall wrapper. --- lib/std/os/linux.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 90298bc7cd..9039acedee 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1456,6 +1456,16 @@ pub fn clock_settime(clk_id: i32, tp: *const timespec) usize { return syscall2(.clock_settime, @as(usize, @bitCast(@as(isize, clk_id))), @intFromPtr(tp)); } +pub fn clock_nanosleep(clockid: clockid_t, flags: TIMER, request: *const timespec, remain: ?*timespec) usize { + return syscall4( + .clock_nanosleep, + @intFromEnum(clockid), + @as(u32, @bitCast(flags)), + @intFromPtr(request), + @intFromPtr(remain), + ); +} + pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize { return syscall2(.gettimeofday, @intFromPtr(tv), @intFromPtr(tz)); } @@ -4527,6 +4537,11 @@ pub const clockid_t = enum(u32) { _, }; +pub const TIMER = packed struct(u32) { + ABSTIME: bool, + _: u31 = 0, +}; + pub const CSIGNAL = 0x000000ff; pub const CLONE = struct { From f35015575ef7ef5b493cf217f5e9c7152d6b6658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:28:50 +0200 Subject: [PATCH 5/8] std.time: Use clock_nanosleep() to implement sleep() on Linux. This fixes the function for riscv32 where the old nanosleep() is not available. clock_nanosleep() has been available since Linux 2.6 and glibc 2.1 anyway. --- lib/std/time.zig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/std/time.zig b/lib/std/time.zig index 34e544a28b..a80a2477ac 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -50,6 +50,34 @@ pub fn sleep(nanoseconds: u64) void { const s = nanoseconds / ns_per_s; const ns = nanoseconds % ns_per_s; + + // Newer kernel ports don't have old `nanosleep()` and `clock_nanosleep()` has been around + // since Linux 2.6 and glibc 2.1 anyway. + if (builtin.os.tag == .linux) { + const linux = std.os.linux; + + var req: linux.timespec = .{ + .sec = std.math.cast(linux.time_t, s) orelse std.math.maxInt(linux.time_t), + .nsec = std.math.cast(linux.time_t, ns) orelse std.math.maxInt(linux.time_t), + }; + var rem: linux.timespec = undefined; + + while (true) { + switch (linux.E.init(linux.clock_nanosleep(.MONOTONIC, .{ .ABSTIME = false }, &req, &rem))) { + .SUCCESS => return, + .INTR => { + req = rem; + continue; + }, + .FAULT, + .INVAL, + .OPNOTSUPP, + => unreachable, + else => return, + } + } + } + posix.nanosleep(s, ns); } From 65a6e9eee5f0c59622e97c6fd0f283bf2594d6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:28:28 +0200 Subject: [PATCH 6/8] std.posix: Skip a couple of tests that use fstat()/fstatat() on riscv32. --- lib/std/posix/test.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 474de28f6d..e62ffa39ca 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -349,6 +349,7 @@ test "linkat with different directories" { } test "fstatat" { + if (builtin.cpu.arch == .riscv32 and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`. // enable when `fstat` and `fstatat` are implemented on Windows if (native_os == .windows) return error.SkipZigTest; @@ -1264,6 +1265,9 @@ test "fchmodat smoke test" { 0o644, ); posix.close(fd); + + if (builtin.cpu.arch == .riscv32 and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`. + try posix.symlinkat("regfile", tmp.dir.fd, "symlink"); const sym_mode = blk: { const st = try posix.fstatat(tmp.dir.fd, "symlink", posix.AT.SYMLINK_NOFOLLOW); From a0205fff98f1e3df24d28b78b86d6e8f385d350f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:24:19 +0200 Subject: [PATCH 7/8] std.DynLib: Prefer std.fs.File.stat() over posix.fstat(). This is necessary for riscv32-linux. --- lib/std/dynamic_library.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 110393d91a..7fd231aba7 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -215,7 +215,8 @@ pub const ElfDynLib = struct { const fd = try resolveFromName(path); defer posix.close(fd); - const stat = try posix.fstat(fd); + const file: std.fs.File = .{ .handle = fd }; + const stat = try file.stat(); const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig; // This one is to read the ELF info. We do more mmapping later From ae10adb6ef7182352c6176a135e181ba70c81212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 31 Aug 2024 03:29:46 +0200 Subject: [PATCH 8/8] llvm: Don't lower to f16 for riscv32. This causes so many test failures that I doubt this has been tested at all. --- src/codegen/llvm.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index dc8996afda..69e32ad2d2 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -11990,6 +11990,7 @@ fn backendSupportsF16(target: std.Target) bool { .mipsel, .mips64, .mips64el, + .riscv32, .s390x, => false, .aarch64,