| ... | ... | @@ -339,8 +339,8 @@ const Group = struct { |
| 339 | 339 | .canceled => true, |
| 340 | 340 | .parked => unreachable, |
| 341 | 341 | .blocked => unreachable, |
| 342 | | .blocked_apc => unreachable, |
| 343 | | .blocked_windows_dns => unreachable, |
| 342 | .blocked_alertable => unreachable, |
| 343 | .blocked_alertable_canceling => unreachable, |
| 344 | 344 | .blocked_canceling => unreachable, |
| 345 | 345 | }; |
| 346 | 346 | if (result) { |
| ... | ... | @@ -379,10 +379,7 @@ const Group = struct { |
| 379 | 379 | while (it) |thread| : (it = thread.next) { |
| 380 | 380 | // This non-mutating RMW exists for ordering reasons: see comment in `Group.Task.start` for reasons. |
| 381 | 381 | _ = thread.status.fetchOr(.{ .cancelation = @enumFromInt(0), .awaitable = .null }, .release); |
| 382 | | if (thread.cancelAwaitable(.fromGroup(g.ptr))) |method| { |
| 383 | | thread.interrupt_method = method; |
| 384 | | any_blocked = true; |
| 385 | | } |
| 382 | if (thread.cancelAwaitable(.fromGroup(g.ptr))) any_blocked = true; |
| 386 | 383 | } |
| 387 | 384 | return any_blocked; |
| 388 | 385 | } |
| ... | ... | @@ -394,7 +391,7 @@ const Group = struct { |
| 394 | 391 | var any_signaled = false; |
| 395 | 392 | var it = t.worker_threads.load(.acquire); // acquire `Thread` values |
| 396 | 393 | while (it) |thread| : (it = thread.next) { |
| 397 | | if (thread.signalCanceledSyscall(t, .fromGroup(g.ptr), thread.interrupt_method)) any_signaled = true; |
| 394 | if (thread.signalCanceledSyscall(t, .fromGroup(g.ptr))) any_signaled = true; |
| 398 | 395 | } |
| 399 | 396 | return any_signaled; |
| 400 | 397 | } |
| ... | ... | @@ -546,8 +543,8 @@ const Future = struct { |
| 546 | 543 | .canceled => true, |
| 547 | 544 | .parked => unreachable, |
| 548 | 545 | .blocked => unreachable, |
| 549 | | .blocked_apc => unreachable, |
| 550 | | .blocked_windows_dns => unreachable, |
| 546 | .blocked_alertable => unreachable, |
| 547 | .blocked_alertable_canceling => unreachable, |
| 551 | 548 | .blocked_canceling => unreachable, |
| 552 | 549 | }; |
| 553 | 550 | thread.status.store(.{ .cancelation = .none, .awaitable = .null }, .monotonic); |
| ... | ... | @@ -576,15 +573,11 @@ const Future = struct { |
| 576 | 573 | num_completed: *std.atomic.Value(u32), |
| 577 | 574 | thread: ?*Thread, |
| 578 | 575 | ) void { |
| 579 | | var interrupt_method: ?Thread.InterruptMethod = |
| 580 | | if (thread) |th| th.cancelAwaitable(.fromFuture(future)) else null; |
| 576 | var need_signal: bool = if (thread) |th| th.cancelAwaitable(.fromFuture(future)) else false; |
| 581 | 577 | var timeout_ns: u64 = 1 << 10; |
| 582 | 578 | while (true) { |
| 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); |
| 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); |
| 588 | 581 | switch (num_completed.load(.acquire)) { // acquire task results |
| 589 | 582 | 0 => {}, |
| 590 | 583 | 1 => break, |
| ... | ... | @@ -632,17 +625,9 @@ const Thread = struct { |
| 632 | 625 | cancel_protection: Io.CancelProtection, |
| 633 | 626 | /// Always released when `Status.cancelation` is set to `.parked`. |
| 634 | 627 | futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn, |
| 635 | | apc: Apc, |
| 636 | | /// Used only by group cancelation code for temporary storage. |
| 637 | | interrupt_method: InterruptMethod, |
| 638 | 628 | |
| 639 | 629 | csprng: Csprng, |
| 640 | 630 | |
| 641 | | const Apc = if (is_windows) struct { |
| 642 | | handle: windows.HANDLE, |
| 643 | | iosb: ?*windows.IO_STATUS_BLOCK, |
| 644 | | } else void; |
| 645 | | |
| 646 | 631 | const Handle = Handle: { |
| 647 | 632 | if (std.Thread.use_pthreads) break :Handle std.c.pthread_t; |
| 648 | 633 | if (is_windows) break :Handle windows.HANDLE; |
| ... | ... | @@ -667,13 +652,11 @@ const Thread = struct { |
| 667 | 652 | /// To request cancelation, set the status to `.blocked_canceling` and repeatedly interrupt the system call until the status changes. |
| 668 | 653 | blocked = 0b011, |
| 669 | 654 | |
| 670 | | /// Windows-only: the thread is blocked in a call to `NtDelayExecution`. |
| 671 | | /// To request cancelation, set the status to `.canceling` and call `NtCancelIoFileEx`. |
| 672 | | blocked_apc = 0b100, |
| 673 | | |
| 674 | | /// Windows-only: the thread is blocked in a call to `GetAddrInfoExW`. |
| 675 | | /// To request cancelation, set the status to `.canceling` and call `GetAddrInfoExCancel`. |
| 676 | | blocked_windows_dns = 0b010, |
| 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, |
| 677 | 660 | |
| 678 | 661 | /// The thread has an outstanding cancelation request but is not in a cancelable operation. |
| 679 | 662 | /// When it acknowledges the cancelation, it will set the status to `.canceled`. |
| ... | ... | @@ -722,8 +705,8 @@ const Thread = struct { |
| 722 | 705 | switch (status.cancelation) { |
| 723 | 706 | .parked => unreachable, |
| 724 | 707 | .blocked => unreachable, |
| 725 | | .blocked_apc => unreachable, |
| 726 | | .blocked_windows_dns => unreachable, |
| 708 | .blocked_alertable => unreachable, |
| 709 | .blocked_alertable_canceling => unreachable, |
| 727 | 710 | .blocked_canceling => unreachable, |
| 728 | 711 | .none, .canceled => {}, |
| 729 | 712 | .canceling => { |
| ... | ... | @@ -1003,17 +986,17 @@ const Thread = struct { |
| 1003 | 986 | /// It is possible that `thread` gets canceled by this function, but is blocked in a syscall. In |
| 1004 | 987 | /// that case, the thread may need to be sent a signal to interrupt the call. This function will |
| 1005 | 988 | /// return `true` to indicate this, in which case the caller must call `signalCanceledSyscall`. |
| 1006 | | fn cancelAwaitable(thread: *Thread, awaitable: AwaitableId) ?InterruptMethod { |
| 989 | fn cancelAwaitable(thread: *Thread, awaitable: AwaitableId) bool { |
| 1007 | 990 | var status = thread.status.load(.monotonic); |
| 1008 | 991 | while (true) { |
| 1009 | | if (status.awaitable != awaitable) return null; // thread is working on something else |
| 992 | if (status.awaitable != awaitable) return false; // thread is working on something else |
| 1010 | 993 | status = switch (status.cancelation) { |
| 1011 | 994 | .none => thread.status.cmpxchgWeak( |
| 1012 | 995 | .{ .cancelation = .none, .awaitable = awaitable }, |
| 1013 | 996 | .{ .cancelation = .canceling, .awaitable = awaitable }, |
| 1014 | 997 | .monotonic, |
| 1015 | 998 | .monotonic, |
| 1016 | | ) orelse return null, |
| 999 | ) orelse return false, |
| 1017 | 1000 | |
| 1018 | 1001 | .parked => thread.status.cmpxchgWeak( |
| 1019 | 1002 | .{ .cancelation = .parked, .awaitable = awaitable }, |
| ... | ... | @@ -1026,7 +1009,7 @@ const Thread = struct { |
| 1026 | 1009 | parking_futex.removeCanceledWaiter(futex_waiter); |
| 1027 | 1010 | } |
| 1028 | 1011 | unpark(&.{thread.id}, null); |
| 1029 | | return null; |
| 1012 | return false; |
| 1030 | 1013 | }, |
| 1031 | 1014 | |
| 1032 | 1015 | .blocked => thread.status.cmpxchgWeak( |
| ... | ... | @@ -1034,17 +1017,7 @@ const Thread = struct { |
| 1034 | 1017 | .{ .cancelation = .blocked_canceling, .awaitable = awaitable }, |
| 1035 | 1018 | .monotonic, |
| 1036 | 1019 | .monotonic, |
| 1037 | | ) orelse return .sync, |
| 1038 | | |
| 1039 | | .blocked_apc => thread.status.cmpxchgWeak( |
| 1040 | | .{ .cancelation = .blocked_apc, .awaitable = awaitable }, |
| 1041 | | .{ .cancelation = .canceling, .awaitable = awaitable }, |
| 1042 | | .monotonic, |
| 1043 | | .monotonic, |
| 1044 | | ) orelse { |
| 1045 | | if (!is_windows) unreachable; |
| 1046 | | return .apc; |
| 1047 | | }, |
| 1020 | ) orelse return true, |
| 1048 | 1021 | |
| 1049 | 1022 | .blocked_alertable => thread.status.cmpxchgWeak( |
| 1050 | 1023 | .{ .cancelation = .blocked_alertable, .awaitable = awaitable }, |
| ... | ... | @@ -1053,14 +1026,14 @@ const Thread = struct { |
| 1053 | 1026 | .monotonic, |
| 1054 | 1027 | ) orelse { |
| 1055 | 1028 | if (!is_windows) unreachable; |
| 1056 | | return .dns; |
| 1029 | return true; |
| 1057 | 1030 | }, |
| 1058 | 1031 | |
| 1059 | 1032 | .canceling, .canceled => { |
| 1060 | 1033 | // This can happen when the task start raced with the cancelation, so the thread |
| 1061 | 1034 | // saw the cancelation on the future/group *and* we are trying to signal the |
| 1062 | 1035 | // thread here. |
| 1063 | | return null; |
| 1036 | return false; |
| 1064 | 1037 | }, |
| 1065 | 1038 | |
| 1066 | 1039 | .blocked_canceling => unreachable, // `awaitable` has not been canceled before now |
| ... | ... | @@ -1069,11 +1042,6 @@ const Thread = struct { |
| 1069 | 1042 | } |
| 1070 | 1043 | } |
| 1071 | 1044 | |
| 1072 | | const InterruptMethod = switch (native_os) { |
| 1073 | | .windows => enum { sync, dns, apc }, |
| 1074 | | else => enum { sync }, |
| 1075 | | }; |
| 1076 | | |
| 1077 | 1045 | /// Sends a signal to `thread` if it is still blocked in a syscall (i.e. has not yet observed |
| 1078 | 1046 | /// the cancelation request from `cancelAwaitable`). |
| 1079 | 1047 | /// |
| ... | ... | @@ -1083,21 +1051,24 @@ const Thread = struct { |
| 1083 | 1051 | /// the thread is still blocked. For the implementation, `Future.waitForCancelWithSignaling` and |
| 1084 | 1052 | /// `Group.waitForCancelWithSignaling`: they use exponential backoff starting at a 1us delay and |
| 1085 | 1053 | /// doubling each call. In practice, it is rare to send more than one signal. |
| 1086 | | fn signalCanceledSyscall(thread: *Thread, t: *Threaded, awaitable: AwaitableId, method: InterruptMethod) bool { |
| 1087 | | const bad_status: Status = .{ .cancelation = .blocked_canceling, .awaitable = awaitable }; |
| 1088 | | if (thread.status.load(.monotonic) != bad_status) return false; |
| 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 | } |
| 1089 | 1060 | |
| 1090 | 1061 | // The thread ID and/or handle can be read non-atomically because they never change and were |
| 1091 | 1062 | // released by the store that made `thread` available to us. |
| 1092 | 1063 | |
| 1093 | | if (std.Thread.use_pthreads) switch (method) { |
| 1094 | | .sync => return switch (std.c.pthread_kill(thread.handle, .IO)) { |
| 1095 | | 0 => true, |
| 1096 | | else => false, |
| 1097 | | }, |
| 1098 | | } else switch (native_os) { |
| 1099 | | .linux => switch (method) { |
| 1100 | | .sync => { |
| 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 => { |
| 1101 | 1072 | const pid: posix.pid_t = pid: { |
| 1102 | 1073 | const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic); |
| 1103 | 1074 | if (cached_pid != .unknown) break :pid @intFromEnum(cached_pid); |
| ... | ... | @@ -1110,9 +1081,7 @@ const Thread = struct { |
| 1110 | 1081 | else => false, |
| 1111 | 1082 | }; |
| 1112 | 1083 | }, |
| 1113 | | }, |
| 1114 | | .windows => switch (method) { |
| 1115 | | .sync => { |
| 1084 | .windows => { |
| 1116 | 1085 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 1117 | 1086 | return switch (windows.ntdll.NtCancelSynchronousIoFile(thread.handle, null, &iosb)) { |
| 1118 | 1087 | .NOT_FOUND => true, // this might mean the operation hasn't started yet |
| ... | ... | @@ -1120,15 +1089,15 @@ const Thread = struct { |
| 1120 | 1089 | else => false, |
| 1121 | 1090 | }; |
| 1122 | 1091 | }, |
| 1123 | | .dns => @panic("TODO call GetAddrInfoExCancel"), |
| 1124 | | .apc => { |
| 1125 | | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 1126 | | return switch (windows.ntdll.NtCancelIoFileEx(thread.apc.handle, thread.apc.iosb, &iosb)) { |
| 1127 | | .NOT_FOUND => true, // this might mean the operation hasn't started yet |
| 1128 | | .SUCCESS => false, // the OS confirmed that our cancelation worked |
| 1129 | | else => false, |
| 1130 | | }; |
| 1131 | | }, |
| 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 | }; |
| 1132 | 1101 | }, |
| 1133 | 1102 | |
| 1134 | 1103 | else => { |
| ... | ... | @@ -1176,8 +1145,8 @@ const Syscall = struct { |
| 1176 | 1145 | }, .monotonic).cancelation) { |
| 1177 | 1146 | .parked => unreachable, |
| 1178 | 1147 | .blocked => unreachable, |
| 1179 | | .blocked_apc => unreachable, |
| 1180 | | .blocked_windows_dns => unreachable, |
| 1148 | .blocked_alertable => unreachable, |
| 1149 | .blocked_alertable_canceling => unreachable, |
| 1181 | 1150 | .blocked_canceling => unreachable, |
| 1182 | 1151 | .none => return .{ .thread = thread }, // new status is `.blocked` |
| 1183 | 1152 | .canceling => return error.Canceled, // new status is `.canceled` |
| ... | ... | @@ -1196,8 +1165,8 @@ const Syscall = struct { |
| 1196 | 1165 | }, .monotonic).cancelation) { |
| 1197 | 1166 | .none => unreachable, |
| 1198 | 1167 | .parked => unreachable, |
| 1199 | | .blocked_apc => unreachable, |
| 1200 | | .blocked_windows_dns => unreachable, |
| 1168 | .blocked_alertable => unreachable, |
| 1169 | .blocked_alertable_canceling => unreachable, |
| 1201 | 1170 | .canceling => unreachable, |
| 1202 | 1171 | .canceled => unreachable, |
| 1203 | 1172 | .blocked => {}, // new status is `.blocked` (unchanged) |
| ... | ... | @@ -1213,8 +1182,8 @@ const Syscall = struct { |
| 1213 | 1182 | }, .monotonic).cancelation) { |
| 1214 | 1183 | .none => unreachable, |
| 1215 | 1184 | .parked => unreachable, |
| 1216 | | .blocked_apc => unreachable, |
| 1217 | | .blocked_windows_dns => unreachable, |
| 1185 | .blocked_alertable => unreachable, |
| 1186 | .blocked_alertable_canceling => unreachable, |
| 1218 | 1187 | .canceling => unreachable, |
| 1219 | 1188 | .canceled => unreachable, |
| 1220 | 1189 | .blocked => {}, // new status is `.none` |
| ... | ... | @@ -1222,25 +1191,25 @@ const Syscall = struct { |
| 1222 | 1191 | } |
| 1223 | 1192 | } |
| 1224 | 1193 | /// Indicates instead of `NtCancelSynchronousIoFile` we need to use |
| 1225 | | /// `NtCancelIoFileEx` to interrupt the wait. |
| 1194 | /// `NtAlertThread` to interrupt the wait. |
| 1226 | 1195 | /// |
| 1227 | 1196 | /// Windows only, called from blocked state only. |
| 1228 | | fn toApc(s: Syscall, apc: Thread.Apc) Io.Cancelable!void { |
| 1229 | | const thread = s.thread orelse return; |
| 1230 | | thread.apc = apc; |
| 1197 | fn toAlertable(s: Syscall) Io.Cancelable!AlertableSyscall { |
| 1198 | comptime assert(is_windows); |
| 1199 | const thread = s.thread orelse return .{ .thread = null }; |
| 1231 | 1200 | var prev = thread.status.load(.monotonic); |
| 1232 | 1201 | while (true) prev = switch (prev.cancelation) { |
| 1233 | 1202 | .none => unreachable, |
| 1234 | 1203 | .parked => unreachable, |
| 1235 | | .blocked_apc => unreachable, |
| 1236 | | .blocked_windows_dns => unreachable, |
| 1204 | .blocked_alertable => unreachable, |
| 1205 | .blocked_alertable_canceling => unreachable, |
| 1237 | 1206 | .canceling => unreachable, |
| 1238 | 1207 | .canceled => unreachable, |
| 1239 | 1208 | |
| 1240 | 1209 | .blocked => thread.status.cmpxchgWeak(prev, .{ |
| 1241 | | .cancelation = .blocked_apc, |
| 1210 | .cancelation = .blocked_alertable, |
| 1242 | 1211 | .awaitable = prev.awaitable, |
| 1243 | | }, .monotonic, .monotonic) orelse return, |
| 1212 | }, .monotonic, .monotonic) orelse return .{ .thread = thread }, |
| 1244 | 1213 | |
| 1245 | 1214 | .blocked_canceling => thread.status.cmpxchgWeak(prev, .{ |
| 1246 | 1215 | .cancelation = .canceled, |
| ... | ... | @@ -1248,45 +1217,6 @@ const Syscall = struct { |
| 1248 | 1217 | }, .monotonic, .monotonic) orelse return error.Canceled, |
| 1249 | 1218 | }; |
| 1250 | 1219 | } |
| 1251 | | /// Windows only, called from blocked_apc state only. |
| 1252 | | fn checkCancelApc(s: Syscall) Io.Cancelable!void { |
| 1253 | | const thread = s.thread orelse return; |
| 1254 | | var prev = thread.status.load(.monotonic); |
| 1255 | | while (true) prev = switch (prev.cancelation) { |
| 1256 | | .none => unreachable, |
| 1257 | | .parked => unreachable, |
| 1258 | | .blocked_windows_dns => unreachable, |
| 1259 | | .blocked => unreachable, |
| 1260 | | .canceling => unreachable, |
| 1261 | | .canceled => unreachable, |
| 1262 | | .blocked_apc => return, |
| 1263 | | .blocked_canceling => thread.status.cmpxchgWeak(prev, .{ |
| 1264 | | .cancelation = .canceled, |
| 1265 | | .awaitable = prev.awaitable, |
| 1266 | | }, .monotonic, .monotonic) orelse return error.Canceled, |
| 1267 | | }; |
| 1268 | | } |
| 1269 | | /// Windows only, called from blocked_apc state only. |
| 1270 | | fn finishApc(s: Syscall) void { |
| 1271 | | const thread = s.thread orelse return; |
| 1272 | | var prev = thread.status.load(.monotonic); |
| 1273 | | while (true) prev = switch (prev.cancelation) { |
| 1274 | | .none => unreachable, |
| 1275 | | .parked => unreachable, |
| 1276 | | .blocked_windows_dns => unreachable, |
| 1277 | | .blocked => unreachable, |
| 1278 | | .canceling => unreachable, |
| 1279 | | .canceled => unreachable, |
| 1280 | | .blocked_apc => thread.status.cmpxchgWeak(prev, .{ |
| 1281 | | .cancelation = .none, |
| 1282 | | .awaitable = prev.awaitable, |
| 1283 | | }, .monotonic, .monotonic) orelse return, |
| 1284 | | .blocked_canceling => thread.status.cmpxchgWeak(prev, .{ |
| 1285 | | .cancelation = .canceling, |
| 1286 | | .awaitable = prev.awaitable, |
| 1287 | | }, .monotonic, .monotonic) orelse return, |
| 1288 | | }; |
| 1289 | | } |
| 1290 | 1220 | /// Convenience wrapper which calls `finish`, then returns `err`. |
| 1291 | 1221 | fn fail(s: Syscall, err: anytype) @TypeOf(err) { |
| 1292 | 1222 | s.finish(); |
| ... | ... | @@ -1566,8 +1496,6 @@ fn worker(t: *Threaded) void { |
| 1566 | 1496 | .cancel_protection = .unblocked, |
| 1567 | 1497 | .futex_waiter = undefined, |
| 1568 | 1498 | .csprng = .{}, |
| 1569 | | .apc = undefined, |
| 1570 | | .interrupt_method = undefined, |
| 1571 | 1499 | }; |
| 1572 | 1500 | Thread.current = &thread; |
| 1573 | 1501 | |
| ... | ... | @@ -2176,8 +2104,8 @@ fn groupAsyncEager( |
| 2176 | 2104 | .canceled => true, |
| 2177 | 2105 | .parked => unreachable, |
| 2178 | 2106 | .blocked => unreachable, |
| 2179 | | .blocked_apc => unreachable, |
| 2180 | | .blocked_windows_dns => unreachable, |
| 2107 | .blocked_alertable => unreachable, |
| 2108 | .blocked_alertable_canceling => unreachable, |
| 2181 | 2109 | .blocked_canceling => unreachable, |
| 2182 | 2110 | }; |
| 2183 | 2111 | } else false; |
| ... | ... | @@ -2188,8 +2116,8 @@ fn groupAsyncEager( |
| 2188 | 2116 | .canceled => true, |
| 2189 | 2117 | .parked => unreachable, |
| 2190 | 2118 | .blocked => unreachable, |
| 2191 | | .blocked_apc => unreachable, |
| 2192 | | .blocked_windows_dns => unreachable, |
| 2119 | .blocked_alertable => unreachable, |
| 2120 | .blocked_alertable_canceling => unreachable, |
| 2193 | 2121 | .blocked_canceling => unreachable, |
| 2194 | 2122 | }; |
| 2195 | 2123 | } else false; |
| ... | ... | @@ -2368,8 +2296,8 @@ fn recancelInner() void { |
| 2368 | 2296 | .canceling => unreachable, // called `recancel` but cancelation was already pending |
| 2369 | 2297 | .parked => unreachable, |
| 2370 | 2298 | .blocked => unreachable, |
| 2371 | | .blocked_apc => unreachable, |
| 2372 | | .blocked_windows_dns => unreachable, |
| 2299 | .blocked_alertable => unreachable, |
| 2300 | .blocked_alertable_canceling => unreachable, |
| 2373 | 2301 | .blocked_canceling => unreachable, |
| 2374 | 2302 | } |
| 2375 | 2303 | } |
| ... | ... | @@ -8467,36 +8395,37 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us |
| 8467 | 8395 | continue; |
| 8468 | 8396 | }, |
| 8469 | 8397 | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), // streaming read of async mode file |
| 8470 | | else => |status| std.debug.panic("fileReadStreamingWindows NtReadFile returned {t}", .{status}), |
| 8471 | | //else => |status| return syscall.unexpectedNtstatus(status), |
| 8398 | else => |status| return syscall.unexpectedNtstatus(status), |
| 8472 | 8399 | } |
| 8473 | 8400 | } |
| 8474 | | try syscall.toApc(.{ .handle = file.handle, .iosb = &io_status_block }); |
| 8475 | | while (true) { |
| 8476 | | switch (windows.ntdll.NtDelayExecution(1, &infinite)) { |
| 8477 | | .USER_APC => { |
| 8478 | | if (!done) { |
| 8479 | | // Other APC work was queued before calling into this function. |
| 8480 | | try syscall.checkCancelApc(); |
| 8481 | | continue; |
| 8482 | | } |
| 8483 | | break syscall.finishApc(); |
| 8484 | | }, |
| 8485 | | .SUCCESS, .CANCELLED, .TIMEOUT, .ALERTED => { |
| 8486 | | try syscall.checkCancelApc(); |
| 8487 | | continue; |
| 8401 | // Once we get here we received PENDING so we must not return from the |
| 8402 | // function until the operation completes. |
| 8403 | defer while (!done) { |
| 8404 | _ = windows.ntdll.NtDelayExecution(1, &infinite); |
| 8405 | }; |
| 8406 | |
| 8407 | const alertable_syscall = syscall.toAlertable() catch |err| switch (err) { |
| 8408 | error.Canceled => |e| { |
| 8409 | _ = windows.ntdll.NtCancelIoFile(file.handle, &io_status_block); |
| 8410 | return e; |
| 8411 | }, |
| 8412 | }; |
| 8413 | defer alertable_syscall.finish(); |
| 8414 | while (!done) { |
| 8415 | _ = windows.ntdll.NtDelayExecution(1, &infinite); |
| 8416 | alertable_syscall.checkCancel() catch |err| switch (err) { |
| 8417 | error.Canceled => |e| { |
| 8418 | _ = windows.ntdll.NtCancelIoFile(file.handle, &io_status_block); |
| 8419 | return e; |
| 8488 | 8420 | }, |
| 8489 | | else => |status| std.debug.panic("fileReadStreamingWindows NtDelayExecution returned {t}", .{status}), |
| 8490 | | //else => |status| return syscall.unexpectedNtstatus(status), |
| 8491 | | } |
| 8421 | }; |
| 8492 | 8422 | } |
| 8493 | 8423 | } |
| 8494 | 8424 | |
| 8495 | 8425 | switch (io_status_block.u.Status) { |
| 8496 | 8426 | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => {}, |
| 8497 | 8427 | .ACCESS_DENIED => return error.AccessDenied, |
| 8498 | | else => |status| std.debug.panic("fileReadStreamingWindows IO_STATUS_BLOCK returned {t}", .{status}), |
| 8499 | | //else => |status| return windows.unexpectedStatus(status), |
| 8428 | else => |status| return windows.unexpectedStatus(status), |
| 8500 | 8429 | } |
| 8501 | 8430 | return io_status_block.Information; |
| 8502 | 8431 | } |
| ... | ... | @@ -12519,7 +12448,7 @@ fn netLookupFallible( |
| 12519 | 12448 | var res: *ws2_32.ADDRINFOEXW = undefined; |
| 12520 | 12449 | const timeout: ?*ws2_32.timeval = null; |
| 12521 | 12450 | while (true) { |
| 12522 | | // TODO: hook this up to cancelation with `Thread.Status.cancelation.blocked_windows_dns`. |
| 12451 | // TODO: hook this up to cancelation with `NtDelayExecution` and APC callbacks. |
| 12523 | 12452 | try Thread.checkCancel(); |
| 12524 | 12453 | // TODO make this append to the queue eagerly rather than blocking until the whole thing finishes |
| 12525 | 12454 | const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, null)); |
| ... | ... | @@ -16253,8 +16182,8 @@ const parking_futex = struct { |
| 16253 | 16182 | .canceled => break :cancelable, // status is still `.canceled` |
| 16254 | 16183 | .parked => unreachable, |
| 16255 | 16184 | .blocked => unreachable, |
| 16256 | | .blocked_apc => unreachable, |
| 16257 | | .blocked_windows_dns => unreachable, |
| 16185 | .blocked_alertable => unreachable, |
| 16186 | .blocked_alertable_canceling => unreachable, |
| 16258 | 16187 | .blocked_canceling => unreachable, |
| 16259 | 16188 | } |
| 16260 | 16189 | // We could now be unparked for a cancelation at any time! |
| ... | ... | @@ -16305,8 +16234,8 @@ const parking_futex = struct { |
| 16305 | 16234 | }, |
| 16306 | 16235 | .canceled => unreachable, |
| 16307 | 16236 | .blocked => unreachable, |
| 16308 | | .blocked_apc => unreachable, |
| 16309 | | .blocked_windows_dns => unreachable, |
| 16237 | .blocked_alertable => unreachable, |
| 16238 | .blocked_alertable_canceling => unreachable, |
| 16310 | 16239 | .blocked_canceling => unreachable, |
| 16311 | 16240 | }, |
| 16312 | 16241 | } |
| ... | ... | @@ -16347,8 +16276,8 @@ const parking_futex = struct { |
| 16347 | 16276 | .canceling => continue, // race with a canceler who hasn't called `removeCanceledWaiter` yet |
| 16348 | 16277 | .canceled => unreachable, |
| 16349 | 16278 | .blocked => unreachable, |
| 16350 | | .blocked_apc => unreachable, |
| 16351 | | .blocked_windows_dns => unreachable, |
| 16279 | .blocked_alertable => unreachable, |
| 16280 | .blocked_alertable_canceling => unreachable, |
| 16352 | 16281 | .blocked_canceling => unreachable, |
| 16353 | 16282 | } |
| 16354 | 16283 | // We're waking this waiter. Remove them from the bucket and add them to our local list. |
| ... | ... | @@ -16414,8 +16343,8 @@ const parking_sleep = struct { |
| 16414 | 16343 | .canceled => break :cancelable, // status is still `.canceled` |
| 16415 | 16344 | .parked => unreachable, |
| 16416 | 16345 | .blocked => unreachable, |
| 16417 | | .blocked_apc => unreachable, |
| 16418 | | .blocked_windows_dns => unreachable, |
| 16346 | .blocked_alertable => unreachable, |
| 16347 | .blocked_alertable_canceling => unreachable, |
| 16419 | 16348 | .blocked_canceling => unreachable, |
| 16420 | 16349 | } |
| 16421 | 16350 | while (park(deadline, null)) { |
| ... | ... | @@ -16433,8 +16362,8 @@ const parking_sleep = struct { |
| 16433 | 16362 | .none => unreachable, |
| 16434 | 16363 | .canceled => unreachable, |
| 16435 | 16364 | .blocked => unreachable, |
| 16436 | | .blocked_apc => unreachable, |
| 16437 | | .blocked_windows_dns => unreachable, |
| 16365 | .blocked_alertable => unreachable, |
| 16366 | .blocked_alertable_canceling => unreachable, |
| 16438 | 16367 | .blocked_canceling => unreachable, |
| 16439 | 16368 | } |
| 16440 | 16369 | } else |err| switch (err) { |
| ... | ... | @@ -16453,8 +16382,8 @@ const parking_sleep = struct { |
| 16453 | 16382 | .none => unreachable, |
| 16454 | 16383 | .canceled => unreachable, |
| 16455 | 16384 | .blocked => unreachable, |
| 16456 | | .blocked_apc => unreachable, |
| 16457 | | .blocked_windows_dns => unreachable, |
| 16385 | .blocked_alertable => unreachable, |
| 16386 | .blocked_alertable_canceling => unreachable, |
| 16458 | 16387 | .blocked_canceling => unreachable, |
| 16459 | 16388 | }, |
| 16460 | 16389 | } |