| ... | ... | @@ -1173,6 +1173,11 @@ const Syscall = struct { |
| 1173 | 1173 | .blocked_canceling => return error.Canceled, // new status is `.canceled` |
| 1174 | 1174 | } |
| 1175 | 1175 | } |
| 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 | } |
| 1176 | 1181 | /// Marks this syscall as finished. |
| 1177 | 1182 | fn finish(s: Syscall) void { |
| 1178 | 1183 | const thread = s.thread orelse return; |
| ... | ... | @@ -2754,7 +2759,12 @@ fn dirCreateDirPathOpenWasi( |
| 2754 | 2759 | |
| 2755 | 2760 | fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { |
| 2756 | 2761 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2757 | | const file: File = .{ .handle = dir.handle }; |
| 2762 | const file: File = if (is_windows) .{ |
| 2763 | .handle = dir.handle, |
| 2764 | .flags = .{ .nonblocking = false }, |
| 2765 | } else .{ |
| 2766 | .handle = dir.handle, |
| 2767 | }; |
| 2758 | 2768 | return fileStat(t, file); |
| 2759 | 2769 | } |
| 2760 | 2770 | |
| ... | ... | @@ -3676,7 +3686,10 @@ fn dirCreateFileWindows( |
| 3676 | 3686 | errdefer windows.CloseHandle(handle); |
| 3677 | 3687 | |
| 3678 | 3688 | const exclusive = switch (flags.lock) { |
| 3679 | | .none => return .{ .handle = handle }, |
| 3689 | .none => return .{ |
| 3690 | .handle = handle, |
| 3691 | .flags = .{ .nonblocking = false }, |
| 3692 | }, |
| 3680 | 3693 | .shared => false, |
| 3681 | 3694 | .exclusive => true, |
| 3682 | 3695 | }; |
| ... | ... | @@ -3696,7 +3709,10 @@ fn dirCreateFileWindows( |
| 3696 | 3709 | )) { |
| 3697 | 3710 | .SUCCESS => { |
| 3698 | 3711 | syscall.finish(); |
| 3699 | | return .{ .handle = handle }; |
| 3712 | return .{ |
| 3713 | .handle = handle, |
| 3714 | .flags = .{ .nonblocking = false }, |
| 3715 | }; |
| 3700 | 3716 | }, |
| 3701 | 3717 | .INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources), |
| 3702 | 3718 | .LOCK_NOT_GRANTED => return syscall.fail(error.WouldBlock), |
| ... | ... | @@ -4271,7 +4287,10 @@ pub fn dirOpenFileWtf16( |
| 4271 | 4287 | errdefer w.CloseHandle(handle); |
| 4272 | 4288 | |
| 4273 | 4289 | const exclusive = switch (flags.lock) { |
| 4274 | | .none => return .{ .handle = handle }, |
| 4290 | .none => return .{ |
| 4291 | .handle = handle, |
| 4292 | .flags = .{ .nonblocking = false }, |
| 4293 | }, |
| 4275 | 4294 | .shared => false, |
| 4276 | 4295 | .exclusive => true, |
| 4277 | 4296 | }; |
| ... | ... | @@ -4294,7 +4313,10 @@ pub fn dirOpenFileWtf16( |
| 4294 | 4313 | .ACCESS_VIOLATION => |err| return syscall.ntstatusBug(err), // bad io_status_block pointer |
| 4295 | 4314 | else => |status| return syscall.unexpectedNtstatus(status), |
| 4296 | 4315 | }; |
| 4297 | | return .{ .handle = handle }; |
| 4316 | return .{ |
| 4317 | .handle = handle, |
| 4318 | .flags = .{ .nonblocking = false }, |
| 4319 | }; |
| 4298 | 4320 | } |
| 4299 | 4321 | |
| 4300 | 4322 | fn dirOpenFileWasi( |
| ... | ... | @@ -8222,46 +8244,66 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz |
| 8222 | 8244 | } |
| 8223 | 8245 | |
| 8224 | 8246 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { |
| 8225 | | const DWORD = windows.DWORD; |
| 8226 | 8247 | var index: usize = 0; |
| 8227 | 8248 | while (index < data.len and data[index].len == 0) index += 1; |
| 8228 | 8249 | if (index == data.len) return 0; |
| 8229 | 8250 | const buffer = data[index]; |
| 8230 | | const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len); |
| 8231 | 8251 | |
| 8232 | | const syscall: Syscall = try .start(); |
| 8233 | | while (true) { |
| 8234 | | var n: DWORD = undefined; |
| 8235 | | if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0) { |
| 8236 | | syscall.finish(); |
| 8237 | | return n; |
| 8252 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 8253 | |
| 8254 | read: { |
| 8255 | const syscall: Syscall = try .start(); |
| 8256 | while (true) { |
| 8257 | switch (windows.ntdll.NtReadFile( |
| 8258 | file.handle, |
| 8259 | null, // event |
| 8260 | noopApc, // apc callback |
| 8261 | null, // apc context |
| 8262 | &io_status_block, |
| 8263 | buffer.ptr, |
| 8264 | @min(std.math.maxInt(u32), buffer.len), |
| 8265 | null, // byte offset |
| 8266 | null, // key |
| 8267 | )) { |
| 8268 | .SUCCESS => break :read syscall.finish(), |
| 8269 | .PENDING => break, |
| 8270 | .CANCELLED => { |
| 8271 | try syscall.checkCancel(); |
| 8272 | continue; |
| 8273 | }, |
| 8274 | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), // wrong value for flags.nonblocking |
| 8275 | else => |status| return syscall.unexpectedNtstatus(status), |
| 8276 | } |
| 8238 | 8277 | } |
| 8239 | | switch (windows.GetLastError()) { |
| 8240 | | .IO_PENDING => |err| { |
| 8241 | | syscall.finish(); |
| 8242 | | return windows.errorBug(err); |
| 8243 | | }, |
| 8244 | | .OPERATION_ABORTED => { |
| 8245 | | try syscall.checkCancel(); |
| 8246 | | continue; |
| 8247 | | }, |
| 8248 | | .BROKEN_PIPE, .HANDLE_EOF => { |
| 8249 | | syscall.finish(); |
| 8250 | | return 0; |
| 8251 | | }, |
| 8252 | | .NETNAME_DELETED => if (is_debug) unreachable else return error.Unexpected, |
| 8253 | | .LOCK_VIOLATION => return syscall.fail(error.LockViolation), |
| 8254 | | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 8255 | | .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected, |
| 8256 | | // TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing |
| 8257 | | // a handle to a directory. |
| 8258 | | .INVALID_FUNCTION => return syscall.fail(error.IsDir), |
| 8259 | | else => |err| { |
| 8260 | | syscall.finish(); |
| 8261 | | return windows.unexpectedError(err); |
| 8262 | | }, |
| 8278 | try syscall.toApc(); |
| 8279 | while (true) { |
| 8280 | switch (windows.ntdll.NtDelayExecution(1, null)) { |
| 8281 | .USER_APC => break syscall.finish(), |
| 8282 | .SUCCESS, .CANCELLED => { |
| 8283 | try syscall.checkCancel(); |
| 8284 | continue; |
| 8285 | }, |
| 8286 | else => |status| return syscall.unexpectedNtstatus(status), |
| 8287 | } |
| 8263 | 8288 | } |
| 8264 | 8289 | } |
| 8290 | |
| 8291 | switch (io_status_block.u.Status) { |
| 8292 | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => {}, |
| 8293 | .ACCESS_DENIED => return error.AccessDenied, |
| 8294 | else => |status| return windows.unexpectedStatus(status), |
| 8295 | } |
| 8296 | return io_status_block.Information; |
| 8297 | } |
| 8298 | |
| 8299 | fn noopApc( |
| 8300 | apc_context: ?*anyopaque, |
| 8301 | io_status_block: *windows.IO_STATUS_BLOCK, |
| 8302 | unused: windows.ULONG, |
| 8303 | ) callconv(.winapi) void { |
| 8304 | _ = apc_context; |
| 8305 | _ = io_status_block; |
| 8306 | _ = unused; |
| 8265 | 8307 | } |
| 8266 | 8308 | |
| 8267 | 8309 | fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { |
| ... | ... | @@ -14321,9 +14363,9 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro |
| 14321 | 14363 | return .{ |
| 14322 | 14364 | .id = piProcInfo.hProcess, |
| 14323 | 14365 | .thread_handle = piProcInfo.hThread, |
| 14324 | | .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h } else null, |
| 14325 | | .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h } else null, |
| 14326 | | .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h } else null, |
| 14366 | .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14367 | .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14368 | .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14327 | 14369 | .request_resource_usage_statistics = options.request_resource_usage_statistics, |
| 14328 | 14370 | }; |
| 14329 | 14371 | } |
| ... | ... | @@ -15457,6 +15499,7 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { |
| 15457 | 15499 | .pointer => @ptrFromInt(int), |
| 15458 | 15500 | else => return error.UnsupportedOperation, |
| 15459 | 15501 | }, |
| 15502 | .flags = if (is_windows) .{ .nonblocking = true } else .{}, |
| 15460 | 15503 | }; |
| 15461 | 15504 | } |
| 15462 | 15505 | |