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;
2929/// * scanning environment variables on some targets
3030/// * memory-mapping when mmap or equivalent is not available
3131allocator: Allocator,
32mutex: Io.Mutex = .init,
33cond: Io.Condition = .init,
32mutex: Mutex = .init,
33cond: Condition = .init,
3434run_queue: std.SinglyLinkedList = .{},
3535join_requested: bool = false,
3636stack_size: usize,
......@@ -14299,9 +14299,10 @@ const Wsa = struct {
1429914299};
1430014300
1430114301fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
14302 const t_io = io(t);
1430214303 const wsa = &t.wsa;
14303 try mutexLock(&wsa.mutex);
14304 defer mutexUnlock(&wsa.mutex);
14304 try wsa.mutex.lock(t_io);
14305 defer wsa.mutex.unlock(t_io);
1430514306 switch (wsa.status) {
1430614307 .uninitialized => {
1430714308 var wsa_data: ws2_32.WSADATA = undefined;
......@@ -16877,7 +16878,7 @@ const parking_futex = struct {
1687716878 /// avoid a race.
1687816879 num_waiters: std.atomic.Value(u32),
1687916880 /// Protects `waiters`.
16880 mutex: Io.Mutex,
16881 mutex: Mutex,
1688116882 waiters: std.DoublyLinkedList,
1688216883
1688316884 /// Prevent false sharing between buckets.
......@@ -18102,8 +18103,14 @@ fn eventSet(event: *Io.Event) void {
1810218103 }
1810318104}
1810418105
18106const Condition = if (!is_windows) Io.Condition else struct {
18107 condition: windows.CONDITION_VARIABLE,
18108 const init: @This() = .{ .condition = .{} };
18109};
18110
1810518111/// 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);
1810718114 var prev_state = cond.state.load(.monotonic);
1810818115 while (prev_state.waiters > prev_state.signals) {
1810918116 @branchHint(.unlikely);
......@@ -18123,7 +18130,8 @@ fn condBroadcast(cond: *Io.Condition) void {
1812318130}
1812418131
1812518132/// 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);
1812718135 var prev_state = cond.state.load(.monotonic);
1812818136 while (prev_state.waiters > prev_state.signals) {
1812918137 @branchHint(.unlikely);
......@@ -18143,7 +18151,11 @@ fn condSignal(cond: *Io.Condition) void {
1814318151}
1814418152
1814518153/// 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 }
1814718159 var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load
1814818160
1814918161 {
......@@ -18172,6 +18184,11 @@ fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void {
1817218184 }
1817318185}
1817418186
18187const Mutex = if (!is_windows) Io.Mutex else struct {
18188 srwlock: windows.SRWLOCK,
18189 const init: @This() = .{ .srwlock = .{} };
18190};
18191
1817518192/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.
1817618193fn mutexLock(m: *Io.Mutex) Io.Cancelable!void {
1817718194 const initial_state = m.state.cmpxchgWeak(
......@@ -18192,7 +18209,8 @@ fn mutexLock(m: *Io.Mutex) Io.Cancelable!void {
1819218209}
1819318210
1819418211/// 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);
1819618214 const initial_state = m.state.cmpxchgWeak(
1819718215 .unlocked,
1819818216 .locked_once,
......@@ -18211,7 +18229,8 @@ fn mutexLockUncancelable(m: *Io.Mutex) void {
1821118229}
1821218230
1821318231/// 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);
1821518234 switch (m.state.swap(.unlocked, .release)) {
1821618235 .unlocked => unreachable,
1821718236 .locked_once => {},