authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-02 14:25:27-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-02 14:25:27-08:00
log5312063138e787a09493e5f5affb5c8652b66dbc
treea3ef8619becb5a68fc44159583623c675b7d93d2
parenteb74e23e7ba4f2000bbe4e908bf74c5c9dd7adcc

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

1 files changed, 29 insertions(+), 10 deletions(-)

lib/std/Io/Threaded.zig+29-10
...@@ -29,8 +29,8 @@ const ws2_32 = std.os.windows.ws2_32;...@@ -29,8 +29,8 @@ const ws2_32 = std.os.windows.ws2_32;
29/// * scanning environment variables on some targets29/// * scanning environment variables on some targets
30/// * memory-mapping when mmap or equivalent is not available30/// * memory-mapping when mmap or equivalent is not available
31allocator: Allocator,31allocator: Allocator,
32mutex: Io.Mutex = .init,32mutex: Mutex = .init,
33cond: Io.Condition = .init,33cond: Condition = .init,
34run_queue: std.SinglyLinkedList = .{},34run_queue: std.SinglyLinkedList = .{},
35join_requested: bool = false,35join_requested: bool = false,
36stack_size: usize,36stack_size: usize,
...@@ -14299,9 +14299,10 @@ const Wsa = struct {...@@ -14299,9 +14299,10 @@ const Wsa = struct {
14299};14299};
1430014300
14301fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {14301fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
14302 const t_io = io(t);
14302 const wsa = &t.wsa;14303 const wsa = &t.wsa;
14303 try mutexLock(&wsa.mutex);14304 try wsa.mutex.lock(t_io);
14304 defer mutexUnlock(&wsa.mutex);14305 defer wsa.mutex.unlock(t_io);
14305 switch (wsa.status) {14306 switch (wsa.status) {
14306 .uninitialized => {14307 .uninitialized => {
14307 var wsa_data: ws2_32.WSADATA = undefined;14308 var wsa_data: ws2_32.WSADATA = undefined;
...@@ -16877,7 +16878,7 @@ const parking_futex = struct {...@@ -16877,7 +16878,7 @@ const parking_futex = struct {
16877 /// avoid a race.16878 /// avoid a race.
16878 num_waiters: std.atomic.Value(u32),16879 num_waiters: std.atomic.Value(u32),
16879 /// Protects `waiters`.16880 /// Protects `waiters`.
16880 mutex: Io.Mutex,16881 mutex: Mutex,
16881 waiters: std.DoublyLinkedList,16882 waiters: std.DoublyLinkedList,
1688216883
16883 /// Prevent false sharing between buckets.16884 /// Prevent false sharing between buckets.
...@@ -18102,8 +18103,14 @@ fn eventSet(event: *Io.Event) void {...@@ -18102,8 +18103,14 @@ fn eventSet(event: *Io.Event) void {
18102 }18103 }
18103}18104}
1810418105
18106const Condition = if (!is_windows) Io.Condition else struct {
18107 condition: windows.CONDITION_VARIABLE,
18108 const init: @This() = .{ .condition = .{} };
18109};
18110
18105/// Same as `Io.Condition.broadcast` but avoids the VTable.18111/// Same as `Io.Condition.broadcast` but avoids the VTable.
18106fn condBroadcast(cond: *Io.Condition) void {18112fn condBroadcast(cond: *Condition) void {
18113 if (is_windows) return windows.ntdll.RtlWakeAllConditionVariable(&cond.condition);
18107 var prev_state = cond.state.load(.monotonic);18114 var prev_state = cond.state.load(.monotonic);
18108 while (prev_state.waiters > prev_state.signals) {18115 while (prev_state.waiters > prev_state.signals) {
18109 @branchHint(.unlikely);18116 @branchHint(.unlikely);
...@@ -18123,7 +18130,8 @@ fn condBroadcast(cond: *Io.Condition) void {...@@ -18123,7 +18130,8 @@ fn condBroadcast(cond: *Io.Condition) void {
18123}18130}
1812418131
18125/// Same as `Io.Condition.signal` but avoids the VTable.18132/// Same as `Io.Condition.signal` but avoids the VTable.
18126fn condSignal(cond: *Io.Condition) void {18133fn condSignal(cond: *Condition) void {
18134 if (is_windows) return windows.ntdll.RtlWakeConditionVariable(&cond.condition);
18127 var prev_state = cond.state.load(.monotonic);18135 var prev_state = cond.state.load(.monotonic);
18128 while (prev_state.waiters > prev_state.signals) {18136 while (prev_state.waiters > prev_state.signals) {
18129 @branchHint(.unlikely);18137 @branchHint(.unlikely);
...@@ -18143,7 +18151,11 @@ fn condSignal(cond: *Io.Condition) void {...@@ -18143,7 +18151,11 @@ fn condSignal(cond: *Io.Condition) void {
18143}18151}
1814418152
18145/// Same as `Io.Condition.waitUncancelable` but avoids the VTable.18153/// Same as `Io.Condition.waitUncancelable` but avoids the VTable.
18146fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void {18154fn condWait(cond: *Condition, mutex: *Mutex) void {
18155 if (is_windows) {
18156 _ = windows.kernel32.SleepConditionVariableSRW(&cond.condition, &mutex.srwlock, windows.INFINITE, 0);
18157 return;
18158 }
18147 var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load18159 var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load
1814818160
18149 {18161 {
...@@ -18172,6 +18184,11 @@ fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void {...@@ -18172,6 +18184,11 @@ fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void {
18172 }18184 }
18173}18185}
1817418186
18187const Mutex = if (!is_windows) Io.Mutex else struct {
18188 srwlock: windows.SRWLOCK,
18189 const init: @This() = .{ .srwlock = .{} };
18190};
18191
18175/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.18192/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.
18176fn mutexLock(m: *Io.Mutex) Io.Cancelable!void {18193fn mutexLock(m: *Io.Mutex) Io.Cancelable!void {
18177 const initial_state = m.state.cmpxchgWeak(18194 const initial_state = m.state.cmpxchgWeak(
...@@ -18192,7 +18209,8 @@ fn mutexLock(m: *Io.Mutex) Io.Cancelable!void {...@@ -18192,7 +18209,8 @@ fn mutexLock(m: *Io.Mutex) Io.Cancelable!void {
18192}18209}
1819318210
18194/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.18211/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.
18195fn mutexLockUncancelable(m: *Io.Mutex) void {18212fn mutexLockUncancelable(m: *Mutex) void {
18213 if (is_windows) return windows.ntdll.RtlAcquireSRWLockExclusive(&m.srwlock);
18196 const initial_state = m.state.cmpxchgWeak(18214 const initial_state = m.state.cmpxchgWeak(
18197 .unlocked,18215 .unlocked,
18198 .locked_once,18216 .locked_once,
...@@ -18211,7 +18229,8 @@ fn mutexLockUncancelable(m: *Io.Mutex) void {...@@ -18211,7 +18229,8 @@ fn mutexLockUncancelable(m: *Io.Mutex) void {
18211}18229}
1821218230
18213/// Same as `Io.Mutex.unlock` but avoids the VTable.18231/// Same as `Io.Mutex.unlock` but avoids the VTable.
18214fn mutexUnlock(m: *Io.Mutex) void {18232fn mutexUnlock(m: *Mutex) void {
18233 if (is_windows) return windows.ntdll.RtlReleaseSRWLockExclusive(&m.srwlock);
18215 switch (m.state.swap(.unlocked, .release)) {18234 switch (m.state.swap(.unlocked, .release)) {
18216 .unlocked => unreachable,18235 .unlocked => unreachable,
18217 .locked_once => {},18236 .locked_once => {},