authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-21 21:05:15-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-27 15:32:34-08:00
loge18ee3a93afb7cb090ac6ef2cd49d2386edd3950
treef5ec3e8725f48ca1f879f832fb4e8aa45f328886
parent20c4211b6e4fffe47330fa2a60e42ac39e78044c

std.Io.Threaded: introduce Thread.InterruptMethod

implements APC cancelation except for the actual call to NtCancelIoFileEx

1 files changed, 149 insertions(+), 92 deletions(-)

lib/std/Io/Threaded.zig+149-92
......@@ -339,8 +339,8 @@ const Group = struct {
339339 .canceled => true,
340340 .parked => unreachable,
341341 .blocked => unreachable,
342 .blocked_alertable => unreachable,
343 .blocked_alertable_canceling => unreachable,
342 .blocked_apc => unreachable,
343 .blocked_windows_dns => unreachable,
344344 .blocked_canceling => unreachable,
345345 };
346346 if (result) {
......@@ -379,7 +379,10 @@ const Group = struct {
379379 while (it) |thread| : (it = thread.next) {
380380 // This non-mutating RMW exists for ordering reasons: see comment in `Group.Task.start` for reasons.
381381 _ = thread.status.fetchOr(.{ .cancelation = @enumFromInt(0), .awaitable = .null }, .release);
382 if (thread.cancelAwaitable(.fromGroup(g.ptr))) any_blocked = true;
382 if (thread.cancelAwaitable(.fromGroup(g.ptr))) |method| {
383 thread.interrupt_method = method;
384 any_blocked = true;
385 }
383386 }
384387 return any_blocked;
385388 }
......@@ -391,7 +394,7 @@ const Group = struct {
391394 var any_signaled = false;
392395 var it = t.worker_threads.load(.acquire); // acquire `Thread` values
393396 while (it) |thread| : (it = thread.next) {
394 if (thread.signalCanceledSyscall(t, .fromGroup(g.ptr))) any_signaled = true;
397 if (thread.signalCanceledSyscall(t, .fromGroup(g.ptr), thread.interrupt_method)) any_signaled = true;
395398 }
396399 return any_signaled;
397400 }
......@@ -543,8 +546,8 @@ const Future = struct {
543546 .canceled => true,
544547 .parked => unreachable,
545548 .blocked => unreachable,
546 .blocked_alertable => unreachable,
547 .blocked_alertable_canceling => unreachable,
549 .blocked_apc => unreachable,
550 .blocked_windows_dns => unreachable,
548551 .blocked_canceling => unreachable,
549552 };
550553 thread.status.store(.{ .cancelation = .none, .awaitable = .null }, .monotonic);
......@@ -573,11 +576,15 @@ const Future = struct {
573576 num_completed: *std.atomic.Value(u32),
574577 thread: ?*Thread,
575578 ) void {
576 var need_signal: bool = if (thread) |th| th.cancelAwaitable(.fromFuture(future)) else false;
579 var interrupt_method: ?Thread.InterruptMethod =
580 if (thread) |th| th.cancelAwaitable(.fromFuture(future)) else null;
577581 var timeout_ns: u64 = 1 << 10;
578582 while (true) {
579 need_signal = need_signal and thread.?.signalCanceledSyscall(t, .fromFuture(future));
580 Thread.futexWaitUncancelable(&num_completed.raw, 0, if (need_signal) timeout_ns else null);
583 if (interrupt_method) |method| {
584 if (!thread.?.signalCanceledSyscall(t, .fromFuture(future), method))
585 interrupt_method = null;
586 }
587 Thread.futexWaitUncancelable(&num_completed.raw, 0, if (interrupt_method != null) timeout_ns else null);
581588 switch (num_completed.load(.acquire)) { // acquire task results
582589 0 => {},
583590 1 => break,
......@@ -625,6 +632,9 @@ const Thread = struct {
625632 cancel_protection: Io.CancelProtection,
626633 /// Always released when `Status.cancelation` is set to `.parked`.
627634 futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn,
635 apc_context: if (is_windows) ?*anyopaque else void,
636 /// Used only by group cancelation code for temporary storage.
637 interrupt_method: InterruptMethod,
628638
629639 csprng: Csprng,
630640
......@@ -652,11 +662,13 @@ const Thread = struct {
652662 /// To request cancelation, set the status to `.blocked_canceling` and repeatedly interrupt the system call until the status changes.
653663 blocked = 0b011,
654664
655 /// Windows-only: the thread is blocked in an alertable wait via
656 /// `NtDelayExecution`. To request cancelation, set the status to
657 /// `blocked_alertable_canceling` and repeatedly alert the thread
658 /// until the status changes.
659 blocked_alertable = 0b010,
665 /// Windows-only: the thread is blocked in a call to `NtDelayExecution`.
666 /// To request cancelation, set the status to `.canceling` and call `NtCancelIoFileEx`.
667 blocked_apc = 0b100,
668
669 /// Windows-only: the thread is blocked in a call to `GetAddrInfoExW`.
670 /// To request cancelation, set the status to `.canceling` and call `GetAddrInfoExCancel`.
671 blocked_windows_dns = 0b010,
660672
661673 /// The thread has an outstanding cancelation request but is not in a cancelable operation.
662674 /// When it acknowledges the cancelation, it will set the status to `.canceled`.
......@@ -705,8 +717,8 @@ const Thread = struct {
705717 switch (status.cancelation) {
706718 .parked => unreachable,
707719 .blocked => unreachable,
708 .blocked_alertable => unreachable,
709 .blocked_alertable_canceling => unreachable,
720 .blocked_apc => unreachable,
721 .blocked_windows_dns => unreachable,
710722 .blocked_canceling => unreachable,
711723 .none, .canceled => {},
712724 .canceling => {
......@@ -986,17 +998,17 @@ const Thread = struct {
986998 /// It is possible that `thread` gets canceled by this function, but is blocked in a syscall. In
987999 /// that case, the thread may need to be sent a signal to interrupt the call. This function will
9881000 /// return `true` to indicate this, in which case the caller must call `signalCanceledSyscall`.
989 fn cancelAwaitable(thread: *Thread, awaitable: AwaitableId) bool {
1001 fn cancelAwaitable(thread: *Thread, awaitable: AwaitableId) ?InterruptMethod {
9901002 var status = thread.status.load(.monotonic);
9911003 while (true) {
992 if (status.awaitable != awaitable) return false; // thread is working on something else
1004 if (status.awaitable != awaitable) return null; // thread is working on something else
9931005 status = switch (status.cancelation) {
9941006 .none => thread.status.cmpxchgWeak(
9951007 .{ .cancelation = .none, .awaitable = awaitable },
9961008 .{ .cancelation = .canceling, .awaitable = awaitable },
9971009 .monotonic,
9981010 .monotonic,
999 ) orelse return false,
1011 ) orelse return null,
10001012
10011013 .parked => thread.status.cmpxchgWeak(
10021014 .{ .cancelation = .parked, .awaitable = awaitable },
......@@ -1009,7 +1021,7 @@ const Thread = struct {
10091021 parking_futex.removeCanceledWaiter(futex_waiter);
10101022 }
10111023 unpark(&.{thread.id}, null);
1012 return false;
1024 return null;
10131025 },
10141026
10151027 .blocked => thread.status.cmpxchgWeak(
......@@ -1017,7 +1029,17 @@ const Thread = struct {
10171029 .{ .cancelation = .blocked_canceling, .awaitable = awaitable },
10181030 .monotonic,
10191031 .monotonic,
1020 ) orelse return true,
1032 ) orelse return .sync,
1033
1034 .blocked_apc => thread.status.cmpxchgWeak(
1035 .{ .cancelation = .blocked_apc, .awaitable = awaitable },
1036 .{ .cancelation = .canceling, .awaitable = awaitable },
1037 .monotonic,
1038 .monotonic,
1039 ) orelse {
1040 if (!is_windows) unreachable;
1041 return .apc;
1042 },
10211043
10221044 .blocked_alertable => thread.status.cmpxchgWeak(
10231045 .{ .cancelation = .blocked_alertable, .awaitable = awaitable },
......@@ -1026,14 +1048,14 @@ const Thread = struct {
10261048 .monotonic,
10271049 ) orelse {
10281050 if (!is_windows) unreachable;
1029 return true;
1051 return .dns;
10301052 },
10311053
10321054 .canceling, .canceled => {
10331055 // This can happen when the task start raced with the cancelation, so the thread
10341056 // saw the cancelation on the future/group *and* we are trying to signal the
10351057 // thread here.
1036 return false;
1058 return null;
10371059 },
10381060
10391061 .blocked_canceling => unreachable, // `awaitable` has not been canceled before now
......@@ -1042,6 +1064,11 @@ const Thread = struct {
10421064 }
10431065 }
10441066
1067 const InterruptMethod = switch (native_os) {
1068 .windows => enum { sync, dns, apc },
1069 else => enum { sync },
1070 };
1071
10451072 /// Sends a signal to `thread` if it is still blocked in a syscall (i.e. has not yet observed
10461073 /// the cancelation request from `cancelAwaitable`).
10471074 ///
......@@ -1051,24 +1078,21 @@ const Thread = struct {
10511078 /// the thread is still blocked. For the implementation, `Future.waitForCancelWithSignaling` and
10521079 /// `Group.waitForCancelWithSignaling`: they use exponential backoff starting at a 1us delay and
10531080 /// doubling each call. In practice, it is rare to send more than one signal.
1054 fn signalCanceledSyscall(thread: *Thread, t: *Threaded, awaitable: AwaitableId) bool {
1055 const status = thread.status.load(.monotonic);
1056 if (status.awaitable != awaitable) {
1057 // The thread has moved on and is working on something totally different.
1058 return false;
1059 }
1081 fn signalCanceledSyscall(thread: *Thread, t: *Threaded, awaitable: AwaitableId, method: InterruptMethod) bool {
1082 const bad_status: Status = .{ .cancelation = .blocked_canceling, .awaitable = awaitable };
1083 if (thread.status.load(.monotonic) != bad_status) return false;
10601084
10611085 // The thread ID and/or handle can be read non-atomically because they never change and were
10621086 // released by the store that made `thread` available to us.
10631087
1064 switch (status.cancelation) {
1065 .blocked_canceling => if (std.Thread.use_pthreads) {
1066 return switch (std.c.pthread_kill(thread.handle, .IO)) {
1067 0 => true,
1068 else => false,
1069 };
1070 } else switch (native_os) {
1071 .linux => {
1088 if (std.Thread.use_pthreads) switch (method) {
1089 .sync => return switch (std.c.pthread_kill(thread.handle, .IO)) {
1090 0 => true,
1091 else => false,
1092 },
1093 } else switch (native_os) {
1094 .linux => switch (method) {
1095 .sync => {
10721096 const pid: posix.pid_t = pid: {
10731097 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
10741098 if (cached_pid != .unknown) break :pid @intFromEnum(cached_pid);
......@@ -1081,7 +1105,9 @@ const Thread = struct {
10811105 else => false,
10821106 };
10831107 },
1084 .windows => {
1108 },
1109 .windows => switch (method) {
1110 .sync => {
10851111 var iosb: windows.IO_STATUS_BLOCK = undefined;
10861112 return switch (windows.ntdll.NtCancelSynchronousIoFile(thread.handle, null, &iosb)) {
10871113 .NOT_FOUND => true, // this might mean the operation hasn't started yet
......@@ -1089,15 +1115,8 @@ const Thread = struct {
10891115 else => false,
10901116 };
10911117 },
1092 else => return false,
1093 },
1094
1095 .blocked_alertable_canceling => {
1096 if (!is_windows) unreachable;
1097 return switch (windows.ntdll.NtAlertThread(thread.handle)) {
1098 .SUCCESS => true,
1099 else => false,
1100 };
1118 .dns => @panic("TODO call GetAddrInfoExCancel"),
1119 .apc => @panic("TODO call NtCancelIoFileEx"),
11011120 },
11021121
11031122 else => {
......@@ -1145,8 +1164,8 @@ const Syscall = struct {
11451164 }, .monotonic).cancelation) {
11461165 .parked => unreachable,
11471166 .blocked => unreachable,
1148 .blocked_alertable => unreachable,
1149 .blocked_alertable_canceling => unreachable,
1167 .blocked_apc => unreachable,
1168 .blocked_windows_dns => unreachable,
11501169 .blocked_canceling => unreachable,
11511170 .none => return .{ .thread = thread }, // new status is `.blocked`
11521171 .canceling => return error.Canceled, // new status is `.canceled`
......@@ -1165,19 +1184,14 @@ const Syscall = struct {
11651184 }, .monotonic).cancelation) {
11661185 .none => unreachable,
11671186 .parked => unreachable,
1168 .blocked_alertable => unreachable,
1169 .blocked_alertable_canceling => unreachable,
1187 .blocked_apc => unreachable,
1188 .blocked_windows_dns => unreachable,
11701189 .canceling => unreachable,
11711190 .canceled => unreachable,
11721191 .blocked => {}, // new status is `.blocked` (unchanged)
11731192 .blocked_canceling => return error.Canceled, // new status is `.canceled`
11741193 }
11751194 }
1176 fn toApc(s: Syscall) Io.Cancelable!void {
1177 // TODO set state to indicate instead of NtCancelSynchronousIoFile we
1178 // need to use NtCancelIoFileEx
1179 return s.checkCancel();
1180 }
11811195 /// Marks this syscall as finished.
11821196 fn finish(s: Syscall) void {
11831197 const thread = s.thread orelse return;
......@@ -1187,8 +1201,8 @@ const Syscall = struct {
11871201 }, .monotonic).cancelation) {
11881202 .none => unreachable,
11891203 .parked => unreachable,
1190 .blocked_alertable => unreachable,
1191 .blocked_alertable_canceling => unreachable,
1204 .blocked_apc => unreachable,
1205 .blocked_windows_dns => unreachable,
11921206 .canceling => unreachable,
11931207 .canceled => unreachable,
11941208 .blocked => {}, // new status is `.none`
......@@ -1196,25 +1210,25 @@ const Syscall = struct {
11961210 }
11971211 }
11981212 /// Indicates instead of `NtCancelSynchronousIoFile` we need to use
1199 /// `NtAlertThread` to interrupt the wait.
1213 /// `NtCancelIoFileEx` to interrupt the wait.
12001214 ///
12011215 /// Windows only, called from blocked state only.
1202 fn toAlertable(s: Syscall) Io.Cancelable!AlertableSyscall {
1203 comptime assert(is_windows);
1204 const thread = s.thread orelse return .{ .thread = null };
1216 fn toApc(s: Syscall, apc_context: ?*anyopaque) Io.Cancelable!void {
1217 const thread = s.thread orelse return;
1218 thread.apc_context = apc_context;
12051219 var prev = thread.status.load(.monotonic);
12061220 while (true) prev = switch (prev.cancelation) {
12071221 .none => unreachable,
12081222 .parked => unreachable,
1209 .blocked_alertable => unreachable,
1210 .blocked_alertable_canceling => unreachable,
1223 .blocked_apc => unreachable,
1224 .blocked_windows_dns => unreachable,
12111225 .canceling => unreachable,
12121226 .canceled => unreachable,
12131227
12141228 .blocked => thread.status.cmpxchgWeak(prev, .{
1215 .cancelation = .blocked_alertable,
1229 .cancelation = .blocked_apc,
12161230 .awaitable = prev.awaitable,
1217 }, .monotonic, .monotonic) orelse return .{ .thread = thread },
1231 }, .monotonic, .monotonic) orelse return,
12181232
12191233 .blocked_canceling => thread.status.cmpxchgWeak(prev, .{
12201234 .cancelation = .canceled,
......@@ -1222,6 +1236,45 @@ const Syscall = struct {
12221236 }, .monotonic, .monotonic) orelse return error.Canceled,
12231237 };
12241238 }
1239 /// Windows only, called from blocked_apc state only.
1240 fn checkCancelApc(s: Syscall) Io.Cancelable!void {
1241 const thread = s.thread orelse return;
1242 var prev = thread.status.load(.monotonic);
1243 while (true) prev = switch (prev.cancelation) {
1244 .none => unreachable,
1245 .parked => unreachable,
1246 .blocked_windows_dns => unreachable,
1247 .blocked => unreachable,
1248 .canceling => unreachable,
1249 .canceled => unreachable,
1250 .blocked_apc => return,
1251 .blocked_canceling => thread.status.cmpxchgWeak(prev, .{
1252 .cancelation = .canceled,
1253 .awaitable = prev.awaitable,
1254 }, .monotonic, .monotonic) orelse return error.Canceled,
1255 };
1256 }
1257 /// Windows only, called from blocked_apc state only.
1258 fn finishApc(s: Syscall) void {
1259 const thread = s.thread orelse return;
1260 var prev = thread.status.load(.monotonic);
1261 while (true) prev = switch (prev.cancelation) {
1262 .none => unreachable,
1263 .parked => unreachable,
1264 .blocked_windows_dns => unreachable,
1265 .blocked => unreachable,
1266 .canceling => unreachable,
1267 .canceled => unreachable,
1268 .blocked_apc => thread.status.cmpxchgWeak(prev, .{
1269 .cancelation = .none,
1270 .awaitable = prev.awaitable,
1271 }, .monotonic, .monotonic) orelse return,
1272 .blocked_canceling => thread.status.cmpxchgWeak(prev, .{
1273 .cancelation = .canceling,
1274 .awaitable = prev.awaitable,
1275 }, .monotonic, .monotonic) orelse return,
1276 };
1277 }
12251278 /// Convenience wrapper which calls `finish`, then returns `err`.
12261279 fn fail(s: Syscall, err: anytype) @TypeOf(err) {
12271280 s.finish();
......@@ -1501,6 +1554,8 @@ fn worker(t: *Threaded) void {
15011554 .cancel_protection = .unblocked,
15021555 .futex_waiter = undefined,
15031556 .csprng = .{},
1557 .apc_context = undefined,
1558 .interrupt_method = undefined,
15041559 };
15051560 Thread.current = &thread;
15061561
......@@ -2105,8 +2160,8 @@ fn groupAsyncEager(
21052160 .canceled => true,
21062161 .parked => unreachable,
21072162 .blocked => unreachable,
2108 .blocked_alertable => unreachable,
2109 .blocked_alertable_canceling => unreachable,
2163 .blocked_apc => unreachable,
2164 .blocked_windows_dns => unreachable,
21102165 .blocked_canceling => unreachable,
21112166 };
21122167 } else false;
......@@ -2117,8 +2172,8 @@ fn groupAsyncEager(
21172172 .canceled => true,
21182173 .parked => unreachable,
21192174 .blocked => unreachable,
2120 .blocked_alertable => unreachable,
2121 .blocked_alertable_canceling => unreachable,
2175 .blocked_apc => unreachable,
2176 .blocked_windows_dns => unreachable,
21222177 .blocked_canceling => unreachable,
21232178 };
21242179 } else false;
......@@ -2297,8 +2352,8 @@ fn recancelInner() void {
22972352 .canceling => unreachable, // called `recancel` but cancelation was already pending
22982353 .parked => unreachable,
22992354 .blocked => unreachable,
2300 .blocked_alertable => unreachable,
2301 .blocked_alertable_canceling => unreachable,
2355 .blocked_apc => unreachable,
2356 .blocked_windows_dns => unreachable,
23022357 .blocked_canceling => unreachable,
23032358 }
23042359}
......@@ -8233,6 +8288,7 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
82338288 const buffer = data[index];
82348289
82358290 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
8291 var done: bool = false;
82368292
82378293 read: {
82388294 const syscall: Syscall = try .start();
......@@ -8240,8 +8296,8 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
82408296 switch (windows.ntdll.NtReadFile(
82418297 file.handle,
82428298 null, // event
8243 noopApc, // apc callback
8244 null, // apc context
8299 flagApc, // apc callback
8300 &done, // apc context
82458301 &io_status_block,
82468302 buffer.ptr,
82478303 @min(std.math.maxInt(u32), buffer.len),
......@@ -8259,12 +8315,12 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
82598315 //else => |status| return syscall.unexpectedNtstatus(status),
82608316 }
82618317 }
8262 try syscall.toApc();
8318 try syscall.toApc(&done);
82638319 while (true) {
82648320 switch (windows.ntdll.NtDelayExecution(1, null)) {
8265 .USER_APC => break syscall.finish(),
8321 .USER_APC => break syscall.finishApc(),
82668322 .SUCCESS, .CANCELLED => {
8267 try syscall.checkCancel();
8323 try syscall.checkCancelApc();
82688324 continue;
82698325 },
82708326 else => |status| std.debug.panic("fileReadStreamingWindows NtDelayExecution returned {t}", .{status}),
......@@ -8282,12 +8338,13 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
82828338 return io_status_block.Information;
82838339}
82848340
8285fn noopApc(
8341fn flagApc(
82868342 apc_context: ?*anyopaque,
82878343 io_status_block: *windows.IO_STATUS_BLOCK,
82888344 unused: windows.ULONG,
82898345) callconv(.winapi) void {
8290 _ = apc_context;
8346 const flag: *bool = @ptrCast(apc_context);
8347 flag.* = true;
82918348 _ = io_status_block;
82928349 _ = unused;
82938350}
......@@ -12254,7 +12311,7 @@ fn netLookupFallible(
1225412311 var res: *ws2_32.ADDRINFOEXW = undefined;
1225512312 const timeout: ?*ws2_32.timeval = null;
1225612313 while (true) {
12257 // TODO: hook this up to cancelation with `NtDelayExecution` and APC callbacks.
12314 // TODO: hook this up to cancelation with `Thread.Status.cancelation.blocked_windows_dns`.
1225812315 try Thread.checkCancel();
1225912316 // TODO make this append to the queue eagerly rather than blocking until the whole thing finishes
1226012317 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, null));
......@@ -15937,8 +15994,8 @@ const parking_futex = struct {
1593715994 .canceled => break :cancelable, // status is still `.canceled`
1593815995 .parked => unreachable,
1593915996 .blocked => unreachable,
15940 .blocked_alertable => unreachable,
15941 .blocked_alertable_canceling => unreachable,
15997 .blocked_apc => unreachable,
15998 .blocked_windows_dns => unreachable,
1594215999 .blocked_canceling => unreachable,
1594316000 }
1594416001 // We could now be unparked for a cancelation at any time!
......@@ -15989,8 +16046,8 @@ const parking_futex = struct {
1598916046 },
1599016047 .canceled => unreachable,
1599116048 .blocked => unreachable,
15992 .blocked_alertable => unreachable,
15993 .blocked_alertable_canceling => unreachable,
16049 .blocked_apc => unreachable,
16050 .blocked_windows_dns => unreachable,
1599416051 .blocked_canceling => unreachable,
1599516052 },
1599616053 }
......@@ -16031,8 +16088,8 @@ const parking_futex = struct {
1603116088 .canceling => continue, // race with a canceler who hasn't called `removeCanceledWaiter` yet
1603216089 .canceled => unreachable,
1603316090 .blocked => unreachable,
16034 .blocked_alertable => unreachable,
16035 .blocked_alertable_canceling => unreachable,
16091 .blocked_apc => unreachable,
16092 .blocked_windows_dns => unreachable,
1603616093 .blocked_canceling => unreachable,
1603716094 }
1603816095 // We're waking this waiter. Remove them from the bucket and add them to our local list.
......@@ -16098,8 +16155,8 @@ const parking_sleep = struct {
1609816155 .canceled => break :cancelable, // status is still `.canceled`
1609916156 .parked => unreachable,
1610016157 .blocked => unreachable,
16101 .blocked_alertable => unreachable,
16102 .blocked_alertable_canceling => unreachable,
16158 .blocked_apc => unreachable,
16159 .blocked_windows_dns => unreachable,
1610316160 .blocked_canceling => unreachable,
1610416161 }
1610516162 while (park(deadline, null)) {
......@@ -16117,8 +16174,8 @@ const parking_sleep = struct {
1611716174 .none => unreachable,
1611816175 .canceled => unreachable,
1611916176 .blocked => unreachable,
16120 .blocked_alertable => unreachable,
16121 .blocked_alertable_canceling => unreachable,
16177 .blocked_apc => unreachable,
16178 .blocked_windows_dns => unreachable,
1612216179 .blocked_canceling => unreachable,
1612316180 }
1612416181 } else |err| switch (err) {
......@@ -16137,8 +16194,8 @@ const parking_sleep = struct {
1613716194 .none => unreachable,
1613816195 .canceled => unreachable,
1613916196 .blocked => unreachable,
16140 .blocked_alertable => unreachable,
16141 .blocked_alertable_canceling => unreachable,
16197 .blocked_apc => unreachable,
16198 .blocked_windows_dns => unreachable,
1614216199 .blocked_canceling => unreachable,
1614316200 },
1614416201 }