zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 5312063138e787a09493e5f5affb5c8652b66dbc (tree)
parent eb74e23e7ba4f2000bbe4e908bf74c5c9dd7adcc
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Mon,  2 Feb 2026 14:25:27 -0800

std.Io.Threaded: work around parking futex bug

This commit should be reverted - it's testing a hypothesis that Windows
is deadlocking due to bug in the implementation of
std.Io.Threaded.parking_futex

Diffstat:
Mlib/std/Io/Threaded.zig | 39+++++++++++++++++++++++++++++----------
1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig @@ -29,8 +29,8 @@ const ws2_32 = std.os.windows.ws2_32; /// * scanning environment variables on some targets /// * memory-mapping when mmap or equivalent is not available allocator: Allocator, -mutex: Io.Mutex = .init, -cond: Io.Condition = .init, +mutex: Mutex = .init, +cond: Condition = .init, run_queue: std.SinglyLinkedList = .{}, join_requested: bool = false, stack_size: usize, @@ -14299,9 +14299,10 @@ const Wsa = struct { }; fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void { + const t_io = io(t); const wsa = &t.wsa; - try mutexLock(&wsa.mutex); - defer mutexUnlock(&wsa.mutex); + try wsa.mutex.lock(t_io); + defer wsa.mutex.unlock(t_io); switch (wsa.status) { .uninitialized => { var wsa_data: ws2_32.WSADATA = undefined; @@ -16877,7 +16878,7 @@ const parking_futex = struct { /// avoid a race. num_waiters: std.atomic.Value(u32), /// Protects `waiters`. - mutex: Io.Mutex, + mutex: Mutex, waiters: std.DoublyLinkedList, /// Prevent false sharing between buckets. @@ -18102,8 +18103,14 @@ fn eventSet(event: *Io.Event) void { } } +const Condition = if (!is_windows) Io.Condition else struct { + condition: windows.CONDITION_VARIABLE, + const init: @This() = .{ .condition = .{} }; +}; + /// Same as `Io.Condition.broadcast` but avoids the VTable. -fn condBroadcast(cond: *Io.Condition) void { +fn condBroadcast(cond: *Condition) void { + if (is_windows) return windows.ntdll.RtlWakeAllConditionVariable(&cond.condition); var prev_state = cond.state.load(.monotonic); while (prev_state.waiters > prev_state.signals) { @branchHint(.unlikely); @@ -18123,7 +18130,8 @@ fn condBroadcast(cond: *Io.Condition) void { } /// Same as `Io.Condition.signal` but avoids the VTable. -fn condSignal(cond: *Io.Condition) void { +fn condSignal(cond: *Condition) void { + if (is_windows) return windows.ntdll.RtlWakeConditionVariable(&cond.condition); var prev_state = cond.state.load(.monotonic); while (prev_state.waiters > prev_state.signals) { @branchHint(.unlikely); @@ -18143,7 +18151,11 @@ fn condSignal(cond: *Io.Condition) void { } /// Same as `Io.Condition.waitUncancelable` but avoids the VTable. -fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void { +fn condWait(cond: *Condition, mutex: *Mutex) void { + if (is_windows) { + _ = windows.kernel32.SleepConditionVariableSRW(&cond.condition, &mutex.srwlock, windows.INFINITE, 0); + return; + } var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load { @@ -18172,6 +18184,11 @@ fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void { } } +const Mutex = if (!is_windows) Io.Mutex else struct { + srwlock: windows.SRWLOCK, + const init: @This() = .{ .srwlock = .{} }; +}; + /// Same as `Io.Mutex.lockUncancelable` but avoids the VTable. fn mutexLock(m: *Io.Mutex) Io.Cancelable!void { const initial_state = m.state.cmpxchgWeak( @@ -18192,7 +18209,8 @@ fn mutexLock(m: *Io.Mutex) Io.Cancelable!void { } /// Same as `Io.Mutex.lockUncancelable` but avoids the VTable. -fn mutexLockUncancelable(m: *Io.Mutex) void { +fn mutexLockUncancelable(m: *Mutex) void { + if (is_windows) return windows.ntdll.RtlAcquireSRWLockExclusive(&m.srwlock); const initial_state = m.state.cmpxchgWeak( .unlocked, .locked_once, @@ -18211,7 +18229,8 @@ fn mutexLockUncancelable(m: *Io.Mutex) void { } /// Same as `Io.Mutex.unlock` but avoids the VTable. -fn mutexUnlock(m: *Io.Mutex) void { +fn mutexUnlock(m: *Mutex) void { + if (is_windows) return windows.ntdll.RtlReleaseSRWLockExclusive(&m.srwlock); switch (m.state.swap(.unlocked, .release)) { .unlocked => unreachable, .locked_once => {},