authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-22 21:46:08-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:12-08:00
logbd6acbf7da55a2497fcfb9c589093612a3fe9680
tree6305654f8efc3c44c4afec344ff09f5fda74113d
parent6ece10f63d91cfa16d8388f8d696368537c1662e

std.Io: minor cleanups to futex and event

mainly avoid an unnecessary `@ptrCast`

2 files changed, 19 insertions(+), 20 deletions(-)

lib/std/Io.zig+13-7
...@@ -1314,17 +1314,21 @@ pub fn futexWait(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, e...@@ -1314,17 +1314,21 @@ pub fn futexWait(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, e
1314/// wakeups are possible. It remains the caller's responsibility to differentiate between these1314/// wakeups are possible. It remains the caller's responsibility to differentiate between these
1315/// three possible wake-up reasons if necessary.1315/// three possible wake-up reasons if necessary.
1316pub fn futexWaitTimeout(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, expected: T, timeout: Timeout) Cancelable!void {1316pub fn futexWaitTimeout(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, expected: T, timeout: Timeout) Cancelable!void {
1317 comptime assert(@sizeOf(T) == 4);1317 const expected_int: u32 = switch (@typeInfo(T)) {
1318 const expected_raw: *align(1) const u32 = @ptrCast(&expected);1318 .@"enum" => @bitCast(@intFromEnum(expected)),
1319 return io.vtable.futexWait(io.userdata, @ptrCast(ptr), expected_raw.*, timeout);1319 else => @bitCast(expected),
1320 };
1321 return io.vtable.futexWait(io.userdata, @ptrCast(ptr), expected_int, timeout);
1320}1322}
1321/// Same as `futexWait`, except does not introduce a cancelation point.1323/// Same as `futexWait`, except does not introduce a cancelation point.
1322///1324///
1323/// For a description of cancelation and cancelation points, see `Future.cancel`.1325/// For a description of cancelation and cancelation points, see `Future.cancel`.
1324pub fn futexWaitUncancelable(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, expected: T) void {1326pub fn futexWaitUncancelable(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, expected: T) void {
1325 comptime assert(@sizeOf(T) == @sizeOf(u32));1327 const expected_int: u32 = switch (@typeInfo(T)) {
1326 const expected_raw: *align(1) const u32 = @ptrCast(&expected);1328 .@"enum" => @bitCast(@intFromEnum(expected)),
1327 io.vtable.futexWaitUncancelable(io.userdata, @ptrCast(ptr), expected_raw.*);1329 else => @bitCast(expected),
1330 };
1331 io.vtable.futexWaitUncancelable(io.userdata, @ptrCast(ptr), expected_int);
1328}1332}
1329/// Unblocks pending futex waits on `ptr`, up to a limit of `max_waiters` calls.1333/// Unblocks pending futex waits on `ptr`, up to a limit of `max_waiters` calls.
1330pub fn futexWake(io: Io, comptime T: type, ptr: *align(@alignOf(u32)) const T, max_waiters: u32) void {1334pub 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) {...@@ -1576,10 +1580,12 @@ pub const Event = enum(u32) {
1576 }1580 }
1577 }1581 }
15781582
1583 pub const WaitTimeoutError = error{Timeout} || Cancelable;
1584
1579 /// Blocks the calling thread until either the logical boolean is set, the timeout expires, or a1585 /// Blocks the calling thread until either the logical boolean is set, the timeout expires, or a
1580 /// spurious wakeup occurs. If the timeout expires or a spurious wakeup occurs, `error.Timeout`1586 /// spurious wakeup occurs. If the timeout expires or a spurious wakeup occurs, `error.Timeout`
1581 /// is returned.1587 /// is returned.
1582 pub fn waitTimeout(event: *Event, io: Io, timeout: Timeout) (error{Timeout} || Cancelable)!void {1588 pub fn waitTimeout(event: *Event, io: Io, timeout: Timeout) WaitTimeoutError!void {
1583 if (@cmpxchgStrong(Event, event, .unset, .waiting, .acquire, .acquire)) |prev| switch (prev) {1589 if (@cmpxchgStrong(Event, event, .unset, .waiting, .acquire, .acquire)) |prev| switch (prev) {
1584 .unset => unreachable,1590 .unset => unreachable,
1585 .waiting => assert(!builtin.single_threaded), // invalid state1591 .waiting => assert(!builtin.single_threaded), // invalid state
lib/std/Io/Threaded.zig+6-13
...@@ -292,7 +292,7 @@ const Thread = struct {...@@ -292,7 +292,7 @@ const Thread = struct {
292 .INTR => {}, // caller's responsibility to retry292 .INTR => {}, // caller's responsibility to retry
293 .AGAIN => {}, // ptr.* != expect293 .AGAIN => {}, // ptr.* != expect
294 .INVAL => {}, // possibly timeout overflow294 .INVAL => {}, // possibly timeout overflow
295 .TIMEDOUT => {}, // timeout295 .TIMEDOUT => {},
296 .FAULT => recoverableOsBugDetected(), // ptr was invalid296 .FAULT => recoverableOsBugDetected(), // ptr was invalid
297 else => recoverableOsBugDetected(),297 else => recoverableOsBugDetected(),
298 }298 }
...@@ -1548,6 +1548,7 @@ fn cancel(...@@ -1548,6 +1548,7 @@ fn cancel(
1548}1548}
15491549
1550fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.Timeout) Io.Cancelable!void {1550fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.Timeout) Io.Cancelable!void {
1551 if (builtin.single_threaded) unreachable; // Deadlock.
1551 const t: *Threaded = @ptrCast(@alignCast(userdata));1552 const t: *Threaded = @ptrCast(@alignCast(userdata));
1552 const current_thread = Thread.getCurrent(t);1553 const current_thread = Thread.getCurrent(t);
1553 const t_io = ioBasic(t);1554 const t_io = ioBasic(t);
...@@ -1555,29 +1556,21 @@ fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io....@@ -1555,29 +1556,21 @@ fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.
1555 const d = (timeout.toDurationFromNow(t_io) catch break :ns 10) orelse break :ns null;1556 const d = (timeout.toDurationFromNow(t_io) catch break :ns 10) orelse break :ns null;
1556 break :ns std.math.lossyCast(u64, d.raw.toNanoseconds());1557 break :ns std.math.lossyCast(u64, d.raw.toNanoseconds());
1557 };1558 };
1558 switch (native_os) {1559 return Thread.futexWaitTimed(current_thread, ptr, expected, timeout_ns);
1559 .illumos, .netbsd, .openbsd => @panic("TODO"),
1560 else => try current_thread.futexWaitTimed(ptr, expected, timeout_ns),
1561 }
1562}1560}
15631561
1564fn futexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32) void {1562fn futexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32) void {
1563 if (builtin.single_threaded) unreachable; // Deadlock.
1565 const t: *Threaded = @ptrCast(@alignCast(userdata));1564 const t: *Threaded = @ptrCast(@alignCast(userdata));
1566 _ = t;1565 _ = t;
1567 switch (native_os) {1566 Thread.futexWaitUncancelable(ptr, expected);
1568 .illumos, .netbsd, .openbsd => @panic("TODO"),
1569 else => Thread.futexWaitUncancelable(ptr, expected),
1570 }
1571}1567}
15721568
1573fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void {1569fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void {
1574 if (builtin.single_threaded) unreachable; // Nothing to wake up.1570 if (builtin.single_threaded) unreachable; // Nothing to wake up.
1575 const t: *Threaded = @ptrCast(@alignCast(userdata));1571 const t: *Threaded = @ptrCast(@alignCast(userdata));
1576 _ = t;1572 _ = t;
1577 switch (native_os) {1573 Thread.futexWake(ptr, max_waiters);
1578 .illumos, .netbsd, .openbsd => @panic("TODO"),
1579 else => Thread.futexWake(ptr, max_waiters),
1580 }
1581}1574}
15821575
1583const dirCreateDir = switch (native_os) {1576const dirCreateDir = switch (native_os) {