authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-23 12:59:36-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-23 12:59:36-08:00
log5c42193b177e4b56ca91acb256cad36dd7cd4dec
tree5e0450cc5e056e88f49ed3464f2693aa10232df4
parent2774436a831194b5a97fc2774ad5570762ed0965

std.Io.Threaded: rework cancelation

Now it can handle sync cancelation and alertable cancelation on Windows. Also fix the API of NtCancelIoFileEx

2 files changed, 193 insertions(+), 59 deletions(-)

lib/std/Io/Threaded.zig+187-56
...@@ -339,7 +339,8 @@ const Group = struct {...@@ -339,7 +339,8 @@ const Group = struct {
339 .canceled => true,339 .canceled => true,
340 .parked => unreachable,340 .parked => unreachable,
341 .blocked => unreachable,341 .blocked => unreachable,
342 .blocked_windows_dns => unreachable,342 .blocked_alertable => unreachable,
343 .blocked_alertable_canceling => unreachable,
343 .blocked_canceling => unreachable,344 .blocked_canceling => unreachable,
344 };345 };
345 if (result) {346 if (result) {
...@@ -542,7 +543,8 @@ const Future = struct {...@@ -542,7 +543,8 @@ const Future = struct {
542 .canceled => true,543 .canceled => true,
543 .parked => unreachable,544 .parked => unreachable,
544 .blocked => unreachable,545 .blocked => unreachable,
545 .blocked_windows_dns => unreachable,546 .blocked_alertable => unreachable,
547 .blocked_alertable_canceling => unreachable,
546 .blocked_canceling => unreachable,548 .blocked_canceling => unreachable,
547 };549 };
548 thread.status.store(.{ .cancelation = .none, .awaitable = .null }, .monotonic);550 thread.status.store(.{ .cancelation = .none, .awaitable = .null }, .monotonic);
...@@ -650,9 +652,11 @@ const Thread = struct {...@@ -650,9 +652,11 @@ const Thread = struct {
650 /// To request cancelation, set the status to `.blocked_canceling` and repeatedly interrupt the system call until the status changes.652 /// To request cancelation, set the status to `.blocked_canceling` and repeatedly interrupt the system call until the status changes.
651 blocked = 0b011,653 blocked = 0b011,
652654
653 /// Windows-only: the thread is blocked in a call to `GetAddrInfoExW`.655 /// Windows-only: the thread is blocked in an alertable wait via
654 /// To request cancelation, set the status to `.canceling` and call `GetAddrInfoExCancel`.656 /// `NtDelayExecution`. To request cancelation, set the status to
655 blocked_windows_dns = 0b010,657 /// `blocked_alertable_canceling` and repeatedly alert the thread
658 /// until the status changes.
659 blocked_alertable = 0b010,
656660
657 /// The thread has an outstanding cancelation request but is not in a cancelable operation.661 /// The thread has an outstanding cancelation request but is not in a cancelable operation.
658 /// When it acknowledges the cancelation, it will set the status to `.canceled`.662 /// When it acknowledges the cancelation, it will set the status to `.canceled`.
...@@ -663,9 +667,16 @@ const Thread = struct {...@@ -663,9 +667,16 @@ const Thread = struct {
663 /// will not change for the remainder of this task's execution.667 /// will not change for the remainder of this task's execution.
664 canceled = 0b111,668 canceled = 0b111,
665669
666 /// The thread is blocked in a cancelable system call, and is being canceled. The thread which triggered the cancelation will send signals to this thread670 /// The thread is blocked in a cancelable system call, and is being
667 /// until its status changes.671 /// canceled. The thread which triggered the cancelation will send
672 /// signals to this thread until its status changes.
668 blocked_canceling = 0b101,673 blocked_canceling = 0b101,
674
675 /// Windows-only: the thread is blocked in an alertable wait via
676 /// `NtDelayExecution`, and is being canceled. The thread which
677 /// triggered the cancelation will send signals to this thread
678 /// until its status changes.
679 blocked_alertable_canceling = 0b100,
669 },680 },
670681
671 /// We cannot turn this value back into a pointer. Instead, it exists so that a task can be682 /// We cannot turn this value back into a pointer. Instead, it exists so that a task can be
...@@ -694,7 +705,8 @@ const Thread = struct {...@@ -694,7 +705,8 @@ const Thread = struct {
694 switch (status.cancelation) {705 switch (status.cancelation) {
695 .parked => unreachable,706 .parked => unreachable,
696 .blocked => unreachable,707 .blocked => unreachable,
697 .blocked_windows_dns => unreachable,708 .blocked_alertable => unreachable,
709 .blocked_alertable_canceling => unreachable,
698 .blocked_canceling => unreachable,710 .blocked_canceling => unreachable,
699 .none, .canceled => {},711 .none, .canceled => {},
700 .canceling => {712 .canceling => {
...@@ -1007,19 +1019,14 @@ const Thread = struct {...@@ -1007,19 +1019,14 @@ const Thread = struct {
1007 .monotonic,1019 .monotonic,
1008 ) orelse return true,1020 ) orelse return true,
10091021
1010 .blocked_windows_dns => thread.status.cmpxchgWeak(1022 .blocked_alertable => thread.status.cmpxchgWeak(
1011 .{ .cancelation = .blocked_windows_dns, .awaitable = awaitable },1023 .{ .cancelation = .blocked_alertable, .awaitable = awaitable },
1012 .{ .cancelation = .canceling, .awaitable = awaitable },1024 .{ .cancelation = .blocked_alertable_canceling, .awaitable = awaitable },
1013 .monotonic,1025 .monotonic,
1014 .monotonic,1026 .monotonic,
1015 ) orelse {1027 ) orelse {
1016 if (builtin.target.os.tag != .windows) unreachable;1028 if (!is_windows) unreachable;
1017 if (true) {1029 return true;
1018 // TODO: cancel Windows DNS queries. This code path is currently impossible
1019 // as `netLookupFallible` doesn't actually use `.blocked_windows_dns` yet.
1020 unreachable;
1021 }
1022 return false;
1023 },1030 },
10241031
1025 .canceling, .canceled => {1032 .canceling, .canceled => {
...@@ -1029,7 +1036,8 @@ const Thread = struct {...@@ -1029,7 +1036,8 @@ const Thread = struct {
1029 return false;1036 return false;
1030 },1037 },
10311038
1032 .blocked_canceling => unreachable,1039 .blocked_canceling => unreachable, // `awaitable` has not been canceled before now
1040 .blocked_alertable_canceling => unreachable, // `awaitable` has not been canceled before now
1033 };1041 };
1034 }1042 }
1035 }1043 }
...@@ -1044,40 +1052,59 @@ const Thread = struct {...@@ -1044,40 +1052,59 @@ const Thread = struct {
1044 /// `Group.waitForCancelWithSignaling`: they use exponential backoff starting at a 1us delay and1052 /// `Group.waitForCancelWithSignaling`: they use exponential backoff starting at a 1us delay and
1045 /// doubling each call. In practice, it is rare to send more than one signal.1053 /// doubling each call. In practice, it is rare to send more than one signal.
1046 fn signalCanceledSyscall(thread: *Thread, t: *Threaded, awaitable: AwaitableId) bool {1054 fn signalCanceledSyscall(thread: *Thread, t: *Threaded, awaitable: AwaitableId) bool {
1047 const bad_status: Status = .{ .cancelation = .blocked_canceling, .awaitable = awaitable };1055 const status = thread.status.load(.monotonic);
1048 if (thread.status.load(.monotonic) != bad_status) return false;1056 if (status.awaitable != awaitable) {
1057 // The thread has moved on and is working on something totally different.
1058 return false;
1059 }
10491060
1050 // The thread ID and/or handle can be read non-atomically because they never change and were1061 // The thread ID and/or handle can be read non-atomically because they never change and were
1051 // released by the store that made `thread` available to us.1062 // released by the store that made `thread` available to us.
10521063
1053 if (std.Thread.use_pthreads) {1064 switch (status.cancelation) {
1054 return switch (std.c.pthread_kill(thread.handle, .IO)) {1065 .blocked_canceling => if (std.Thread.use_pthreads) {
1055 0 => true,1066 return switch (std.c.pthread_kill(thread.handle, .IO)) {
1056 else => false,
1057 };
1058 } else switch (builtin.target.os.tag) {
1059 .linux => {
1060 const pid: posix.pid_t = pid: {
1061 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
1062 if (cached_pid != .unknown) break :pid @intFromEnum(cached_pid);
1063 const pid = std.os.linux.getpid();
1064 @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
1065 break :pid pid;
1066 };
1067 return switch (std.os.linux.tgkill(pid, @bitCast(thread.id), .IO)) {
1068 0 => true,1067 0 => true,
1069 else => false,1068 else => false,
1070 };1069 };
1070 } else switch (native_os) {
1071 .linux => {
1072 const pid: posix.pid_t = pid: {
1073 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
1074 if (cached_pid != .unknown) break :pid @intFromEnum(cached_pid);
1075 const pid = std.os.linux.getpid();
1076 @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
1077 break :pid pid;
1078 };
1079 return switch (std.os.linux.tgkill(pid, @bitCast(thread.id), .IO)) {
1080 0 => true,
1081 else => false,
1082 };
1083 },
1084 .windows => {
1085 var iosb: windows.IO_STATUS_BLOCK = undefined;
1086 return switch (windows.ntdll.NtCancelSynchronousIoFile(thread.handle, null, &iosb)) {
1087 .NOT_FOUND => true, // this might mean the operation hasn't started yet
1088 .SUCCESS => false, // the OS confirmed that our cancelation worked
1089 else => false,
1090 };
1091 },
1092 else => return false,
1071 },1093 },
1072 .windows => {1094
1073 var iosb: windows.IO_STATUS_BLOCK = undefined;1095 .blocked_alertable_canceling => {
1074 return switch (windows.ntdll.NtCancelSynchronousIoFile(thread.handle, null, &iosb)) {1096 if (!is_windows) unreachable;
1075 .NOT_FOUND => true, // this might mean the operation hasn't started yet1097 return switch (windows.ntdll.NtAlertThread(thread.handle)) {
1076 .SUCCESS => false, // the OS confirmed that our cancelation worked1098 .SUCCESS => true,
1077 else => false,1099 else => false,
1078 };1100 };
1079 },1101 },
1080 else => return false,1102
1103 else => {
1104 // The thread is working on `awaitable`, but no longer needs signaling (they already
1105 // woke up and saw the cancelation).
1106 return false;
1107 },
1081 }1108 }
1082 }1109 }
10831110
...@@ -1118,7 +1145,8 @@ const Syscall = struct {...@@ -1118,7 +1145,8 @@ const Syscall = struct {
1118 }, .monotonic).cancelation) {1145 }, .monotonic).cancelation) {
1119 .parked => unreachable,1146 .parked => unreachable,
1120 .blocked => unreachable,1147 .blocked => unreachable,
1121 .blocked_windows_dns => unreachable,1148 .blocked_alertable => unreachable,
1149 .blocked_alertable_canceling => unreachable,
1122 .blocked_canceling => unreachable,1150 .blocked_canceling => unreachable,
1123 .none => return .{ .thread = thread }, // new status is `.blocked`1151 .none => return .{ .thread = thread }, // new status is `.blocked`
1124 .canceling => return error.Canceled, // new status is `.canceled`1152 .canceling => return error.Canceled, // new status is `.canceled`
...@@ -1137,7 +1165,8 @@ const Syscall = struct {...@@ -1137,7 +1165,8 @@ const Syscall = struct {
1137 }, .monotonic).cancelation) {1165 }, .monotonic).cancelation) {
1138 .none => unreachable,1166 .none => unreachable,
1139 .parked => unreachable,1167 .parked => unreachable,
1140 .blocked_windows_dns => unreachable,1168 .blocked_alertable => unreachable,
1169 .blocked_alertable_canceling => unreachable,
1141 .canceling => unreachable,1170 .canceling => unreachable,
1142 .canceled => unreachable,1171 .canceled => unreachable,
1143 .blocked => {}, // new status is `.blocked` (unchanged)1172 .blocked => {}, // new status is `.blocked` (unchanged)
...@@ -1153,13 +1182,41 @@ const Syscall = struct {...@@ -1153,13 +1182,41 @@ const Syscall = struct {
1153 }, .monotonic).cancelation) {1182 }, .monotonic).cancelation) {
1154 .none => unreachable,1183 .none => unreachable,
1155 .parked => unreachable,1184 .parked => unreachable,
1156 .blocked_windows_dns => unreachable,1185 .blocked_alertable => unreachable,
1186 .blocked_alertable_canceling => unreachable,
1157 .canceling => unreachable,1187 .canceling => unreachable,
1158 .canceled => unreachable,1188 .canceled => unreachable,
1159 .blocked => {}, // new status is `.none`1189 .blocked => {}, // new status is `.none`
1160 .blocked_canceling => {}, // new status is `.canceling`1190 .blocked_canceling => {}, // new status is `.canceling`
1161 }1191 }
1162 }1192 }
1193 /// Indicates instead of `NtCancelSynchronousIoFile` we need to use
1194 /// `NtAlertThread` to interrupt the wait.
1195 ///
1196 /// Windows only, called from blocked state only.
1197 fn toAlertable(s: Syscall) Io.Cancelable!AlertableSyscall {
1198 comptime assert(is_windows);
1199 const thread = s.thread orelse return .{ .thread = null };
1200 var prev = thread.status.load(.monotonic);
1201 while (true) prev = switch (prev.cancelation) {
1202 .none => unreachable,
1203 .parked => unreachable,
1204 .blocked_alertable => unreachable,
1205 .blocked_alertable_canceling => unreachable,
1206 .canceling => unreachable,
1207 .canceled => unreachable,
1208
1209 .blocked => thread.status.cmpxchgWeak(prev, .{
1210 .cancelation = .blocked_alertable,
1211 .awaitable = prev.awaitable,
1212 }, .monotonic, .monotonic) orelse return .{ .thread = thread },
1213
1214 .blocked_canceling => thread.status.cmpxchgWeak(prev, .{
1215 .cancelation = .canceled,
1216 .awaitable = prev.awaitable,
1217 }, .monotonic, .monotonic) orelse return error.Canceled,
1218 };
1219 }
1163 /// Convenience wrapper which calls `finish`, then returns `err`.1220 /// Convenience wrapper which calls `finish`, then returns `err`.
1164 fn fail(s: Syscall, err: anytype) @TypeOf(err) {1221 fn fail(s: Syscall, err: anytype) @TypeOf(err) {
1165 s.finish();1222 s.finish();
...@@ -1191,6 +1248,72 @@ const Syscall = struct {...@@ -1191,6 +1248,72 @@ const Syscall = struct {
1191 }1248 }
1192};1249};
11931250
1251const AlertableSyscall = struct {
1252 thread: ?*Thread,
1253
1254 comptime {
1255 assert(is_windows);
1256 }
1257
1258 fn checkCancel(s: AlertableSyscall) Io.Cancelable!void {
1259 comptime assert(is_windows);
1260 const thread = s.thread orelse return;
1261 const old_status = thread.status.fetchOr(.{
1262 .cancelation = @enumFromInt(0b010),
1263 .awaitable = .null,
1264 }, .monotonic);
1265 switch (old_status.cancelation) {
1266 .none => unreachable,
1267 .parked => unreachable,
1268 .blocked => unreachable,
1269 .blocked_canceling => unreachable,
1270 .canceling => unreachable,
1271 .canceled => unreachable,
1272 .blocked_alertable => {}, // new status is `.blocked_alertable` (unchanged)
1273 .blocked_alertable_canceling => {
1274 // New status is `.canceling`---change to `.canceled` before return.
1275 thread.status.store(.{ .cancelation = .canceled, .awaitable = old_status.awaitable }, .monotonic);
1276 return error.Canceled;
1277 },
1278 }
1279 }
1280
1281 fn finish(s: AlertableSyscall) void {
1282 comptime assert(is_windows);
1283 const thread = s.thread orelse return;
1284 switch (thread.status.fetchXor(.{
1285 .cancelation = @enumFromInt(0b010),
1286 .awaitable = .null,
1287 }, .monotonic).cancelation) {
1288 .none => unreachable,
1289 .parked => unreachable,
1290 .blocked => unreachable,
1291 .blocked_canceling => unreachable,
1292 .canceling => unreachable,
1293 .canceled => unreachable,
1294 .blocked_alertable => {}, // new status is `.none`
1295 .blocked_alertable_canceling => {}, // new status is `.canceling`
1296 }
1297 }
1298
1299 fn fail(s: AlertableSyscall, err: anytype) @TypeOf(err) {
1300 s.finish();
1301 return err;
1302 }
1303
1304 fn ntstatusBug(s: AlertableSyscall, status: windows.NTSTATUS) Io.UnexpectedError {
1305 @branchHint(.cold);
1306 s.finish();
1307 return windows.statusBug(status);
1308 }
1309
1310 fn unexpectedNtstatus(s: AlertableSyscall, status: windows.NTSTATUS) Io.UnexpectedError {
1311 @branchHint(.cold);
1312 s.finish();
1313 return windows.unexpectedStatus(status);
1314 }
1315};
1316
1194const max_iovecs_len = 8;1317const max_iovecs_len = 8;
1195const splat_buffer_size = 64;1318const splat_buffer_size = 64;
1196const default_PATH = "/usr/local/bin:/bin/:/usr/bin";1319const default_PATH = "/usr/local/bin:/bin/:/usr/bin";
...@@ -1977,7 +2100,8 @@ fn groupAsyncEager(...@@ -1977,7 +2100,8 @@ fn groupAsyncEager(
1977 .canceled => true,2100 .canceled => true,
1978 .parked => unreachable,2101 .parked => unreachable,
1979 .blocked => unreachable,2102 .blocked => unreachable,
1980 .blocked_windows_dns => unreachable,2103 .blocked_alertable => unreachable,
2104 .blocked_alertable_canceling => unreachable,
1981 .blocked_canceling => unreachable,2105 .blocked_canceling => unreachable,
1982 };2106 };
1983 } else false;2107 } else false;
...@@ -1988,7 +2112,8 @@ fn groupAsyncEager(...@@ -1988,7 +2112,8 @@ fn groupAsyncEager(
1988 .canceled => true,2112 .canceled => true,
1989 .parked => unreachable,2113 .parked => unreachable,
1990 .blocked => unreachable,2114 .blocked => unreachable,
1991 .blocked_windows_dns => unreachable,2115 .blocked_alertable => unreachable,
2116 .blocked_alertable_canceling => unreachable,
1992 .blocked_canceling => unreachable,2117 .blocked_canceling => unreachable,
1993 };2118 };
1994 } else false;2119 } else false;
...@@ -2167,7 +2292,8 @@ fn recancelInner() void {...@@ -2167,7 +2292,8 @@ fn recancelInner() void {
2167 .canceling => unreachable, // called `recancel` but cancelation was already pending2292 .canceling => unreachable, // called `recancel` but cancelation was already pending
2168 .parked => unreachable,2293 .parked => unreachable,
2169 .blocked => unreachable,2294 .blocked => unreachable,
2170 .blocked_windows_dns => unreachable,2295 .blocked_alertable => unreachable,
2296 .blocked_alertable_canceling => unreachable,
2171 .blocked_canceling => unreachable,2297 .blocked_canceling => unreachable,
2172 }2298 }
2173}2299}
...@@ -12096,8 +12222,7 @@ fn netLookupFallible(...@@ -12096,8 +12222,7 @@ fn netLookupFallible(
12096 var res: *ws2_32.ADDRINFOEXW = undefined;12222 var res: *ws2_32.ADDRINFOEXW = undefined;
12097 const timeout: ?*ws2_32.timeval = null;12223 const timeout: ?*ws2_32.timeval = null;
12098 while (true) {12224 while (true) {
12099 // TODO: hook this up to cancelation with `Thread.Status.cancelation.blocked_windows_dns`.12225 // TODO: hook this up to cancelation with `NtDelayExecution` and APC callbacks.
12100 // See matching TODO in `Thread.cancelAwaitable`.
12101 try Thread.checkCancel();12226 try Thread.checkCancel();
12102 // TODO make this append to the queue eagerly rather than blocking until the whole thing finishes12227 // TODO make this append to the queue eagerly rather than blocking until the whole thing finishes
12103 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, null));12228 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, null));
...@@ -15780,7 +15905,8 @@ const parking_futex = struct {...@@ -15780,7 +15905,8 @@ const parking_futex = struct {
15780 .canceled => break :cancelable, // status is still `.canceled`15905 .canceled => break :cancelable, // status is still `.canceled`
15781 .parked => unreachable,15906 .parked => unreachable,
15782 .blocked => unreachable,15907 .blocked => unreachable,
15783 .blocked_windows_dns => unreachable,15908 .blocked_alertable => unreachable,
15909 .blocked_alertable_canceling => unreachable,
15784 .blocked_canceling => unreachable,15910 .blocked_canceling => unreachable,
15785 }15911 }
15786 // We could now be unparked for a cancelation at any time!15912 // We could now be unparked for a cancelation at any time!
...@@ -15831,7 +15957,8 @@ const parking_futex = struct {...@@ -15831,7 +15957,8 @@ const parking_futex = struct {
15831 },15957 },
15832 .canceled => unreachable,15958 .canceled => unreachable,
15833 .blocked => unreachable,15959 .blocked => unreachable,
15834 .blocked_windows_dns => unreachable,15960 .blocked_alertable => unreachable,
15961 .blocked_alertable_canceling => unreachable,
15835 .blocked_canceling => unreachable,15962 .blocked_canceling => unreachable,
15836 },15963 },
15837 }15964 }
...@@ -15872,7 +15999,8 @@ const parking_futex = struct {...@@ -15872,7 +15999,8 @@ const parking_futex = struct {
15872 .canceling => continue, // race with a canceler who hasn't called `removeCanceledWaiter` yet15999 .canceling => continue, // race with a canceler who hasn't called `removeCanceledWaiter` yet
15873 .canceled => unreachable,16000 .canceled => unreachable,
15874 .blocked => unreachable,16001 .blocked => unreachable,
15875 .blocked_windows_dns => unreachable,16002 .blocked_alertable => unreachable,
16003 .blocked_alertable_canceling => unreachable,
15876 .blocked_canceling => unreachable,16004 .blocked_canceling => unreachable,
15877 }16005 }
15878 // We're waking this waiter. Remove them from the bucket and add them to our local list.16006 // We're waking this waiter. Remove them from the bucket and add them to our local list.
...@@ -15938,7 +16066,8 @@ const parking_sleep = struct {...@@ -15938,7 +16066,8 @@ const parking_sleep = struct {
15938 .canceled => break :cancelable, // status is still `.canceled`16066 .canceled => break :cancelable, // status is still `.canceled`
15939 .parked => unreachable,16067 .parked => unreachable,
15940 .blocked => unreachable,16068 .blocked => unreachable,
15941 .blocked_windows_dns => unreachable,16069 .blocked_alertable => unreachable,
16070 .blocked_alertable_canceling => unreachable,
15942 .blocked_canceling => unreachable,16071 .blocked_canceling => unreachable,
15943 }16072 }
15944 while (park(deadline, null)) {16073 while (park(deadline, null)) {
...@@ -15956,7 +16085,8 @@ const parking_sleep = struct {...@@ -15956,7 +16085,8 @@ const parking_sleep = struct {
15956 .none => unreachable,16085 .none => unreachable,
15957 .canceled => unreachable,16086 .canceled => unreachable,
15958 .blocked => unreachable,16087 .blocked => unreachable,
15959 .blocked_windows_dns => unreachable,16088 .blocked_alertable => unreachable,
16089 .blocked_alertable_canceling => unreachable,
15960 .blocked_canceling => unreachable,16090 .blocked_canceling => unreachable,
15961 }16091 }
15962 } else |err| switch (err) {16092 } else |err| switch (err) {
...@@ -15975,7 +16105,8 @@ const parking_sleep = struct {...@@ -15975,7 +16105,8 @@ const parking_sleep = struct {
15975 .none => unreachable,16105 .none => unreachable,
15976 .canceled => unreachable,16106 .canceled => unreachable,
15977 .blocked => unreachable,16107 .blocked => unreachable,
15978 .blocked_windows_dns => unreachable,16108 .blocked_alertable => unreachable,
16109 .blocked_alertable_canceling => unreachable,
15979 .blocked_canceling => unreachable,16110 .blocked_canceling => unreachable,
15980 },16111 },
15981 }16112 }
lib/std/os/windows/ntdll.zig+6-3
...@@ -596,8 +596,11 @@ pub extern "ntdll" fn NtDelayExecution(...@@ -596,8 +596,11 @@ pub extern "ntdll" fn NtDelayExecution(
596596
597pub extern "ntdll" fn NtCancelIoFileEx(597pub extern "ntdll" fn NtCancelIoFileEx(
598 FileHandle: HANDLE,598 FileHandle: HANDLE,
599 /// Documentation has this as IO_STATUS_BLOCK but it's actually the APC599 IoRequestToCancel: *const IO_STATUS_BLOCK,
600 /// context parameter.
601 IoRequestToCancel: ?*anyopaque,
602 IoStatusBlock: *IO_STATUS_BLOCK,600 IoStatusBlock: *IO_STATUS_BLOCK,
603) callconv(.winapi) NTSTATUS;601) callconv(.winapi) NTSTATUS;
602
603pub extern "ntdll" fn NtCancelIoFile(
604 handle: HANDLE,
605 iosbToCancel: *const IO_STATUS_BLOCK,
606) callconv(.winapi) NTSTATUS;