authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-03 19:42:54+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-03 22:38:28+00:00
log56a43fb86f5127171709033fb43e19bc3b8a1cdc
tree44a578b94baa0e187c765ba5b6ea81dae3431311
parent184c8f9545944333bf122203c8d813785b43df8a
signaturelock-open Commit is signed but in an unrecognized format.

Revert "std.Io.Threaded: work around parking futex bug"

This reverts commit 5312063138e787a09493e5f5affb5c8652b66dbc.

1 files changed, 64 insertions(+), 91 deletions(-)

lib/std/Io/Threaded.zig+64-91
...@@ -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: Mutex = .init,32mutex: Io.Mutex = .init,
33cond: Condition = .init,33cond: Io.Condition = .init,
34run_queue: std.SinglyLinkedList = .{},34run_queue: std.SinglyLinkedList = .{},
35join_requested: bool = false,35join_requested: bool = false,
36stack_size: usize,36stack_size: usize,
...@@ -1505,8 +1505,8 @@ var global_single_threaded_instance: Threaded = .init_single_threaded;...@@ -1505,8 +1505,8 @@ var global_single_threaded_instance: Threaded = .init_single_threaded;
1505pub const global_single_threaded: *Threaded = &global_single_threaded_instance;1505pub const global_single_threaded: *Threaded = &global_single_threaded_instance;
15061506
1507pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {1507pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {
1508 mutexLockInternal(&t.mutex);1508 mutexLock(&t.mutex);
1509 defer mutexUnlockInternal(&t.mutex);1509 defer mutexUnlock(&t.mutex);
1510 t.async_limit = new_limit;1510 t.async_limit = new_limit;
1511}1511}
15121512
...@@ -1527,8 +1527,8 @@ pub fn deinit(t: *Threaded) void {...@@ -1527,8 +1527,8 @@ pub fn deinit(t: *Threaded) void {
1527fn join(t: *Threaded) void {1527fn join(t: *Threaded) void {
1528 if (builtin.single_threaded) return;1528 if (builtin.single_threaded) return;
1529 {1529 {
1530 mutexLockInternal(&t.mutex);1530 mutexLock(&t.mutex);
1531 defer mutexUnlockInternal(&t.mutex);1531 defer mutexUnlock(&t.mutex);
1532 t.join_requested = true;1532 t.join_requested = true;
1533 }1533 }
1534 condBroadcast(&t.cond);1534 condBroadcast(&t.cond);
...@@ -1593,16 +1593,16 @@ fn worker(t: *Threaded) void {...@@ -1593,16 +1593,16 @@ fn worker(t: *Threaded) void {
15931593
1594 defer t.wait_group.finish();1594 defer t.wait_group.finish();
15951595
1596 mutexLockInternal(&t.mutex);1596 mutexLock(&t.mutex);
1597 defer mutexUnlockInternal(&t.mutex);1597 defer mutexUnlock(&t.mutex);
15981598
1599 while (true) {1599 while (true) {
1600 while (t.run_queue.popFirst()) |runnable_node| {1600 while (t.run_queue.popFirst()) |runnable_node| {
1601 mutexUnlockInternal(&t.mutex);1601 mutexUnlock(&t.mutex);
1602 thread.cancel_protection = .unblocked;1602 thread.cancel_protection = .unblocked;
1603 const runnable: *Runnable = @fieldParentPtr("node", runnable_node);1603 const runnable: *Runnable = @fieldParentPtr("node", runnable_node);
1604 runnable.startFn(runnable, &thread, t);1604 runnable.startFn(runnable, &thread, t);
1605 mutexLockInternal(&t.mutex);1605 mutexLock(&t.mutex);
1606 t.busy_count -= 1;1606 t.busy_count -= 1;
1607 }1607 }
1608 if (t.join_requested) break;1608 if (t.join_requested) break;
...@@ -2025,12 +2025,12 @@ fn async(...@@ -2025,12 +2025,12 @@ fn async(
2025 },2025 },
2026 };2026 };
20272027
2028 mutexLockInternal(&t.mutex);2028 mutexLock(&t.mutex);
20292029
2030 const busy_count = t.busy_count;2030 const busy_count = t.busy_count;
20312031
2032 if (busy_count >= @intFromEnum(t.async_limit)) {2032 if (busy_count >= @intFromEnum(t.async_limit)) {
2033 mutexUnlockInternal(&t.mutex);2033 mutexUnlock(&t.mutex);
2034 future.destroy(gpa);2034 future.destroy(gpa);
2035 start(context.ptr, result.ptr);2035 start(context.ptr, result.ptr);
2036 return null;2036 return null;
...@@ -2044,7 +2044,7 @@ fn async(...@@ -2044,7 +2044,7 @@ fn async(
2044 const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch {2044 const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch {
2045 t.wait_group.finish();2045 t.wait_group.finish();
2046 t.busy_count = busy_count;2046 t.busy_count = busy_count;
2047 mutexUnlockInternal(&t.mutex);2047 mutexUnlock(&t.mutex);
2048 future.destroy(gpa);2048 future.destroy(gpa);
2049 start(context.ptr, result.ptr);2049 start(context.ptr, result.ptr);
2050 return null;2050 return null;
...@@ -2054,7 +2054,7 @@ fn async(...@@ -2054,7 +2054,7 @@ fn async(
20542054
2055 t.run_queue.prepend(&future.runnable.node);2055 t.run_queue.prepend(&future.runnable.node);
20562056
2057 mutexUnlockInternal(&t.mutex);2057 mutexUnlock(&t.mutex);
2058 condSignal(&t.cond);2058 condSignal(&t.cond);
2059 return @ptrCast(future);2059 return @ptrCast(future);
2060}2060}
...@@ -2077,8 +2077,8 @@ fn concurrent(...@@ -2077,8 +2077,8 @@ fn concurrent(
2077 };2077 };
2078 errdefer future.destroy(gpa);2078 errdefer future.destroy(gpa);
20792079
2080 mutexLockInternal(&t.mutex);2080 mutexLock(&t.mutex);
2081 defer mutexUnlockInternal(&t.mutex);2081 defer mutexUnlock(&t.mutex);
20822082
2083 const busy_count = t.busy_count;2083 const busy_count = t.busy_count;
20842084
...@@ -2122,12 +2122,12 @@ fn groupAsync(...@@ -2122,12 +2122,12 @@ fn groupAsync(
2122 error.OutOfMemory => return groupAsyncEager(start, context.ptr),2122 error.OutOfMemory => return groupAsyncEager(start, context.ptr),
2123 };2123 };
21242124
2125 mutexLockInternal(&t.mutex);2125 mutexLock(&t.mutex);
21262126
2127 const busy_count = t.busy_count;2127 const busy_count = t.busy_count;
21282128
2129 if (busy_count >= @intFromEnum(t.async_limit)) {2129 if (busy_count >= @intFromEnum(t.async_limit)) {
2130 mutexUnlockInternal(&t.mutex);2130 mutexUnlock(&t.mutex);
2131 task.destroy(gpa);2131 task.destroy(gpa);
2132 return groupAsyncEager(start, context.ptr);2132 return groupAsyncEager(start, context.ptr);
2133 }2133 }
...@@ -2140,7 +2140,7 @@ fn groupAsync(...@@ -2140,7 +2140,7 @@ fn groupAsync(
2140 const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch {2140 const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch {
2141 t.wait_group.finish();2141 t.wait_group.finish();
2142 t.busy_count = busy_count;2142 t.busy_count = busy_count;
2143 mutexUnlockInternal(&t.mutex);2143 mutexUnlock(&t.mutex);
2144 task.destroy(gpa);2144 task.destroy(gpa);
2145 return groupAsyncEager(start, context.ptr);2145 return groupAsyncEager(start, context.ptr);
2146 };2146 };
...@@ -2157,7 +2157,7 @@ fn groupAsync(...@@ -2157,7 +2157,7 @@ fn groupAsync(
2157 }, .monotonic);2157 }, .monotonic);
2158 t.run_queue.prepend(&task.runnable.node);2158 t.run_queue.prepend(&task.runnable.node);
21592159
2160 mutexUnlockInternal(&t.mutex);2160 mutexUnlock(&t.mutex);
2161 condSignal(&t.cond);2161 condSignal(&t.cond);
2162}2162}
2163fn groupAsyncEager(2163fn groupAsyncEager(
...@@ -2222,8 +2222,8 @@ fn groupConcurrent(...@@ -2222,8 +2222,8 @@ fn groupConcurrent(
2222 };2222 };
2223 errdefer task.destroy(gpa);2223 errdefer task.destroy(gpa);
22242224
2225 mutexLockInternal(&t.mutex);2225 mutexLock(&t.mutex);
2226 defer mutexUnlockInternal(&t.mutex);2226 defer mutexUnlock(&t.mutex);
22272227
2228 const busy_count = t.busy_count;2228 const busy_count = t.busy_count;
22292229
...@@ -3847,8 +3847,8 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {...@@ -3847,8 +3847,8 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
38473847
3848fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION {3848fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION {
3849 if (!t.system_basic_information.initialized.load(.acquire)) {3849 if (!t.system_basic_information.initialized.load(.acquire)) {
3850 mutexLockInternal(&t.mutex);3850 mutexLock(&t.mutex);
3851 defer mutexUnlockInternal(&t.mutex);3851 defer mutexUnlock(&t.mutex);
38523852
3853 switch (windows.ntdll.NtQuerySystemInformation(3853 switch (windows.ntdll.NtQuerySystemInformation(
3854 .SystemBasicInformation,3854 .SystemBasicInformation,
...@@ -14359,10 +14359,9 @@ const Wsa = struct {...@@ -14359,10 +14359,9 @@ const Wsa = struct {
14359};14359};
1436014360
14361fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {14361fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
14362 const t_io = io(t);
14363 const wsa = &t.wsa;14362 const wsa = &t.wsa;
14364 try wsa.mutex.lock(t_io);14363 try mutexLock(&wsa.mutex);
14365 defer wsa.mutex.unlock(t_io);14364 defer mutexUnlock(&wsa.mutex);
14366 switch (wsa.status) {14365 switch (wsa.status) {
14367 .uninitialized => {14366 .uninitialized => {
14368 var wsa_data: ws2_32.WSADATA = undefined;14367 var wsa_data: ws2_32.WSADATA = undefined;
...@@ -14433,8 +14432,8 @@ const WindowsEnvironStrings = struct {...@@ -14433,8 +14432,8 @@ const WindowsEnvironStrings = struct {
14433};14432};
1443414433
14435fn scanEnviron(t: *Threaded) void {14434fn scanEnviron(t: *Threaded) void {
14436 mutexLockInternal(&t.mutex);14435 mutexLock(&t.mutex);
14437 defer mutexUnlockInternal(&t.mutex);14436 defer mutexUnlock(&t.mutex);
1443814437
14439 if (t.environ.initialized) return;14438 if (t.environ.initialized) return;
14440 t.environ.initialized = true;14439 t.environ.initialized = true;
...@@ -14789,8 +14788,8 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp...@@ -14789,8 +14788,8 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp
1478914788
14790fn getDevNullFd(t: *Threaded) !posix.fd_t {14789fn getDevNullFd(t: *Threaded) !posix.fd_t {
14791 {14790 {
14792 mutexLockInternal(&t.mutex);14791 mutexLock(&t.mutex);
14793 defer mutexUnlockInternal(&t.mutex);14792 defer mutexUnlock(&t.mutex);
14794 if (t.null_file.fd != -1) return t.null_file.fd;14793 if (t.null_file.fd != -1) return t.null_file.fd;
14795 }14794 }
14796 const mode: u32 = 0;14795 const mode: u32 = 0;
...@@ -14801,8 +14800,8 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t {...@@ -14801,8 +14800,8 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t {
14801 .SUCCESS => {14800 .SUCCESS => {
14802 syscall.finish();14801 syscall.finish();
14803 const fresh_fd: posix.fd_t = @intCast(rc);14802 const fresh_fd: posix.fd_t = @intCast(rc);
14804 mutexLockInternal(&t.mutex); // Another thread might have won the race.14803 mutexLock(&t.mutex); // Another thread might have won the race.
14805 defer mutexUnlockInternal(&t.mutex);14804 defer mutexUnlock(&t.mutex);
14806 if (t.null_file.fd != -1) {14805 if (t.null_file.fd != -1) {
14807 posix.close(fresh_fd);14806 posix.close(fresh_fd);
14808 return t.null_file.fd;14807 return t.null_file.fd;
...@@ -15462,8 +15461,8 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro...@@ -15462,8 +15461,8 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
1546215461
15463fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE {15462fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE {
15464 {15463 {
15465 mutexLockInternal(&t.mutex);15464 mutexLock(&t.mutex);
15466 defer mutexUnlockInternal(&t.mutex);15465 defer mutexUnlock(&t.mutex);
15467 if (t.random_file.handle) |handle| return handle;15466 if (t.random_file.handle) |handle| return handle;
15468 }15467 }
1546915468
...@@ -15497,8 +15496,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE {...@@ -15497,8 +15496,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE {
15497 )) {15496 )) {
15498 .SUCCESS => {15497 .SUCCESS => {
15499 syscall.finish();15498 syscall.finish();
15500 mutexLockInternal(&t.mutex); // Another thread might have won the race.15499 mutexLock(&t.mutex); // Another thread might have won the race.
15501 defer mutexUnlockInternal(&t.mutex);15500 defer mutexUnlock(&t.mutex);
15502 if (t.random_file.handle) |prev_handle| {15501 if (t.random_file.handle) |prev_handle| {
15503 windows.CloseHandle(fresh_handle);15502 windows.CloseHandle(fresh_handle);
15504 return prev_handle;15503 return prev_handle;
...@@ -15518,8 +15517,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE {...@@ -15518,8 +15517,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE {
1551815517
15519fn getNulHandle(t: *Threaded) !windows.HANDLE {15518fn getNulHandle(t: *Threaded) !windows.HANDLE {
15520 {15519 {
15521 mutexLockInternal(&t.mutex);15520 mutexLock(&t.mutex);
15522 defer mutexUnlockInternal(&t.mutex);15521 defer mutexUnlock(&t.mutex);
15523 if (t.null_file.handle) |handle| return handle;15522 if (t.null_file.handle) |handle| return handle;
15524 }15523 }
1552515524
...@@ -15565,8 +15564,8 @@ fn getNulHandle(t: *Threaded) !windows.HANDLE {...@@ -15565,8 +15564,8 @@ fn getNulHandle(t: *Threaded) !windows.HANDLE {
15565 )) {15564 )) {
15566 .SUCCESS => {15565 .SUCCESS => {
15567 syscall.finish();15566 syscall.finish();
15568 mutexLockInternal(&t.mutex); // Another thread might have won the race.15567 mutexLock(&t.mutex); // Another thread might have won the race.
15569 defer mutexUnlockInternal(&t.mutex);15568 defer mutexUnlock(&t.mutex);
15570 if (t.null_file.handle) |prev_handle| {15569 if (t.null_file.handle) |prev_handle| {
15571 windows.CloseHandle(fresh_handle);15570 windows.CloseHandle(fresh_handle);
15572 return prev_handle;15571 return prev_handle;
...@@ -16611,15 +16610,15 @@ fn random(userdata: ?*anyopaque, buffer: []u8) void {...@@ -16611,15 +16610,15 @@ fn random(userdata: ?*anyopaque, buffer: []u8) void {
16611}16610}
1661216611
16613fn randomMainThread(t: *Threaded, buffer: []u8) void {16612fn randomMainThread(t: *Threaded, buffer: []u8) void {
16614 mutexLockInternal(&t.mutex);16613 mutexLock(&t.mutex);
16615 defer mutexUnlockInternal(&t.mutex);16614 defer mutexUnlock(&t.mutex);
1661616615
16617 if (!t.csprng.isInitialized()) {16616 if (!t.csprng.isInitialized()) {
16618 @branchHint(.unlikely);16617 @branchHint(.unlikely);
16619 var seed: [Csprng.seed_len]u8 = undefined;16618 var seed: [Csprng.seed_len]u8 = undefined;
16620 {16619 {
16621 mutexUnlockInternal(&t.mutex);16620 mutexUnlock(&t.mutex);
16622 defer mutexLockInternal(&t.mutex);16621 defer mutexLock(&t.mutex);
1662316622
16624 const prev = swapCancelProtection(t, .blocked);16623 const prev = swapCancelProtection(t, .blocked);
16625 defer _ = swapCancelProtection(t, prev);16624 defer _ = swapCancelProtection(t, prev);
...@@ -16804,8 +16803,8 @@ fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void {...@@ -16804,8 +16803,8 @@ fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void {
1680416803
16805fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {16804fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {
16806 {16805 {
16807 mutexLockInternal(&t.mutex);16806 mutexLock(&t.mutex);
16808 defer mutexUnlockInternal(&t.mutex);16807 defer mutexUnlock(&t.mutex);
1680916808
16810 if (t.random_file.fd == -2) return error.EntropyUnavailable;16809 if (t.random_file.fd == -2) return error.EntropyUnavailable;
16811 if (t.random_file.fd != -1) return t.random_file.fd;16810 if (t.random_file.fd != -1) return t.random_file.fd;
...@@ -16845,8 +16844,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {...@@ -16845,8 +16844,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {
16845 .SUCCESS => {16844 .SUCCESS => {
16846 syscall.finish();16845 syscall.finish();
16847 if (!statx.mask.TYPE) return error.EntropyUnavailable;16846 if (!statx.mask.TYPE) return error.EntropyUnavailable;
16848 mutexLockInternal(&t.mutex); // Another thread might have won the race.16847 mutexLock(&t.mutex); // Another thread might have won the race.
16849 defer mutexUnlockInternal(&t.mutex);16848 defer mutexUnlock(&t.mutex);
16850 if (t.random_file.fd >= 0) {16849 if (t.random_file.fd >= 0) {
16851 posix.close(fd);16850 posix.close(fd);
16852 return t.random_file.fd;16851 return t.random_file.fd;
...@@ -16873,8 +16872,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {...@@ -16873,8 +16872,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {
16873 switch (posix.errno(fstat_sym(fd, &stat))) {16872 switch (posix.errno(fstat_sym(fd, &stat))) {
16874 .SUCCESS => {16873 .SUCCESS => {
16875 syscall.finish();16874 syscall.finish();
16876 mutexLockInternal(&t.mutex); // Another thread might have won the race.16875 mutexLock(&t.mutex); // Another thread might have won the race.
16877 defer mutexUnlockInternal(&t.mutex);16876 defer mutexUnlock(&t.mutex);
16878 if (t.random_file.fd >= 0) {16877 if (t.random_file.fd >= 0) {
16879 posix.close(fd);16878 posix.close(fd);
16880 return t.random_file.fd;16879 return t.random_file.fd;
...@@ -16938,7 +16937,7 @@ const parking_futex = struct {...@@ -16938,7 +16937,7 @@ const parking_futex = struct {
16938 /// avoid a race.16937 /// avoid a race.
16939 num_waiters: std.atomic.Value(u32),16938 num_waiters: std.atomic.Value(u32),
16940 /// Protects `waiters`.16939 /// Protects `waiters`.
16941 mutex: Mutex,16940 mutex: Io.Mutex,
16942 waiters: std.DoublyLinkedList,16941 waiters: std.DoublyLinkedList,
1694316942
16944 /// Prevent false sharing between buckets.16943 /// Prevent false sharing between buckets.
...@@ -17007,8 +17006,8 @@ const parking_futex = struct {...@@ -17007,8 +17006,8 @@ const parking_futex = struct {
17007 var status_buf: std.atomic.Value(Thread.Status) = undefined;17006 var status_buf: std.atomic.Value(Thread.Status) = undefined;
1700817007
17009 {17008 {
17010 mutexLockInternal(&bucket.mutex);17009 mutexLock(&bucket.mutex);
17011 defer mutexUnlockInternal(&bucket.mutex);17010 defer mutexUnlock(&bucket.mutex);
1701217011
17013 _ = bucket.num_waiters.fetchAdd(1, .acquire);17012 _ = bucket.num_waiters.fetchAdd(1, .acquire);
1701417013
...@@ -17077,8 +17076,8 @@ const parking_futex = struct {...@@ -17077,8 +17076,8 @@ const parking_futex = struct {
17077 .parked => {17076 .parked => {
17078 // We saw a timeout and updated our own status from `.parked` to `.none`. It is17077 // We saw a timeout and updated our own status from `.parked` to `.none`. It is
17079 // our responsibility to remove `waiter` from `bucket`.17078 // our responsibility to remove `waiter` from `bucket`.
17080 mutexLockInternal(&bucket.mutex);17079 mutexLock(&bucket.mutex);
17081 defer mutexUnlockInternal(&bucket.mutex);17080 defer mutexUnlock(&bucket.mutex);
17082 bucket.waiters.remove(&waiter.node);17081 bucket.waiters.remove(&waiter.node);
17083 assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0);17082 assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0);
17084 },17083 },
...@@ -17117,8 +17116,8 @@ const parking_futex = struct {...@@ -17117,8 +17116,8 @@ const parking_futex = struct {
17117 // of the critical section. This forms a singly-linked list of waiters using `Waiter.node.next`.17116 // of the critical section. This forms a singly-linked list of waiters using `Waiter.node.next`.
17118 var waking_head: ?*std.DoublyLinkedList.Node = null;17117 var waking_head: ?*std.DoublyLinkedList.Node = null;
17119 {17118 {
17120 mutexLockInternal(&bucket.mutex);17119 mutexLock(&bucket.mutex);
17121 defer mutexUnlockInternal(&bucket.mutex);17120 defer mutexUnlock(&bucket.mutex);
1712217121
17123 var num_removed: u32 = 0;17122 var num_removed: u32 = 0;
17124 var it = bucket.waiters.first;17123 var it = bucket.waiters.first;
...@@ -17173,8 +17172,8 @@ const parking_futex = struct {...@@ -17173,8 +17172,8 @@ const parking_futex = struct {
1717317172
17174 fn removeCanceledWaiter(waiter: *Waiter) void {17173 fn removeCanceledWaiter(waiter: *Waiter) void {
17175 const bucket = bucketForAddress(waiter.address);17174 const bucket = bucketForAddress(waiter.address);
17176 mutexLockInternal(&bucket.mutex);17175 mutexLock(&bucket.mutex);
17177 defer mutexUnlockInternal(&bucket.mutex);17176 defer mutexUnlock(&bucket.mutex);
17178 bucket.waiters.remove(&waiter.node);17177 bucket.waiters.remove(&waiter.node);
17179 assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0);17178 assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0);
17180 waiter.done.store(true, .release); // potentially invalidates `waiter.*`17179 waiter.done.store(true, .release); // potentially invalidates `waiter.*`
...@@ -18160,14 +18159,8 @@ fn eventSet(event: *Io.Event) void {...@@ -18160,14 +18159,8 @@ fn eventSet(event: *Io.Event) void {
18160 }18159 }
18161}18160}
1816218161
18163const Condition = if (!is_windows) Io.Condition else struct {
18164 condition: windows.CONDITION_VARIABLE,
18165 const init: @This() = .{ .condition = .{} };
18166};
18167
18168/// Same as `Io.Condition.broadcast` but avoids the VTable.18162/// Same as `Io.Condition.broadcast` but avoids the VTable.
18169fn condBroadcast(cond: *Condition) void {18163fn condBroadcast(cond: *Io.Condition) void {
18170 if (is_windows) return windows.ntdll.RtlWakeAllConditionVariable(&cond.condition);
18171 var prev_state = cond.state.load(.monotonic);18164 var prev_state = cond.state.load(.monotonic);
18172 while (prev_state.waiters > prev_state.signals) {18165 while (prev_state.waiters > prev_state.signals) {
18173 @branchHint(.unlikely);18166 @branchHint(.unlikely);
...@@ -18187,8 +18180,7 @@ fn condBroadcast(cond: *Condition) void {...@@ -18187,8 +18180,7 @@ fn condBroadcast(cond: *Condition) void {
18187}18180}
1818818181
18189/// Same as `Io.Condition.signal` but avoids the VTable.18182/// Same as `Io.Condition.signal` but avoids the VTable.
18190fn condSignal(cond: *Condition) void {18183fn condSignal(cond: *Io.Condition) void {
18191 if (is_windows) return windows.ntdll.RtlWakeConditionVariable(&cond.condition);
18192 var prev_state = cond.state.load(.monotonic);18184 var prev_state = cond.state.load(.monotonic);
18193 while (prev_state.waiters > prev_state.signals) {18185 while (prev_state.waiters > prev_state.signals) {
18194 @branchHint(.unlikely);18186 @branchHint(.unlikely);
...@@ -18208,11 +18200,7 @@ fn condSignal(cond: *Condition) void {...@@ -18208,11 +18200,7 @@ fn condSignal(cond: *Condition) void {
18208}18200}
1820918201
18210/// Same as `Io.Condition.waitUncancelable` but avoids the VTable.18202/// Same as `Io.Condition.waitUncancelable` but avoids the VTable.
18211fn condWait(cond: *Condition, mutex: *Mutex) void {18203fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void {
18212 if (is_windows) {
18213 _ = windows.kernel32.SleepConditionVariableSRW(&cond.condition, &mutex.srwlock, windows.INFINITE, 0);
18214 return;
18215 }
18216 var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load18204 var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load
1821718205
18218 {18206 {
...@@ -18220,8 +18208,8 @@ fn condWait(cond: *Condition, mutex: *Mutex) void {...@@ -18220,8 +18208,8 @@ fn condWait(cond: *Condition, mutex: *Mutex) void {
18220 assert(prev_state.waiters < std.math.maxInt(u16)); // overflow caused by too many waiters18208 assert(prev_state.waiters < std.math.maxInt(u16)); // overflow caused by too many waiters
18221 }18209 }
1822218210
18223 mutexUnlockInternal(mutex);18211 mutexUnlock(mutex);
18224 defer mutexLockInternal(mutex);18212 defer mutexLock(mutex);
1822518213
18226 while (true) {18214 while (true) {
18227 Thread.futexWaitUncancelable(&cond.epoch.raw, epoch, null);18215 Thread.futexWaitUncancelable(&cond.epoch.raw, epoch, null);
...@@ -18241,16 +18229,6 @@ fn condWait(cond: *Condition, mutex: *Mutex) void {...@@ -18241,16 +18229,6 @@ fn condWait(cond: *Condition, mutex: *Mutex) void {
18241 }18229 }
18242}18230}
1824318231
18244const Mutex = if (!is_windows) Io.Mutex else struct {
18245 srwlock: windows.SRWLOCK,
18246 const init: @This() = .{ .srwlock = .{} };
18247};
18248
18249fn mutexLockInternal(m: *Mutex) void {
18250 if (is_windows) return windows.ntdll.RtlAcquireSRWLockExclusive(&m.srwlock);
18251 return mutexLock(m);
18252}
18253
18254/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.18232/// Same as `Io.Mutex.lockUncancelable` but avoids the VTable.
18255pub fn mutexLock(m: *Io.Mutex) void {18233pub fn mutexLock(m: *Io.Mutex) void {
18256 const initial_state = m.state.cmpxchgWeak(18234 const initial_state = m.state.cmpxchgWeak(
...@@ -18270,11 +18248,6 @@ pub fn mutexLock(m: *Io.Mutex) void {...@@ -18270,11 +18248,6 @@ pub fn mutexLock(m: *Io.Mutex) void {
18270 }18248 }
18271}18249}
1827218250
18273fn mutexUnlockInternal(m: *Mutex) void {
18274 if (is_windows) return windows.ntdll.RtlReleaseSRWLockExclusive(&m.srwlock);
18275 return mutexUnlock(m);
18276}
18277
18278/// Same as `Io.Mutex.unlock` but avoids the VTable.18251/// Same as `Io.Mutex.unlock` but avoids the VTable.
18279pub fn mutexUnlock(m: *Io.Mutex) void {18252pub fn mutexUnlock(m: *Io.Mutex) void {
18280 switch (m.state.swap(.unlocked, .release)) {18253 switch (m.state.swap(.unlocked, .release)) {