| ... | ... | @@ -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; |
| ... | ... | @@ -2759,7 +2764,12 @@ fn dirCreateDirPathOpenWasi( |
| 2759 | 2764 | |
| 2760 | 2765 | fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { |
| 2761 | 2766 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2762 | | const file: File = .{ .handle = dir.handle }; |
| 2767 | const file: File = if (is_windows) .{ |
| 2768 | .handle = dir.handle, |
| 2769 | .flags = .{ .nonblocking = false }, |
| 2770 | } else .{ |
| 2771 | .handle = dir.handle, |
| 2772 | }; |
| 2763 | 2773 | return fileStat(t, file); |
| 2764 | 2774 | } |
| 2765 | 2775 | |
| ... | ... | @@ -3682,7 +3692,10 @@ fn dirCreateFileWindows( |
| 3682 | 3692 | errdefer windows.CloseHandle(handle); |
| 3683 | 3693 | |
| 3684 | 3694 | const exclusive = switch (flags.lock) { |
| 3685 | | .none => return .{ .handle = handle }, |
| 3695 | .none => return .{ |
| 3696 | .handle = handle, |
| 3697 | .flags = .{ .nonblocking = false }, |
| 3698 | }, |
| 3686 | 3699 | .shared => false, |
| 3687 | 3700 | .exclusive => true, |
| 3688 | 3701 | }; |
| ... | ... | @@ -3702,7 +3715,10 @@ fn dirCreateFileWindows( |
| 3702 | 3715 | )) { |
| 3703 | 3716 | .SUCCESS => { |
| 3704 | 3717 | syscall.finish(); |
| 3705 | | return .{ .handle = handle }; |
| 3718 | return .{ |
| 3719 | .handle = handle, |
| 3720 | .flags = .{ .nonblocking = false }, |
| 3721 | }; |
| 3706 | 3722 | }, |
| 3707 | 3723 | .INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources), |
| 3708 | 3724 | .LOCK_NOT_GRANTED => return syscall.fail(error.WouldBlock), |
| ... | ... | @@ -4273,7 +4289,10 @@ pub fn dirOpenFileWtf16( |
| 4273 | 4289 | errdefer w.CloseHandle(handle); |
| 4274 | 4290 | |
| 4275 | 4291 | const exclusive = switch (flags.lock) { |
| 4276 | | .none => return .{ .handle = handle }, |
| 4292 | .none => return .{ |
| 4293 | .handle = handle, |
| 4294 | .flags = .{ .nonblocking = false }, |
| 4295 | }, |
| 4277 | 4296 | .shared => false, |
| 4278 | 4297 | .exclusive => true, |
| 4279 | 4298 | }; |
| ... | ... | @@ -4296,7 +4315,10 @@ pub fn dirOpenFileWtf16( |
| 4296 | 4315 | .ACCESS_VIOLATION => |err| return syscall.ntstatusBug(err), // bad io_status_block pointer |
| 4297 | 4316 | else => |status| return syscall.unexpectedNtstatus(status), |
| 4298 | 4317 | }; |
| 4299 | | return .{ .handle = handle }; |
| 4318 | return .{ |
| 4319 | .handle = handle, |
| 4320 | .flags = .{ .nonblocking = false }, |
| 4321 | }; |
| 4300 | 4322 | } |
| 4301 | 4323 | |
| 4302 | 4324 | fn dirOpenFileWasi( |
| ... | ... | @@ -8365,46 +8387,66 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz |
| 8365 | 8387 | } |
| 8366 | 8388 | |
| 8367 | 8389 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { |
| 8368 | | const DWORD = windows.DWORD; |
| 8369 | 8390 | var index: usize = 0; |
| 8370 | 8391 | while (index < data.len and data[index].len == 0) index += 1; |
| 8371 | 8392 | if (index == data.len) return 0; |
| 8372 | 8393 | const buffer = data[index]; |
| 8373 | | const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len); |
| 8374 | 8394 | |
| 8375 | | const syscall: Syscall = try .start(); |
| 8376 | | while (true) { |
| 8377 | | var n: DWORD = undefined; |
| 8378 | | if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0) { |
| 8379 | | syscall.finish(); |
| 8380 | | return n; |
| 8395 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 8396 | |
| 8397 | read: { |
| 8398 | const syscall: Syscall = try .start(); |
| 8399 | while (true) { |
| 8400 | switch (windows.ntdll.NtReadFile( |
| 8401 | file.handle, |
| 8402 | null, // event |
| 8403 | noopApc, // apc callback |
| 8404 | null, // apc context |
| 8405 | &io_status_block, |
| 8406 | buffer.ptr, |
| 8407 | @min(std.math.maxInt(u32), buffer.len), |
| 8408 | null, // byte offset |
| 8409 | null, // key |
| 8410 | )) { |
| 8411 | .SUCCESS => break :read syscall.finish(), |
| 8412 | .PENDING => break, |
| 8413 | .CANCELLED => { |
| 8414 | try syscall.checkCancel(); |
| 8415 | continue; |
| 8416 | }, |
| 8417 | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), // wrong value for flags.nonblocking |
| 8418 | else => |status| return syscall.unexpectedNtstatus(status), |
| 8419 | } |
| 8381 | 8420 | } |
| 8382 | | switch (windows.GetLastError()) { |
| 8383 | | .IO_PENDING => |err| { |
| 8384 | | syscall.finish(); |
| 8385 | | return windows.errorBug(err); |
| 8386 | | }, |
| 8387 | | .OPERATION_ABORTED => { |
| 8388 | | try syscall.checkCancel(); |
| 8389 | | continue; |
| 8390 | | }, |
| 8391 | | .BROKEN_PIPE, .HANDLE_EOF => { |
| 8392 | | syscall.finish(); |
| 8393 | | return 0; |
| 8394 | | }, |
| 8395 | | .NETNAME_DELETED => if (is_debug) unreachable else return error.Unexpected, |
| 8396 | | .LOCK_VIOLATION => return syscall.fail(error.LockViolation), |
| 8397 | | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 8398 | | .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected, |
| 8399 | | // TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing |
| 8400 | | // a handle to a directory. |
| 8401 | | .INVALID_FUNCTION => return syscall.fail(error.IsDir), |
| 8402 | | else => |err| { |
| 8403 | | syscall.finish(); |
| 8404 | | return windows.unexpectedError(err); |
| 8405 | | }, |
| 8421 | try syscall.toApc(); |
| 8422 | while (true) { |
| 8423 | switch (windows.ntdll.NtDelayExecution(1, null)) { |
| 8424 | .USER_APC => break syscall.finish(), |
| 8425 | .SUCCESS, .CANCELLED => { |
| 8426 | try syscall.checkCancel(); |
| 8427 | continue; |
| 8428 | }, |
| 8429 | else => |status| return syscall.unexpectedNtstatus(status), |
| 8430 | } |
| 8406 | 8431 | } |
| 8407 | 8432 | } |
| 8433 | |
| 8434 | switch (io_status_block.u.Status) { |
| 8435 | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => {}, |
| 8436 | .ACCESS_DENIED => return error.AccessDenied, |
| 8437 | else => |status| return windows.unexpectedStatus(status), |
| 8438 | } |
| 8439 | return io_status_block.Information; |
| 8440 | } |
| 8441 | |
| 8442 | fn noopApc( |
| 8443 | apc_context: ?*anyopaque, |
| 8444 | io_status_block: *windows.IO_STATUS_BLOCK, |
| 8445 | unused: windows.ULONG, |
| 8446 | ) callconv(.winapi) void { |
| 8447 | _ = apc_context; |
| 8448 | _ = io_status_block; |
| 8449 | _ = unused; |
| 8408 | 8450 | } |
| 8409 | 8451 | |
| 8410 | 8452 | fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { |
| ... | ... | @@ -14560,9 +14602,9 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro |
| 14560 | 14602 | return .{ |
| 14561 | 14603 | .id = piProcInfo.hProcess, |
| 14562 | 14604 | .thread_handle = piProcInfo.hThread, |
| 14563 | | .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h } else null, |
| 14564 | | .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h } else null, |
| 14565 | | .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h } else null, |
| 14605 | .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14606 | .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14607 | .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14566 | 14608 | .request_resource_usage_statistics = options.request_resource_usage_statistics, |
| 14567 | 14609 | }; |
| 14568 | 14610 | } |
| ... | ... | @@ -15696,6 +15738,7 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { |
| 15696 | 15738 | .pointer => @ptrFromInt(int), |
| 15697 | 15739 | else => return error.UnsupportedOperation, |
| 15698 | 15740 | }, |
| 15741 | .flags = if (is_windows) .{ .nonblocking = true } else .{}, |
| 15699 | 15742 | }; |
| 15700 | 15743 | } |
| 15701 | 15744 | |