| ... | @@ -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 targets | 29 | /// * scanning environment variables on some targets |
| 30 | /// * memory-mapping when mmap or equivalent is not available | 30 | /// * memory-mapping when mmap or equivalent is not available |
| 31 | allocator: Allocator, | 31 | allocator: Allocator, |
| 32 | mutex: std.Thread.Mutex = .{}, | 32 | mutex: Io.Mutex = .init, |
| 33 | cond: std.Thread.Condition = .{}, | 33 | cond: Io.Condition = .init, |
| 34 | run_queue: std.SinglyLinkedList = .{}, | 34 | run_queue: std.SinglyLinkedList = .{}, |
| 35 | join_requested: bool = false, | 35 | join_requested: bool = false, |
| 36 | stack_size: usize, | 36 | stack_size: usize, |
| ... | @@ -1486,8 +1486,8 @@ var global_single_threaded_instance: Threaded = .init_single_threaded; | ... | @@ -1486,8 +1486,8 @@ var global_single_threaded_instance: Threaded = .init_single_threaded; |
| 1486 | pub const global_single_threaded: *Threaded = &global_single_threaded_instance; | 1486 | pub const global_single_threaded: *Threaded = &global_single_threaded_instance; |
| 1487 | | 1487 | |
| 1488 | pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void { | 1488 | pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void { |
| 1489 | t.mutex.lock(); | 1489 | mutexLockUncancelable(&t.mutex); |
| 1490 | defer t.mutex.unlock(); | 1490 | defer mutexUnlock(&t.mutex); |
| 1491 | t.async_limit = new_limit; | 1491 | t.async_limit = new_limit; |
| 1492 | } | 1492 | } |
| 1493 | | 1493 | |
| ... | @@ -1508,11 +1508,11 @@ pub fn deinit(t: *Threaded) void { | ... | @@ -1508,11 +1508,11 @@ pub fn deinit(t: *Threaded) void { |
| 1508 | fn join(t: *Threaded) void { | 1508 | fn join(t: *Threaded) void { |
| 1509 | if (builtin.single_threaded) return; | 1509 | if (builtin.single_threaded) return; |
| 1510 | { | 1510 | { |
| 1511 | t.mutex.lock(); | 1511 | mutexLockUncancelable(&t.mutex); |
| 1512 | defer t.mutex.unlock(); | 1512 | defer mutexUnlock(&t.mutex); |
| 1513 | t.join_requested = true; | 1513 | t.join_requested = true; |
| 1514 | } | 1514 | } |
| 1515 | t.cond.broadcast(); | 1515 | condBroadcast(&t.cond); |
| 1516 | t.wait_group.wait(); | 1516 | t.wait_group.wait(); |
| 1517 | } | 1517 | } |
| 1518 | | 1518 | |
| ... | @@ -1574,20 +1574,20 @@ fn worker(t: *Threaded) void { | ... | @@ -1574,20 +1574,20 @@ fn worker(t: *Threaded) void { |
| 1574 | | 1574 | |
| 1575 | defer t.wait_group.finish(); | 1575 | defer t.wait_group.finish(); |
| 1576 | | 1576 | |
| 1577 | t.mutex.lock(); | 1577 | mutexLockUncancelable(&t.mutex); |
| 1578 | defer t.mutex.unlock(); | 1578 | defer mutexUnlock(&t.mutex); |
| 1579 | | 1579 | |
| 1580 | while (true) { | 1580 | while (true) { |
| 1581 | while (t.run_queue.popFirst()) |runnable_node| { | 1581 | while (t.run_queue.popFirst()) |runnable_node| { |
| 1582 | t.mutex.unlock(); | 1582 | mutexUnlock(&t.mutex); |
| 1583 | thread.cancel_protection = .unblocked; | 1583 | thread.cancel_protection = .unblocked; |
| 1584 | const runnable: *Runnable = @fieldParentPtr("node", runnable_node); | 1584 | const runnable: *Runnable = @fieldParentPtr("node", runnable_node); |
| 1585 | runnable.startFn(runnable, &thread, t); | 1585 | runnable.startFn(runnable, &thread, t); |
| 1586 | t.mutex.lock(); | 1586 | mutexLockUncancelable(&t.mutex); |
| 1587 | t.busy_count -= 1; | 1587 | t.busy_count -= 1; |
| 1588 | } | 1588 | } |
| 1589 | if (t.join_requested) break; | 1589 | if (t.join_requested) break; |
| 1590 | t.cond.wait(&t.mutex); | 1590 | condWait(&t.cond, &t.mutex); |
| 1591 | } | 1591 | } |
| 1592 | } | 1592 | } |
| 1593 | | 1593 | |
| ... | @@ -2004,12 +2004,12 @@ fn async( | ... | @@ -2004,12 +2004,12 @@ fn async( |
| 2004 | }, | 2004 | }, |
| 2005 | }; | 2005 | }; |
| 2006 | | 2006 | |
| 2007 | t.mutex.lock(); | 2007 | mutexLockUncancelable(&t.mutex); |
| 2008 | | 2008 | |
| 2009 | const busy_count = t.busy_count; | 2009 | const busy_count = t.busy_count; |
| 2010 | | 2010 | |
| 2011 | if (busy_count >= @intFromEnum(t.async_limit)) { | 2011 | if (busy_count >= @intFromEnum(t.async_limit)) { |
| 2012 | t.mutex.unlock(); | 2012 | mutexUnlock(&t.mutex); |
| 2013 | future.destroy(gpa); | 2013 | future.destroy(gpa); |
| 2014 | start(context.ptr, result.ptr); | 2014 | start(context.ptr, result.ptr); |
| 2015 | return null; | 2015 | return null; |
| ... | @@ -2023,7 +2023,7 @@ fn async( | ... | @@ -2023,7 +2023,7 @@ fn async( |
| 2023 | const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch { | 2023 | const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch { |
| 2024 | t.wait_group.finish(); | 2024 | t.wait_group.finish(); |
| 2025 | t.busy_count = busy_count; | 2025 | t.busy_count = busy_count; |
| 2026 | t.mutex.unlock(); | 2026 | mutexUnlock(&t.mutex); |
| 2027 | future.destroy(gpa); | 2027 | future.destroy(gpa); |
| 2028 | start(context.ptr, result.ptr); | 2028 | start(context.ptr, result.ptr); |
| 2029 | return null; | 2029 | return null; |
| ... | @@ -2033,8 +2033,8 @@ fn async( | ... | @@ -2033,8 +2033,8 @@ fn async( |
| 2033 | | 2033 | |
| 2034 | t.run_queue.prepend(&future.runnable.node); | 2034 | t.run_queue.prepend(&future.runnable.node); |
| 2035 | | 2035 | |
| 2036 | t.mutex.unlock(); | 2036 | mutexUnlock(&t.mutex); |
| 2037 | t.cond.signal(); | 2037 | condSignal(&t.cond); |
| 2038 | return @ptrCast(future); | 2038 | return @ptrCast(future); |
| 2039 | } | 2039 | } |
| 2040 | | 2040 | |
| ... | @@ -2056,8 +2056,8 @@ fn concurrent( | ... | @@ -2056,8 +2056,8 @@ fn concurrent( |
| 2056 | }; | 2056 | }; |
| 2057 | errdefer future.destroy(gpa); | 2057 | errdefer future.destroy(gpa); |
| 2058 | | 2058 | |
| 2059 | t.mutex.lock(); | 2059 | mutexLockUncancelable(&t.mutex); |
| 2060 | defer t.mutex.unlock(); | 2060 | defer mutexUnlock(&t.mutex); |
| 2061 | | 2061 | |
| 2062 | const busy_count = t.busy_count; | 2062 | const busy_count = t.busy_count; |
| 2063 | | 2063 | |
| ... | @@ -2080,7 +2080,7 @@ fn concurrent( | ... | @@ -2080,7 +2080,7 @@ fn concurrent( |
| 2080 | | 2080 | |
| 2081 | t.run_queue.prepend(&future.runnable.node); | 2081 | t.run_queue.prepend(&future.runnable.node); |
| 2082 | | 2082 | |
| 2083 | t.cond.signal(); | 2083 | condSignal(&t.cond); |
| 2084 | return @ptrCast(future); | 2084 | return @ptrCast(future); |
| 2085 | } | 2085 | } |
| 2086 | | 2086 | |
| ... | @@ -2101,12 +2101,12 @@ fn groupAsync( | ... | @@ -2101,12 +2101,12 @@ fn groupAsync( |
| 2101 | error.OutOfMemory => return groupAsyncEager(start, context.ptr), | 2101 | error.OutOfMemory => return groupAsyncEager(start, context.ptr), |
| 2102 | }; | 2102 | }; |
| 2103 | | 2103 | |
| 2104 | t.mutex.lock(); | 2104 | mutexLockUncancelable(&t.mutex); |
| 2105 | | 2105 | |
| 2106 | const busy_count = t.busy_count; | 2106 | const busy_count = t.busy_count; |
| 2107 | | 2107 | |
| 2108 | if (busy_count >= @intFromEnum(t.async_limit)) { | 2108 | if (busy_count >= @intFromEnum(t.async_limit)) { |
| 2109 | t.mutex.unlock(); | 2109 | mutexUnlock(&t.mutex); |
| 2110 | task.destroy(gpa); | 2110 | task.destroy(gpa); |
| 2111 | return groupAsyncEager(start, context.ptr); | 2111 | return groupAsyncEager(start, context.ptr); |
| 2112 | } | 2112 | } |
| ... | @@ -2119,7 +2119,7 @@ fn groupAsync( | ... | @@ -2119,7 +2119,7 @@ fn groupAsync( |
| 2119 | const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch { | 2119 | const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch { |
| 2120 | t.wait_group.finish(); | 2120 | t.wait_group.finish(); |
| 2121 | t.busy_count = busy_count; | 2121 | t.busy_count = busy_count; |
| 2122 | t.mutex.unlock(); | 2122 | mutexUnlock(&t.mutex); |
| 2123 | task.destroy(gpa); | 2123 | task.destroy(gpa); |
| 2124 | return groupAsyncEager(start, context.ptr); | 2124 | return groupAsyncEager(start, context.ptr); |
| 2125 | }; | 2125 | }; |
| ... | @@ -2136,8 +2136,8 @@ fn groupAsync( | ... | @@ -2136,8 +2136,8 @@ fn groupAsync( |
| 2136 | }, .monotonic); | 2136 | }, .monotonic); |
| 2137 | t.run_queue.prepend(&task.runnable.node); | 2137 | t.run_queue.prepend(&task.runnable.node); |
| 2138 | | 2138 | |
| 2139 | t.mutex.unlock(); | 2139 | mutexUnlock(&t.mutex); |
| 2140 | t.cond.signal(); | 2140 | condSignal(&t.cond); |
| 2141 | } | 2141 | } |
| 2142 | fn groupAsyncEager( | 2142 | fn groupAsyncEager( |
| 2143 | start: *const fn (context: *const anyopaque) Io.Cancelable!void, | 2143 | start: *const fn (context: *const anyopaque) Io.Cancelable!void, |
| ... | @@ -2201,8 +2201,8 @@ fn groupConcurrent( | ... | @@ -2201,8 +2201,8 @@ fn groupConcurrent( |
| 2201 | }; | 2201 | }; |
| 2202 | errdefer task.destroy(gpa); | 2202 | errdefer task.destroy(gpa); |
| 2203 | | 2203 | |
| 2204 | t.mutex.lock(); | 2204 | mutexLockUncancelable(&t.mutex); |
| 2205 | defer t.mutex.unlock(); | 2205 | defer mutexUnlock(&t.mutex); |
| 2206 | | 2206 | |
| 2207 | const busy_count = t.busy_count; | 2207 | const busy_count = t.busy_count; |
| 2208 | | 2208 | |
| ... | @@ -2233,7 +2233,7 @@ fn groupConcurrent( | ... | @@ -2233,7 +2233,7 @@ fn groupConcurrent( |
| 2233 | }, .monotonic); | 2233 | }, .monotonic); |
| 2234 | t.run_queue.prepend(&task.runnable.node); | 2234 | t.run_queue.prepend(&task.runnable.node); |
| 2235 | | 2235 | |
| 2236 | t.cond.signal(); | 2236 | condSignal(&t.cond); |
| 2237 | } | 2237 | } |
| 2238 | | 2238 | |
| 2239 | fn groupAwait(userdata: ?*anyopaque, type_erased: *Io.Group, initial_token: *anyopaque) Io.Cancelable!void { | 2239 | fn groupAwait(userdata: ?*anyopaque, type_erased: *Io.Group, initial_token: *anyopaque) Io.Cancelable!void { |
| ... | @@ -3838,8 +3838,8 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { | ... | @@ -3838,8 +3838,8 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 3838 | | 3838 | |
| 3839 | fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION { | 3839 | fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION { |
| 3840 | if (!t.system_basic_information.initialized.load(.acquire)) { | 3840 | if (!t.system_basic_information.initialized.load(.acquire)) { |
| 3841 | t.mutex.lock(); | 3841 | mutexLockUncancelable(&t.mutex); |
| 3842 | defer t.mutex.unlock(); | 3842 | defer mutexUnlock(&t.mutex); |
| 3843 | | 3843 | |
| 3844 | switch (windows.ntdll.NtQuerySystemInformation( | 3844 | switch (windows.ntdll.NtQuerySystemInformation( |
| 3845 | .SystemBasicInformation, | 3845 | .SystemBasicInformation, |
| ... | @@ -14299,10 +14299,9 @@ const Wsa = struct { | ... | @@ -14299,10 +14299,9 @@ const Wsa = struct { |
| 14299 | }; | 14299 | }; |
| 14300 | | 14300 | |
| 14301 | fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void { | 14301 | fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void { |
| 14302 | const t_io = io(t); | | |
| 14303 | const wsa = &t.wsa; | 14302 | const wsa = &t.wsa; |
| 14304 | try wsa.mutex.lock(t_io); | 14303 | try mutexLock(&wsa.mutex); |
| 14305 | defer wsa.mutex.unlock(t_io); | 14304 | defer mutexUnlock(&wsa.mutex); |
| 14306 | switch (wsa.status) { | 14305 | switch (wsa.status) { |
| 14307 | .uninitialized => { | 14306 | .uninitialized => { |
| 14308 | var wsa_data: ws2_32.WSADATA = undefined; | 14307 | var wsa_data: ws2_32.WSADATA = undefined; |
| ... | @@ -14373,8 +14372,8 @@ const WindowsEnvironStrings = struct { | ... | @@ -14373,8 +14372,8 @@ const WindowsEnvironStrings = struct { |
| 14373 | }; | 14372 | }; |
| 14374 | | 14373 | |
| 14375 | fn scanEnviron(t: *Threaded) void { | 14374 | fn scanEnviron(t: *Threaded) void { |
| 14376 | t.mutex.lock(); | 14375 | mutexLockUncancelable(&t.mutex); |
| 14377 | defer t.mutex.unlock(); | 14376 | defer mutexUnlock(&t.mutex); |
| 14378 | | 14377 | |
| 14379 | if (t.environ.initialized) return; | 14378 | if (t.environ.initialized) return; |
| 14380 | t.environ.initialized = true; | 14379 | t.environ.initialized = true; |
| ... | @@ -14729,8 +14728,8 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp | ... | @@ -14729,8 +14728,8 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp |
| 14729 | | 14728 | |
| 14730 | fn getDevNullFd(t: *Threaded) !posix.fd_t { | 14729 | fn getDevNullFd(t: *Threaded) !posix.fd_t { |
| 14731 | { | 14730 | { |
| 14732 | t.mutex.lock(); | 14731 | mutexLockUncancelable(&t.mutex); |
| 14733 | defer t.mutex.unlock(); | 14732 | defer mutexUnlock(&t.mutex); |
| 14734 | if (t.null_file.fd != -1) return t.null_file.fd; | 14733 | if (t.null_file.fd != -1) return t.null_file.fd; |
| 14735 | } | 14734 | } |
| 14736 | const mode: u32 = 0; | 14735 | const mode: u32 = 0; |
| ... | @@ -14741,8 +14740,8 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t { | ... | @@ -14741,8 +14740,8 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t { |
| 14741 | .SUCCESS => { | 14740 | .SUCCESS => { |
| 14742 | syscall.finish(); | 14741 | syscall.finish(); |
| 14743 | const fresh_fd: posix.fd_t = @intCast(rc); | 14742 | const fresh_fd: posix.fd_t = @intCast(rc); |
| 14744 | t.mutex.lock(); // Another thread might have won the race. | 14743 | mutexLockUncancelable(&t.mutex); // Another thread might have won the race. |
| 14745 | defer t.mutex.unlock(); | 14744 | defer mutexUnlock(&t.mutex); |
| 14746 | if (t.null_file.fd != -1) { | 14745 | if (t.null_file.fd != -1) { |
| 14747 | posix.close(fresh_fd); | 14746 | posix.close(fresh_fd); |
| 14748 | return t.null_file.fd; | 14747 | return t.null_file.fd; |
| ... | @@ -15402,8 +15401,8 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro | ... | @@ -15402,8 +15401,8 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro |
| 15402 | | 15401 | |
| 15403 | fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE { | 15402 | fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 15404 | { | 15403 | { |
| 15405 | t.mutex.lock(); | 15404 | mutexLockUncancelable(&t.mutex); |
| 15406 | defer t.mutex.unlock(); | 15405 | defer mutexUnlock(&t.mutex); |
| 15407 | if (t.random_file.handle) |handle| return handle; | 15406 | if (t.random_file.handle) |handle| return handle; |
| 15408 | } | 15407 | } |
| 15409 | | 15408 | |
| ... | @@ -15437,8 +15436,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE { | ... | @@ -15437,8 +15436,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 15437 | )) { | 15436 | )) { |
| 15438 | .SUCCESS => { | 15437 | .SUCCESS => { |
| 15439 | syscall.finish(); | 15438 | syscall.finish(); |
| 15440 | t.mutex.lock(); // Another thread might have won the race. | 15439 | mutexLockUncancelable(&t.mutex); // Another thread might have won the race. |
| 15441 | defer t.mutex.unlock(); | 15440 | defer mutexUnlock(&t.mutex); |
| 15442 | if (t.random_file.handle) |prev_handle| { | 15441 | if (t.random_file.handle) |prev_handle| { |
| 15443 | windows.CloseHandle(fresh_handle); | 15442 | windows.CloseHandle(fresh_handle); |
| 15444 | return prev_handle; | 15443 | return prev_handle; |
| ... | @@ -15458,8 +15457,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE { | ... | @@ -15458,8 +15457,8 @@ fn getCngHandle(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 15458 | | 15457 | |
| 15459 | fn getNulHandle(t: *Threaded) !windows.HANDLE { | 15458 | fn getNulHandle(t: *Threaded) !windows.HANDLE { |
| 15460 | { | 15459 | { |
| 15461 | t.mutex.lock(); | 15460 | mutexLockUncancelable(&t.mutex); |
| 15462 | defer t.mutex.unlock(); | 15461 | defer mutexUnlock(&t.mutex); |
| 15463 | if (t.null_file.handle) |handle| return handle; | 15462 | if (t.null_file.handle) |handle| return handle; |
| 15464 | } | 15463 | } |
| 15465 | | 15464 | |
| ... | @@ -15505,8 +15504,8 @@ fn getNulHandle(t: *Threaded) !windows.HANDLE { | ... | @@ -15505,8 +15504,8 @@ fn getNulHandle(t: *Threaded) !windows.HANDLE { |
| 15505 | )) { | 15504 | )) { |
| 15506 | .SUCCESS => { | 15505 | .SUCCESS => { |
| 15507 | syscall.finish(); | 15506 | syscall.finish(); |
| 15508 | t.mutex.lock(); // Another thread might have won the race. | 15507 | mutexLockUncancelable(&t.mutex); // Another thread might have won the race. |
| 15509 | defer t.mutex.unlock(); | 15508 | defer mutexUnlock(&t.mutex); |
| 15510 | if (t.null_file.handle) |prev_handle| { | 15509 | if (t.null_file.handle) |prev_handle| { |
| 15511 | windows.CloseHandle(fresh_handle); | 15510 | windows.CloseHandle(fresh_handle); |
| 15512 | return prev_handle; | 15511 | return prev_handle; |
| ... | @@ -16551,15 +16550,15 @@ fn random(userdata: ?*anyopaque, buffer: []u8) void { | ... | @@ -16551,15 +16550,15 @@ fn random(userdata: ?*anyopaque, buffer: []u8) void { |
| 16551 | } | 16550 | } |
| 16552 | | 16551 | |
| 16553 | fn randomMainThread(t: *Threaded, buffer: []u8) void { | 16552 | fn randomMainThread(t: *Threaded, buffer: []u8) void { |
| 16554 | t.mutex.lock(); | 16553 | mutexLockUncancelable(&t.mutex); |
| 16555 | defer t.mutex.unlock(); | 16554 | defer mutexUnlock(&t.mutex); |
| 16556 | | 16555 | |
| 16557 | if (!t.csprng.isInitialized()) { | 16556 | if (!t.csprng.isInitialized()) { |
| 16558 | @branchHint(.unlikely); | 16557 | @branchHint(.unlikely); |
| 16559 | var seed: [Csprng.seed_len]u8 = undefined; | 16558 | var seed: [Csprng.seed_len]u8 = undefined; |
| 16560 | { | 16559 | { |
| 16561 | t.mutex.unlock(); | 16560 | mutexUnlock(&t.mutex); |
| 16562 | defer t.mutex.lock(); | 16561 | defer mutexLockUncancelable(&t.mutex); |
| 16563 | | 16562 | |
| 16564 | const prev = swapCancelProtection(t, .blocked); | 16563 | const prev = swapCancelProtection(t, .blocked); |
| 16565 | defer _ = swapCancelProtection(t, prev); | 16564 | defer _ = swapCancelProtection(t, prev); |
| ... | @@ -16744,8 +16743,8 @@ fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void { | ... | @@ -16744,8 +16743,8 @@ fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void { |
| 16744 | | 16743 | |
| 16745 | fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t { | 16744 | fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t { |
| 16746 | { | 16745 | { |
| 16747 | t.mutex.lock(); | 16746 | mutexLockUncancelable(&t.mutex); |
| 16748 | defer t.mutex.unlock(); | 16747 | defer mutexUnlock(&t.mutex); |
| 16749 | | 16748 | |
| 16750 | if (t.random_file.fd == -2) return error.EntropyUnavailable; | 16749 | if (t.random_file.fd == -2) return error.EntropyUnavailable; |
| 16751 | if (t.random_file.fd != -1) return t.random_file.fd; | 16750 | if (t.random_file.fd != -1) return t.random_file.fd; |
| ... | @@ -16785,8 +16784,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t { | ... | @@ -16785,8 +16784,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t { |
| 16785 | .SUCCESS => { | 16784 | .SUCCESS => { |
| 16786 | syscall.finish(); | 16785 | syscall.finish(); |
| 16787 | if (!statx.mask.TYPE) return error.EntropyUnavailable; | 16786 | if (!statx.mask.TYPE) return error.EntropyUnavailable; |
| 16788 | t.mutex.lock(); // Another thread might have won the race. | 16787 | mutexLockUncancelable(&t.mutex); // Another thread might have won the race. |
| 16789 | defer t.mutex.unlock(); | 16788 | defer mutexUnlock(&t.mutex); |
| 16790 | if (t.random_file.fd >= 0) { | 16789 | if (t.random_file.fd >= 0) { |
| 16791 | posix.close(fd); | 16790 | posix.close(fd); |
| 16792 | return t.random_file.fd; | 16791 | return t.random_file.fd; |
| ... | @@ -16813,8 +16812,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t { | ... | @@ -16813,8 +16812,8 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t { |
| 16813 | switch (posix.errno(fstat_sym(fd, &stat))) { | 16812 | switch (posix.errno(fstat_sym(fd, &stat))) { |
| 16814 | .SUCCESS => { | 16813 | .SUCCESS => { |
| 16815 | syscall.finish(); | 16814 | syscall.finish(); |
| 16816 | t.mutex.lock(); // Another thread might have won the race. | 16815 | mutexLockUncancelable(&t.mutex); // Another thread might have won the race. |
| 16817 | defer t.mutex.unlock(); | 16816 | defer mutexUnlock(&t.mutex); |
| 16818 | if (t.random_file.fd >= 0) { | 16817 | if (t.random_file.fd >= 0) { |
| 16819 | posix.close(fd); | 16818 | posix.close(fd); |
| 16820 | return t.random_file.fd; | 16819 | return t.random_file.fd; |
| ... | @@ -16878,13 +16877,13 @@ const parking_futex = struct { | ... | @@ -16878,13 +16877,13 @@ const parking_futex = struct { |
| 16878 | /// avoid a race. | 16877 | /// avoid a race. |
| 16879 | num_waiters: std.atomic.Value(u32), | 16878 | num_waiters: std.atomic.Value(u32), |
| 16880 | /// Protects `waiters`. | 16879 | /// Protects `waiters`. |
| 16881 | mutex: std.Thread.Mutex, | 16880 | mutex: Io.Mutex, |
| 16882 | waiters: std.DoublyLinkedList, | 16881 | waiters: std.DoublyLinkedList, |
| 16883 | | 16882 | |
| 16884 | /// Prevent false sharing between buckets. | 16883 | /// Prevent false sharing between buckets. |
| 16885 | _: void align(std.atomic.cache_line) = {}, | 16884 | _: void align(std.atomic.cache_line) = {}, |
| 16886 | | 16885 | |
| 16887 | const init: Bucket = .{ .num_waiters = .init(0), .mutex = .{}, .waiters = .{} }; | 16886 | const init: Bucket = .{ .num_waiters = .init(0), .mutex = .init, .waiters = .{} }; |
| 16888 | }; | 16887 | }; |
| 16889 | | 16888 | |
| 16890 | const Waiter = struct { | 16889 | const Waiter = struct { |
| ... | @@ -16947,8 +16946,8 @@ const parking_futex = struct { | ... | @@ -16947,8 +16946,8 @@ const parking_futex = struct { |
| 16947 | var status_buf: std.atomic.Value(Thread.Status) = undefined; | 16946 | var status_buf: std.atomic.Value(Thread.Status) = undefined; |
| 16948 | | 16947 | |
| 16949 | { | 16948 | { |
| 16950 | bucket.mutex.lock(); | 16949 | mutexLockUncancelable(&bucket.mutex); |
| 16951 | defer bucket.mutex.unlock(); | 16950 | defer mutexUnlock(&bucket.mutex); |
| 16952 | | 16951 | |
| 16953 | _ = bucket.num_waiters.fetchAdd(1, .acquire); | 16952 | _ = bucket.num_waiters.fetchAdd(1, .acquire); |
| 16954 | | 16953 | |
| ... | @@ -17017,8 +17016,8 @@ const parking_futex = struct { | ... | @@ -17017,8 +17016,8 @@ const parking_futex = struct { |
| 17017 | .parked => { | 17016 | .parked => { |
| 17018 | // We saw a timeout and updated our own status from `.parked` to `.none`. It is | 17017 | // We saw a timeout and updated our own status from `.parked` to `.none`. It is |
| 17019 | // our responsibility to remove `waiter` from `bucket`. | 17018 | // our responsibility to remove `waiter` from `bucket`. |
| 17020 | bucket.mutex.lock(); | 17019 | mutexLockUncancelable(&bucket.mutex); |
| 17021 | defer bucket.mutex.unlock(); | 17020 | defer mutexUnlock(&bucket.mutex); |
| 17022 | bucket.waiters.remove(&waiter.node); | 17021 | bucket.waiters.remove(&waiter.node); |
| 17023 | assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0); | 17022 | assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0); |
| 17024 | }, | 17023 | }, |
| ... | @@ -17057,8 +17056,8 @@ const parking_futex = struct { | ... | @@ -17057,8 +17056,8 @@ const parking_futex = struct { |
| 17057 | // of the critical section. This forms a singly-linked list of waiters using `Waiter.node.next`. | 17056 | // of the critical section. This forms a singly-linked list of waiters using `Waiter.node.next`. |
| 17058 | var waking_head: ?*std.DoublyLinkedList.Node = null; | 17057 | var waking_head: ?*std.DoublyLinkedList.Node = null; |
| 17059 | { | 17058 | { |
| 17060 | bucket.mutex.lock(); | 17059 | mutexLockUncancelable(&bucket.mutex); |
| 17061 | defer bucket.mutex.unlock(); | 17060 | defer mutexUnlock(&bucket.mutex); |
| 17062 | | 17061 | |
| 17063 | var num_removed: u32 = 0; | 17062 | var num_removed: u32 = 0; |
| 17064 | var it = bucket.waiters.first; | 17063 | var it = bucket.waiters.first; |
| ... | @@ -17113,8 +17112,8 @@ const parking_futex = struct { | ... | @@ -17113,8 +17112,8 @@ const parking_futex = struct { |
| 17113 | | 17112 | |
| 17114 | fn removeCanceledWaiter(waiter: *Waiter) void { | 17113 | fn removeCanceledWaiter(waiter: *Waiter) void { |
| 17115 | const bucket = bucketForAddress(waiter.address); | 17114 | const bucket = bucketForAddress(waiter.address); |
| 17116 | bucket.mutex.lock(); | 17115 | mutexLockUncancelable(&bucket.mutex); |
| 17117 | defer bucket.mutex.unlock(); | 17116 | defer mutexUnlock(&bucket.mutex); |
| 17118 | bucket.waiters.remove(&waiter.node); | 17117 | bucket.waiters.remove(&waiter.node); |
| 17119 | assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0); | 17118 | assert(bucket.num_waiters.fetchSub(1, .monotonic) > 0); |
| 17120 | waiter.done.store(true, .release); // potentially invalidates `waiter.*` | 17119 | waiter.done.store(true, .release); // potentially invalidates `waiter.*` |
| ... | @@ -18102,3 +18101,123 @@ fn eventSet(event: *Io.Event) void { | ... | @@ -18102,3 +18101,123 @@ fn eventSet(event: *Io.Event) void { |
| 18102 | .waiting => Thread.futexWake(@ptrCast(event), std.math.maxInt(u32)), | 18101 | .waiting => Thread.futexWake(@ptrCast(event), std.math.maxInt(u32)), |
| 18103 | } | 18102 | } |
| 18104 | } | 18103 | } |
| | 18104 | |
| | 18105 | /// Same as `Io.Condition.broadcast` but avoids the VTable. |
| | 18106 | fn condBroadcast(cond: *Io.Condition) void { |
| | 18107 | var prev_state = cond.state.load(.monotonic); |
| | 18108 | while (prev_state.waiters > prev_state.signals) { |
| | 18109 | @branchHint(.unlikely); |
| | 18110 | prev_state = cond.state.cmpxchgWeak(prev_state, .{ |
| | 18111 | .waiters = prev_state.waiters, |
| | 18112 | .signals = prev_state.waiters, |
| | 18113 | }, .release, .monotonic) orelse { |
| | 18114 | // Update the epoch to tell the waiting threads that there are new signals for them. |
| | 18115 | // Note that a waiting thread could miss a take if *exactly* (1<<32)-1 wakes happen |
| | 18116 | // between it observing the epoch and sleeping on it, but this is extraordinarily |
| | 18117 | // unlikely due to the precise number of calls required. |
| | 18118 | _ = cond.epoch.fetchAdd(1, .release); // `.release` to ensure ordered after `state` update |
| | 18119 | Thread.futexWake(&cond.epoch.raw, prev_state.waiters - prev_state.signals); |
| | 18120 | return; |
| | 18121 | }; |
| | 18122 | } |
| | 18123 | } |
| | 18124 | |
| | 18125 | /// Same as `Io.Condition.signal` but avoids the VTable. |
| | 18126 | fn condSignal(cond: *Io.Condition) void { |
| | 18127 | var prev_state = cond.state.load(.monotonic); |
| | 18128 | while (prev_state.waiters > prev_state.signals) { |
| | 18129 | @branchHint(.unlikely); |
| | 18130 | prev_state = cond.state.cmpxchgWeak(prev_state, .{ |
| | 18131 | .waiters = prev_state.waiters, |
| | 18132 | .signals = prev_state.signals + 1, |
| | 18133 | }, .release, .monotonic) orelse { |
| | 18134 | // Update the epoch to tell the waiting threads that there are new signals for them. |
| | 18135 | // Note that a waiting thread could miss a take if *exactly* (1<<32)-1 wakes happen |
| | 18136 | // between it observing the epoch and sleeping on it, but this is extraordinarily |
| | 18137 | // unlikely due to the precise number of calls required. |
| | 18138 | _ = cond.epoch.fetchAdd(1, .release); // `.release` to ensure ordered after `state` update |
| | 18139 | Thread.futexWake(&cond.epoch.raw, 1); |
| | 18140 | return; |
| | 18141 | }; |
| | 18142 | } |
| | 18143 | } |
| | 18144 | |
| | 18145 | /// Same as `Io.Condition.waitUncancelable` but avoids the VTable. |
| | 18146 | fn condWait(cond: *Io.Condition, mutex: *Io.Mutex) void { |
| | 18147 | var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load |
| | 18148 | |
| | 18149 | { |
| | 18150 | const prev_state = cond.state.fetchAdd(.{ .waiters = 1, .signals = 0 }, .monotonic); |
| | 18151 | assert(prev_state.waiters < std.math.maxInt(u16)); // overflow caused by too many waiters |
| | 18152 | } |
| | 18153 | |
| | 18154 | mutexUnlock(mutex); |
| | 18155 | defer mutexLockUncancelable(mutex); |
| | 18156 | |
| | 18157 | while (true) { |
| | 18158 | Thread.futexWaitUncancelable(&cond.epoch.raw, epoch, null); |
| | 18159 | |
| | 18160 | epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before `state` laod |
| | 18161 | |
| | 18162 | var prev_state = cond.state.load(.monotonic); |
| | 18163 | while (prev_state.signals > 0) { |
| | 18164 | prev_state = cond.state.cmpxchgWeak(prev_state, .{ |
| | 18165 | .waiters = prev_state.waiters - 1, |
| | 18166 | .signals = prev_state.signals - 1, |
| | 18167 | }, .acquire, .monotonic) orelse { |
| | 18168 | // We successfully consumed a signal. |
| | 18169 | return; |
| | 18170 | }; |
| | 18171 | } |
| | 18172 | } |
| | 18173 | } |
| | 18174 | |
| | 18175 | /// Same as `Io.Mutex.lockUncancelable` but avoids the VTable. |
| | 18176 | fn mutexLock(m: *Io.Mutex) Io.Cancelable!void { |
| | 18177 | const initial_state = m.state.cmpxchgWeak( |
| | 18178 | .unlocked, |
| | 18179 | .locked_once, |
| | 18180 | .acquire, |
| | 18181 | .monotonic, |
| | 18182 | ) orelse { |
| | 18183 | @branchHint(.likely); |
| | 18184 | return; |
| | 18185 | }; |
| | 18186 | if (initial_state == .contended) { |
| | 18187 | try Thread.futexWait(@ptrCast(&m.state.raw), @intFromEnum(Io.Mutex.State.contended), null); |
| | 18188 | } |
| | 18189 | while (m.state.swap(.contended, .acquire) != .unlocked) { |
| | 18190 | try Thread.futexWait(@ptrCast(&m.state.raw), @intFromEnum(Io.Mutex.State.contended), null); |
| | 18191 | } |
| | 18192 | } |
| | 18193 | |
| | 18194 | /// Same as `Io.Mutex.lockUncancelable` but avoids the VTable. |
| | 18195 | fn mutexLockUncancelable(m: *Io.Mutex) void { |
| | 18196 | const initial_state = m.state.cmpxchgWeak( |
| | 18197 | .unlocked, |
| | 18198 | .locked_once, |
| | 18199 | .acquire, |
| | 18200 | .monotonic, |
| | 18201 | ) orelse { |
| | 18202 | @branchHint(.likely); |
| | 18203 | return; |
| | 18204 | }; |
| | 18205 | if (initial_state == .contended) { |
| | 18206 | Thread.futexWaitUncancelable(@ptrCast(&m.state.raw), @intFromEnum(Io.Mutex.State.contended), null); |
| | 18207 | } |
| | 18208 | while (m.state.swap(.contended, .acquire) != .unlocked) { |
| | 18209 | Thread.futexWaitUncancelable(@ptrCast(&m.state.raw), @intFromEnum(Io.Mutex.State.contended), null); |
| | 18210 | } |
| | 18211 | } |
| | 18212 | |
| | 18213 | /// Same as `Io.Mutex.unlock` but avoids the VTable. |
| | 18214 | fn mutexUnlock(m: *Io.Mutex) void { |
| | 18215 | switch (m.state.swap(.unlocked, .release)) { |
| | 18216 | .unlocked => unreachable, |
| | 18217 | .locked_once => {}, |
| | 18218 | .contended => { |
| | 18219 | @branchHint(.unlikely); |
| | 18220 | Thread.futexWake(@ptrCast(&m.state.raw), 1); |
| | 18221 | }, |
| | 18222 | } |
| | 18223 | } |