diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index da3da684d920bd9758406453a19eda086782b676..95e4b9503c10f43d5eddad5c6c44e200a0e460fa 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -66,13 +66,13 @@ pub fn main() void { } if (listen) { - return mainServer() catch @panic("internal test runner failure"); + return mainServer(args) catch @panic("internal test runner failure"); } else { - return mainTerminal(); + return mainTerminal(args); } } -fn mainServer() !void { +fn mainServer(args: []const [:0]const u8) !void { @disableInstrumentation(); var stdin_reader = Io.File.stdin().readerStreaming(runner_threaded_io, &stdin_buffer); var stdout_writer = Io.File.stdout().writerStreaming(runner_threaded_io, &stdout_buffer); @@ -131,7 +131,9 @@ fn mainServer() !void { .run_test => { testing.allocator_instance = .{}; - testing.io_instance = .init(testing.allocator, .{}); + testing.io_instance = .init(testing.allocator, .{ + .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{}, + }); log_err_count = 0; const index = try server.receiveBody_u32(); const test_fn = builtin.test_functions[index]; @@ -215,7 +217,7 @@ fn mainServer() !void { } } -fn mainTerminal() void { +fn mainTerminal(args: []const [:0]const u8) void { @disableInstrumentation(); if (builtin.fuzz) @panic("fuzz test requires server"); @@ -233,7 +235,9 @@ fn mainTerminal() void { var leaks: usize = 0; for (test_fn_list, 0..) |test_fn, i| { testing.allocator_instance = .{}; - testing.io_instance = .init(testing.allocator, .{}); + testing.io_instance = .init(testing.allocator, .{ + .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{}, + }); defer { testing.io_instance.deinit(); if (testing.allocator_instance.deinit() == .leak) leaks += 1; diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig index 6db13f5c6cd1daeb770436519f5168daeb23eb8a..82bf3b927df0cd22a14f640e1b1f58aedc23c373 100644 --- a/lib/std/Io/Dir.zig +++ b/lib/std/Io/Dir.zig @@ -113,6 +113,7 @@ pub const Reader = struct { }, .wasi => @sizeOf(std.os.wasi.dirent_t) + std.mem.alignForward(usize, max_name_bytes, @alignOf(std.os.wasi.dirent_t)), + .openbsd => std.c.S.BLKSIZE, else => if (builtin.link_libc) @sizeOf(std.c.dirent) else std.mem.alignForward(usize, max_name_bytes, @alignOf(usize)), }; diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 5f54686a43e925b76e462212d2660ac952bd433e..c9e6ba3fc79ad400593d19be7743f6abd1f264d7 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -390,6 +390,52 @@ const Thread = struct { else => unreachable, }; }, + .openbsd => { + var tm: std.c.timespec = undefined; + var tm_ptr: ?*const std.c.timespec = null; + if (timeout_ns) |ns| { + tm_ptr = &tm; + tm = timestampToPosix(ns); + } + if (thread) |t| try t.beginSyscall(); + const rc = std.c.futex( + ptr, + std.c.FUTEX.WAIT | std.c.FUTEX.PRIVATE_FLAG, + @as(c_int, @bitCast(expect)), + tm_ptr, + null, // uaddr2 is ignored + ); + if (thread) |t| t.endSyscall(); + if (is_debug) switch (posix.errno(rc)) { + .SUCCESS => {}, + .NOSYS => unreachable, // constant op known good value + .AGAIN => {}, // contents of uaddr != val + .INVAL => unreachable, // invalid timeout + .TIMEDOUT => {}, // timeout + .INTR => {}, // a signal arrived + .CANCELED => {}, // a signal arrived and SA_RESTART was set + else => unreachable, + }; + }, + .dragonfly => { + var timeout_us: c_int = undefined; + if (timeout_ns) |ns| { + timeout_us = std.math.cast(c_int, ns / std.time.ns_per_us) orelse std.math.maxInt(c_int); + } else { + timeout_us = 0; + } + if (thread) |t| try t.beginSyscall(); + const rc = std.c.umtx_sleep(@ptrCast(ptr), @bitCast(expect), timeout_us); + if (thread) |t| t.endSyscall(); + if (is_debug) switch (std.posix.errno(rc)) { + .SUCCESS => {}, + .BUSY => {}, // ptr != expect + .AGAIN => {}, // maybe timed out, or paged out, or hit 2s kernel refresh + .INTR => {}, // spurious wake + .INVAL => unreachable, // invalid timeout + else => unreachable, + }; + }, else => if (std.Thread.use_pthreads) { // TODO integrate the following function being called with robust cancelation. return pthreads_futex.wait(ptr, expect, timeout_ns) catch |err| switch (err) { @@ -473,6 +519,23 @@ const Thread = struct { else => unreachable, // deadlock due to operating system bug } }, + .openbsd => { + const rc = std.c.futex( + ptr, + std.c.FUTEX.WAKE | std.c.FUTEX.PRIVATE_FLAG, + @min(max_waiters, std.math.maxInt(c_int)), + null, // timeout is ignored + null, // uaddr2 is ignored + ); + assert(rc >= 0); + }, + .dragonfly => { + // will generally return 0 unless the address is bad + _ = std.c.umtx_wakeup( + @ptrCast(ptr), + @min(max_waiters, std.math.maxInt(c_int)), + ); + }, else => if (std.Thread.use_pthreads) { return pthreads_futex.wake(ptr, max_waiters); } else { diff --git a/lib/std/c.zig b/lib/std/c.zig index 5f0d2dedf879bcabaa3117414d737c78a4b3aabc..e9810aeb0912015c015dd68f1259cde477b1a60a 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -167,6 +167,18 @@ pub const timespec = switch (native_os) { .openbsd, .haiku => extern struct { sec: time_t, nsec: isize, + + /// For use with `utimensat` and `futimens`. + pub const NOW: timespec = .{ + .sec = 0, // ignored + .nsec = -2, + }; + + /// For use with `utimensat` and `futimens`. + pub const OMIT: timespec = .{ + .sec = 0, // ignored + .nsec = -1, + }; }, else => void, }; @@ -2365,6 +2377,8 @@ pub const S = switch (native_os) { pub const IWOTH = 0o002; pub const IXOTH = 0o001; + pub const BLKSIZE = 512; + pub fn ISFIFO(m: u32) bool { return m & IFMT == IFIFO; } @@ -9676,6 +9690,7 @@ pub const NSIG = switch (native_os) { .illumos => 75, // https://github.com/SerenityOS/serenity/blob/046c23f567a17758d762a33bdf04bacbfd088f9f/Kernel/API/POSIX/signal_numbers.h#L42 .openbsd, .serenity => 33, + .dragonfly => 64, else => {}, }; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index bcb9048e0e05428a7288c25d292d37251b000dee..94cf3055e562c0cc077b19c0951578f5bdf05c66 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -645,6 +645,7 @@ fn contains(entries: *const std.array_list.Managed(Dir.Entry), el: Dir.Entry) bo test "Dir.realPath smoke test" { if (native_os == .wasi) return error.SkipZigTest; + if (native_os == .openbsd) return error.SkipZigTest; try testWithAllSupportedPathTypes(struct { fn impl(ctx: *TestContext) !void { @@ -820,7 +821,7 @@ test "file operations on directories" { try expectError(error.IsDir, ctx.dir.createFile(io, test_dir_name, .{})); try expectError(error.IsDir, ctx.dir.deleteFile(io, test_dir_name)); switch (native_os) { - .dragonfly, .netbsd => { + .netbsd => { // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732 const buf = try ctx.dir.readFileAlloc(io, test_dir_name, testing.allocator, .unlimited); testing.allocator.free(buf); @@ -1240,6 +1241,7 @@ test "createDirPath, put some files in it, deleteTreeMinStackSize" { test "createDirPath in a directory that no longer exists" { if (native_os == .windows) return error.SkipZigTest; // Windows returns FileBusy if attempting to remove an open dir + if (native_os == .dragonfly) return error.SkipZigTest; // DragonflyBSD does not produce error (hammer2 fs) const io = testing.io; diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 64845d15ee7b3b778a427756fb6ccb533243bfd8..6fdb980b1bb93ab2db7d1a404cb996c7cf3c24ac 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -364,9 +364,10 @@ test "getrlimit and setrlimit" { } test "sigrtmin/max" { - if (native_os == .wasi or native_os == .windows or native_os.isDarwin() or native_os == .openbsd) { - return error.SkipZigTest; - } + if (native_os.isDarwin() or switch (native_os) { + .wasi, .windows, .openbsd, .dragonfly => true, + else => false, + }) return error.SkipZigTest; try expect(posix.sigrtmin() >= 32); try expect(posix.sigrtmin() >= posix.system.sigrtmin()); @@ -397,7 +398,7 @@ fn reserved_signo(i: usize) bool { if (!builtin.link_libc) return false; const max = if (native_os == .netbsd) 32 else 31; if (i > max) return true; - if (native_os == .openbsd) return false; // no RT signals + if (native_os == .openbsd or native_os == .dragonfly) return false; // no RT signals return i < posix.sigrtmin(); }