| ... | @@ -1173,6 +1173,11 @@ const Syscall = struct { | ... | @@ -1173,6 +1173,11 @@ const Syscall = struct { |
| 1173 | .blocked_canceling => return error.Canceled, // new status is `.canceled` | 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 | /// Marks this syscall as finished. | 1181 | /// Marks this syscall as finished. |
| 1177 | fn finish(s: Syscall) void { | 1182 | fn finish(s: Syscall) void { |
| 1178 | const thread = s.thread orelse return; | 1183 | const thread = s.thread orelse return; |
| ... | @@ -2759,7 +2764,12 @@ fn dirCreateDirPathOpenWasi( | ... | @@ -2759,7 +2764,12 @@ fn dirCreateDirPathOpenWasi( |
| 2759 | | 2764 | |
| 2760 | fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { | 2765 | fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { |
| 2761 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 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 | return fileStat(t, file); | 2773 | return fileStat(t, file); |
| 2764 | } | 2774 | } |
| 2765 | | 2775 | |
| ... | @@ -3682,7 +3692,10 @@ fn dirCreateFileWindows( | ... | @@ -3682,7 +3692,10 @@ fn dirCreateFileWindows( |
| 3682 | errdefer windows.CloseHandle(handle); | 3692 | errdefer windows.CloseHandle(handle); |
| 3683 | | 3693 | |
| 3684 | const exclusive = switch (flags.lock) { | 3694 | const exclusive = switch (flags.lock) { |
| 3685 | .none => return .{ .handle = handle }, | 3695 | .none => return .{ |
| | 3696 | .handle = handle, |
| | 3697 | .flags = .{ .nonblocking = false }, |
| | 3698 | }, |
| 3686 | .shared => false, | 3699 | .shared => false, |
| 3687 | .exclusive => true, | 3700 | .exclusive => true, |
| 3688 | }; | 3701 | }; |
| ... | @@ -3702,7 +3715,10 @@ fn dirCreateFileWindows( | ... | @@ -3702,7 +3715,10 @@ fn dirCreateFileWindows( |
| 3702 | )) { | 3715 | )) { |
| 3703 | .SUCCESS => { | 3716 | .SUCCESS => { |
| 3704 | syscall.finish(); | 3717 | syscall.finish(); |
| 3705 | return .{ .handle = handle }; | 3718 | return .{ |
| | 3719 | .handle = handle, |
| | 3720 | .flags = .{ .nonblocking = false }, |
| | 3721 | }; |
| 3706 | }, | 3722 | }, |
| 3707 | .INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources), | 3723 | .INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources), |
| 3708 | .LOCK_NOT_GRANTED => return syscall.fail(error.WouldBlock), | 3724 | .LOCK_NOT_GRANTED => return syscall.fail(error.WouldBlock), |
| ... | @@ -4273,7 +4289,10 @@ pub fn dirOpenFileWtf16( | ... | @@ -4273,7 +4289,10 @@ pub fn dirOpenFileWtf16( |
| 4273 | errdefer w.CloseHandle(handle); | 4289 | errdefer w.CloseHandle(handle); |
| 4274 | | 4290 | |
| 4275 | const exclusive = switch (flags.lock) { | 4291 | const exclusive = switch (flags.lock) { |
| 4276 | .none => return .{ .handle = handle }, | 4292 | .none => return .{ |
| | 4293 | .handle = handle, |
| | 4294 | .flags = .{ .nonblocking = false }, |
| | 4295 | }, |
| 4277 | .shared => false, | 4296 | .shared => false, |
| 4278 | .exclusive => true, | 4297 | .exclusive => true, |
| 4279 | }; | 4298 | }; |
| ... | @@ -4296,7 +4315,10 @@ pub fn dirOpenFileWtf16( | ... | @@ -4296,7 +4315,10 @@ pub fn dirOpenFileWtf16( |
| 4296 | .ACCESS_VIOLATION => |err| return syscall.ntstatusBug(err), // bad io_status_block pointer | 4315 | .ACCESS_VIOLATION => |err| return syscall.ntstatusBug(err), // bad io_status_block pointer |
| 4297 | else => |status| return syscall.unexpectedNtstatus(status), | 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 | fn dirOpenFileWasi( | 4324 | fn dirOpenFileWasi( |
| ... | @@ -8365,46 +8387,66 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz | ... | @@ -8365,46 +8387,66 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz |
| 8365 | } | 8387 | } |
| 8366 | | 8388 | |
| 8367 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { | 8389 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { |
| 8368 | const DWORD = windows.DWORD; | | |
| 8369 | var index: usize = 0; | 8390 | var index: usize = 0; |
| 8370 | while (index < data.len and data[index].len == 0) index += 1; | 8391 | while (index < data.len and data[index].len == 0) index += 1; |
| 8371 | if (index == data.len) return 0; | 8392 | if (index == data.len) return 0; |
| 8372 | const buffer = data[index]; | 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(); | 8395 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 8376 | while (true) { | 8396 | |
| 8377 | var n: DWORD = undefined; | 8397 | read: { |
| 8378 | if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0) { | 8398 | const syscall: Syscall = try .start(); |
| 8379 | syscall.finish(); | 8399 | while (true) { |
| 8380 | return n; | 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()) { | 8421 | try syscall.toApc(); |
| 8383 | .IO_PENDING => |err| { | 8422 | while (true) { |
| 8384 | syscall.finish(); | 8423 | switch (windows.ntdll.NtDelayExecution(1, null)) { |
| 8385 | return windows.errorBug(err); | 8424 | .USER_APC => break syscall.finish(), |
| 8386 | }, | 8425 | .SUCCESS, .CANCELLED => { |
| 8387 | .OPERATION_ABORTED => { | 8426 | try syscall.checkCancel(); |
| 8388 | try syscall.checkCancel(); | 8427 | continue; |
| 8389 | continue; | 8428 | }, |
| 8390 | }, | 8429 | else => |status| return syscall.unexpectedNtstatus(status), |
| 8391 | .BROKEN_PIPE, .HANDLE_EOF => { | 8430 | } |
| 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 | }, | | |
| 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 | fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { | 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,9 +14602,9 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro |
| 14560 | return .{ | 14602 | return .{ |
| 14561 | .id = piProcInfo.hProcess, | 14603 | .id = piProcInfo.hProcess, |
| 14562 | .thread_handle = piProcInfo.hThread, | 14604 | .thread_handle = piProcInfo.hThread, |
| 14563 | .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h } else null, | 14605 | .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14564 | .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h } else null, | 14606 | .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14565 | .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h } else null, | 14607 | .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, |
| 14566 | .request_resource_usage_statistics = options.request_resource_usage_statistics, | 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,6 +15738,7 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { |
| 15696 | .pointer => @ptrFromInt(int), | 15738 | .pointer => @ptrFromInt(int), |
| 15697 | else => return error.UnsupportedOperation, | 15739 | else => return error.UnsupportedOperation, |
| 15698 | }, | 15740 | }, |
| | 15741 | .flags = if (is_windows) .{ .nonblocking = true } else .{}, |
| 15699 | }; | 15742 | }; |
| 15700 | } | 15743 | } |
| 15701 | | 15744 | |