| ... | @@ -632,12 +632,17 @@ const Thread = struct { | ... | @@ -632,12 +632,17 @@ const Thread = struct { |
| 632 | cancel_protection: Io.CancelProtection, | 632 | cancel_protection: Io.CancelProtection, |
| 633 | /// Always released when `Status.cancelation` is set to `.parked`. | 633 | /// Always released when `Status.cancelation` is set to `.parked`. |
| 634 | futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn, | 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 | /// Used only by group cancelation code for temporary storage. | 636 | /// Used only by group cancelation code for temporary storage. |
| 637 | interrupt_method: InterruptMethod, | 637 | interrupt_method: InterruptMethod, |
| 638 | | 638 | |
| 639 | csprng: Csprng, | 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 | const Handle = Handle: { | 646 | const Handle = Handle: { |
| 642 | if (std.Thread.use_pthreads) break :Handle std.c.pthread_t; | 647 | if (std.Thread.use_pthreads) break :Handle std.c.pthread_t; |
| 643 | if (is_windows) break :Handle windows.HANDLE; | 648 | if (is_windows) break :Handle windows.HANDLE; |
| ... | @@ -1116,7 +1121,14 @@ const Thread = struct { | ... | @@ -1116,7 +1121,14 @@ const Thread = struct { |
| 1116 | }; | 1121 | }; |
| 1117 | }, | 1122 | }, |
| 1118 | .dns => @panic("TODO call GetAddrInfoExCancel"), | 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 | else => { | 1134 | else => { |
| ... | @@ -1213,9 +1225,9 @@ const Syscall = struct { | ... | @@ -1213,9 +1225,9 @@ const Syscall = struct { |
| 1213 | /// `NtCancelIoFileEx` to interrupt the wait. | 1225 | /// `NtCancelIoFileEx` to interrupt the wait. |
| 1214 | /// | 1226 | /// |
| 1215 | /// Windows only, called from blocked state only. | 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 | const thread = s.thread orelse return; | 1229 | const thread = s.thread orelse return; |
| 1218 | thread.apc_context = apc_context; | 1230 | thread.apc = apc; |
| 1219 | var prev = thread.status.load(.monotonic); | 1231 | var prev = thread.status.load(.monotonic); |
| 1220 | while (true) prev = switch (prev.cancelation) { | 1232 | while (true) prev = switch (prev.cancelation) { |
| 1221 | .none => unreachable, | 1233 | .none => unreachable, |
| ... | @@ -1554,7 +1566,7 @@ fn worker(t: *Threaded) void { | ... | @@ -1554,7 +1566,7 @@ fn worker(t: *Threaded) void { |
| 1554 | .cancel_protection = .unblocked, | 1566 | .cancel_protection = .unblocked, |
| 1555 | .futex_waiter = undefined, | 1567 | .futex_waiter = undefined, |
| 1556 | .csprng = .{}, | 1568 | .csprng = .{}, |
| 1557 | .apc_context = undefined, | 1569 | .apc = undefined, |
| 1558 | .interrupt_method = undefined, | 1570 | .interrupt_method = undefined, |
| 1559 | }; | 1571 | }; |
| 1560 | Thread.current = &thread; | 1572 | Thread.current = &thread; |
| ... | @@ -8315,10 +8327,17 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us | ... | @@ -8315,10 +8327,17 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us |
| 8315 | //else => |status| return syscall.unexpectedNtstatus(status), | 8327 | //else => |status| return syscall.unexpectedNtstatus(status), |
| 8316 | } | 8328 | } |
| 8317 | } | 8329 | } |
| 8318 | try syscall.toApc(&done); | 8330 | try syscall.toApc(.{ .handle = file.handle, .iosb = &io_status_block }); |
| 8319 | while (true) { | 8331 | while (true) { |
| 8320 | switch (windows.ntdll.NtDelayExecution(1, null)) { | 8332 | switch (windows.ntdll.NtDelayExecution(1, null)) { |
| 8321 | .USER_APC => break syscall.finishApc(), | 8333 | .USER_APC => { |
| | 8334 | if (!done) { |
| | 8335 | // Other APC work was queued before calling into this function. |
| | 8336 | try syscall.checkCancelApc(); |
| | 8337 | continue; |
| | 8338 | } |
| | 8339 | break syscall.finishApc(); |
| | 8340 | }, |
| 8322 | .SUCCESS, .CANCELLED => { | 8341 | .SUCCESS, .CANCELLED => { |
| 8323 | try syscall.checkCancelApc(); | 8342 | try syscall.checkCancelApc(); |
| 8324 | continue; | 8343 | continue; |