| ... | ... | @@ -632,12 +632,17 @@ const Thread = struct { |
| 632 | 632 | cancel_protection: Io.CancelProtection, |
| 633 | 633 | /// Always released when `Status.cancelation` is set to `.parked`. |
| 634 | 634 | futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn, |
| 635 | | apc_context: if (is_windows) ?*anyopaque else void, |
| 635 | apc: Apc, |
| 636 | 636 | /// Used only by group cancelation code for temporary storage. |
| 637 | 637 | interrupt_method: InterruptMethod, |
| 638 | 638 | |
| 639 | 639 | csprng: Csprng, |
| 640 | 640 | |
| 641 | const Apc = if (is_windows) struct { |
| 642 | handle: windows.HANDLE, |
| 643 | iosb: ?*windows.IO_STATUS_BLOCK, |
| 644 | } else void; |
| 645 | |
| 641 | 646 | const Handle = Handle: { |
| 642 | 647 | if (std.Thread.use_pthreads) break :Handle std.c.pthread_t; |
| 643 | 648 | if (is_windows) break :Handle windows.HANDLE; |
| ... | ... | @@ -1116,7 +1121,14 @@ const Thread = struct { |
| 1116 | 1121 | }; |
| 1117 | 1122 | }, |
| 1118 | 1123 | .dns => @panic("TODO call GetAddrInfoExCancel"), |
| 1119 | | .apc => @panic("TODO call NtCancelIoFileEx"), |
| 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 | }, |
| 1120 | 1132 | }, |
| 1121 | 1133 | |
| 1122 | 1134 | else => { |
| ... | ... | @@ -1213,9 +1225,9 @@ const Syscall = struct { |
| 1213 | 1225 | /// `NtCancelIoFileEx` to interrupt the wait. |
| 1214 | 1226 | /// |
| 1215 | 1227 | /// Windows only, called from blocked state only. |
| 1216 | | fn toApc(s: Syscall, apc_context: ?*anyopaque) Io.Cancelable!void { |
| 1228 | fn toApc(s: Syscall, apc: Thread.Apc) Io.Cancelable!void { |
| 1217 | 1229 | const thread = s.thread orelse return; |
| 1218 | | thread.apc_context = apc_context; |
| 1230 | thread.apc = apc; |
| 1219 | 1231 | var prev = thread.status.load(.monotonic); |
| 1220 | 1232 | while (true) prev = switch (prev.cancelation) { |
| 1221 | 1233 | .none => unreachable, |
| ... | ... | @@ -1554,7 +1566,7 @@ fn worker(t: *Threaded) void { |
| 1554 | 1566 | .cancel_protection = .unblocked, |
| 1555 | 1567 | .futex_waiter = undefined, |
| 1556 | 1568 | .csprng = .{}, |
| 1557 | | .apc_context = undefined, |
| 1569 | .apc = undefined, |
| 1558 | 1570 | .interrupt_method = undefined, |
| 1559 | 1571 | }; |
| 1560 | 1572 | Thread.current = &thread; |
| ... | ... | @@ -8458,10 +8470,17 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us |
| 8458 | 8470 | //else => |status| return syscall.unexpectedNtstatus(status), |
| 8459 | 8471 | } |
| 8460 | 8472 | } |
| 8461 | | try syscall.toApc(&done); |
| 8473 | try syscall.toApc(.{ .handle = file.handle, .iosb = &io_status_block }); |
| 8462 | 8474 | while (true) { |
| 8463 | 8475 | switch (windows.ntdll.NtDelayExecution(1, null)) { |
| 8464 | | .USER_APC => break syscall.finishApc(), |
| 8476 | .USER_APC => { |
| 8477 | if (!done) { |
| 8478 | // Other APC work was queued before calling into this function. |
| 8479 | try syscall.checkCancelApc(); |
| 8480 | continue; |
| 8481 | } |
| 8482 | break syscall.finishApc(); |
| 8483 | }, |
| 8465 | 8484 | .SUCCESS, .CANCELLED => { |
| 8466 | 8485 | try syscall.checkCancelApc(); |
| 8467 | 8486 | continue; |