From bd6acbf7da55a2497fcfb9c589093612a3fe9680 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 22 Dec 2025 21:46:08 -0800 Subject: [PATCH] std.Io: minor cleanups to futex and event mainly avoid an unnecessary `@ptrCast` --- lib/std/Io.zig | 20 +++++++++++++------- lib/std/Io/Threaded.zig | 19 ++++++------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index d01077d803..70b6c5bcc3 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -1314,17 +1314,21 @@ pub fn futexWait(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, e /// wakeups are possible. It remains the caller's responsibility to differentiate between these /// three possible wake-up reasons if necessary. pub fn futexWaitTimeout(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, expected: T, timeout: Timeout) Cancelable!void { - comptime assert(@sizeOf(T) == 4); - const expected_raw: *align(1) const u32 = @ptrCast(&expected); - return io.vtable.futexWait(io.userdata, @ptrCast(ptr), expected_raw.*, timeout); + const expected_int: u32 = switch (@typeInfo(T)) { + .@"enum" => @bitCast(@intFromEnum(expected)), + else => @bitCast(expected), + }; + return io.vtable.futexWait(io.userdata, @ptrCast(ptr), expected_int, timeout); } /// Same as `futexWait`, except does not introduce a cancelation point. /// /// For a description of cancelation and cancelation points, see `Future.cancel`. pub fn futexWaitUncancelable(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, expected: T) void { - comptime assert(@sizeOf(T) == @sizeOf(u32)); - const expected_raw: *align(1) const u32 = @ptrCast(&expected); - io.vtable.futexWaitUncancelable(io.userdata, @ptrCast(ptr), expected_raw.*); + const expected_int: u32 = switch (@typeInfo(T)) { + .@"enum" => @bitCast(@intFromEnum(expected)), + else => @bitCast(expected), + }; + io.vtable.futexWaitUncancelable(io.userdata, @ptrCast(ptr), expected_int); } /// Unblocks pending futex waits on `ptr`, up to a limit of `max_waiters` calls. pub fn futexWake(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, max_waiters: u32) void { @@ -1576,10 +1580,12 @@ pub const Event = enum(u32) { } } + pub const WaitTimeoutError = error{Timeout} || Cancelable; + /// Blocks the calling thread until either the logical boolean is set, the timeout expires, or a /// spurious wakeup occurs. If the timeout expires or a spurious wakeup occurs, `error.Timeout` /// is returned. - pub fn waitTimeout(event: *Event, io: Io, timeout: Timeout) (error{Timeout} || Cancelable)!void { + pub fn waitTimeout(event: *Event, io: Io, timeout: Timeout) WaitTimeoutError!void { if (@cmpxchgStrong(Event, event, .unset, .waiting, .acquire, .acquire)) |prev| switch (prev) { .unset => unreachable, .waiting => assert(!builtin.single_threaded), // invalid state diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 1c7d848aae..4d26780705 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -292,7 +292,7 @@ const Thread = struct { .INTR => {}, // caller's responsibility to retry .AGAIN => {}, // ptr.* != expect .INVAL => {}, // possibly timeout overflow - .TIMEDOUT => {}, // timeout + .TIMEDOUT => {}, .FAULT => recoverableOsBugDetected(), // ptr was invalid else => recoverableOsBugDetected(), } @@ -1548,6 +1548,7 @@ fn cancel( } fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.Timeout) Io.Cancelable!void { + if (builtin.single_threaded) unreachable; // Deadlock. const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); const t_io = ioBasic(t); @@ -1555,29 +1556,21 @@ fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io. const d = (timeout.toDurationFromNow(t_io) catch break :ns 10) orelse break :ns null; break :ns std.math.lossyCast(u64, d.raw.toNanoseconds()); }; - switch (native_os) { - .illumos, .netbsd, .openbsd => @panic("TODO"), - else => try current_thread.futexWaitTimed(ptr, expected, timeout_ns), - } + return Thread.futexWaitTimed(current_thread, ptr, expected, timeout_ns); } fn futexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32) void { + if (builtin.single_threaded) unreachable; // Deadlock. const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - switch (native_os) { - .illumos, .netbsd, .openbsd => @panic("TODO"), - else => Thread.futexWaitUncancelable(ptr, expected), - } + Thread.futexWaitUncancelable(ptr, expected); } fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void { if (builtin.single_threaded) unreachable; // Nothing to wake up. const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - switch (native_os) { - .illumos, .netbsd, .openbsd => @panic("TODO"), - else => Thread.futexWake(ptr, max_waiters), - } + Thread.futexWake(ptr, max_waiters); } const dirCreateDir = switch (native_os) {