diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig index 5db6f81ac6..e0297e0573 100644 --- a/lib/std/Io/File.zig +++ b/lib/std/Io/File.zig @@ -10,6 +10,18 @@ const assert = std.debug.assert; const Dir = std.Io.Dir; handle: Handle, +flags: Flags, + +pub const Flags = struct { + /// * true: + /// - windows: opened with MODE.IO.ASYNCHRONOUS + /// - POSIX: O_NONBLOCK is set + /// * false: + /// - windows: opened with SYNCHRONOUS_ALERT or SYNCHRONOUS_NONALERT, or + /// not a file. + /// - POSIX: O_NONBLOCK is unset + nonblocking: bool, +}; pub const Handle = std.posix.fd_t; @@ -80,9 +92,11 @@ pub fn stdout() File { return switch (native_os) { .windows => .{ .handle = std.os.windows.peb().ProcessParameters.hStdOutput, + .flags = .{ .nonblocking = false }, }, else => .{ .handle = std.posix.STDOUT_FILENO, + .flags = .{ .nonblocking = false }, }, }; } @@ -91,9 +105,11 @@ pub fn stderr() File { return switch (native_os) { .windows => .{ .handle = std.os.windows.peb().ProcessParameters.hStdError, + .flags = .{ .nonblocking = false }, }, else => .{ .handle = std.posix.STDERR_FILENO, + .flags = .{ .nonblocking = false }, }, }; } @@ -102,9 +118,11 @@ pub fn stdin() File { return switch (native_os) { .windows => .{ .handle = std.os.windows.peb().ProcessParameters.hStdInput, + .flags = .{ .nonblocking = false }, }, else => .{ .handle = std.posix.STDIN_FILENO, + .flags = .{ .nonblocking = false }, }, }; } diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 45184e6d59..8fdd2a58e9 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -3215,8 +3215,10 @@ fn dirCreateDirPathOpenWasi( fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { const t: *Threaded = @ptrCast(@alignCast(userdata)); - const file: File = .{ .handle = dir.handle }; - return fileStat(t, file); + return fileStat(t, .{ + .handle = dir.handle, + .flags = .{ .nonblocking = false }, + }); } const dirStatFile = switch (native_os) { @@ -4008,7 +4010,10 @@ fn dirCreateFilePosix( } } - return .{ .handle = fd }; + return .{ + .handle = fd, + .flags = .{ .nonblocking = false }, + }; } fn dirCreateFileWindows( @@ -4138,7 +4143,10 @@ fn dirCreateFileWindows( errdefer windows.CloseHandle(handle); const exclusive = switch (flags.lock) { - .none => return .{ .handle = handle }, + .none => return .{ + .handle = handle, + .flags = .{ .nonblocking = false }, + }, .shared => false, .exclusive => true, }; @@ -4158,7 +4166,10 @@ fn dirCreateFileWindows( )) { .SUCCESS => { syscall.finish(); - return .{ .handle = handle }; + return .{ + .handle = handle, + .flags = .{ .nonblocking = false }, + }; }, .INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources), .LOCK_NOT_GRANTED => return syscall.fail(error.WouldBlock), @@ -4207,7 +4218,10 @@ fn dirCreateFileWasi( switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) { .SUCCESS => { syscall.finish(); - return .{ .handle = fd }; + return .{ + .handle = fd, + .flags = .{ .nonblocking = false }, + }; }, .INTR => { try syscall.checkCancel(); @@ -4302,7 +4316,10 @@ fn dirCreateFileAtomic( .SUCCESS => { syscall.finish(); return .{ - .file = .{ .handle = @intCast(rc) }, + .file = .{ + .handle = @intCast(rc), + .flags = .{ .nonblocking = false }, + }, .file_basename_hex = 0, .dest_sub_path = dest_path, .file_open = true, @@ -4510,7 +4527,10 @@ fn dirOpenFilePosix( if (!flags.allow_directory) { const is_dir = is_dir: { - const stat = fileStat(t, .{ .handle = fd }) catch |err| switch (err) { + const stat = fileStat(t, .{ + .handle = fd, + .flags = .{ .nonblocking = false }, + }) catch |err| switch (err) { // The directory-ness is either unknown or unknowable error.Streaming => break :is_dir false, else => |e| return e, @@ -4596,7 +4616,10 @@ fn dirOpenFilePosix( } } - return .{ .handle = fd }; + return .{ + .handle = fd, + .flags = .{ .nonblocking = false }, + }; } fn dirOpenFileWindows( @@ -4729,7 +4752,10 @@ pub fn dirOpenFileWtf16( errdefer w.CloseHandle(handle); const exclusive = switch (flags.lock) { - .none => return .{ .handle = handle }, + .none => return .{ + .handle = handle, + .flags = .{ .nonblocking = false }, + }, .shared => false, .exclusive => true, }; @@ -4752,7 +4778,10 @@ pub fn dirOpenFileWtf16( .ACCESS_VIOLATION => |err| return syscall.ntstatusBug(err), // bad io_status_block pointer else => |status| return syscall.unexpectedNtstatus(status), }; - return .{ .handle = handle }; + return .{ + .handle = handle, + .flags = .{ .nonblocking = false }, + }; } fn dirOpenFileWasi( @@ -4834,7 +4863,7 @@ fn dirOpenFileWasi( if (!flags.allow_directory) { const is_dir = is_dir: { - const stat = fileStat(t, .{ .handle = fd }) catch |err| switch (err) { + const stat = fileStat(t, .{ .handle = fd, .flags = .{ .nonblocking = false } }) catch |err| switch (err) { // The directory-ness is either unknown or unknowable error.Streaming => break :is_dir false, else => |e| return e, @@ -4844,7 +4873,10 @@ fn dirOpenFileWasi( if (is_dir) return error.IsDir; } - return .{ .handle = fd }; + return .{ + .handle = fd, + .flags = .{ .nonblocking = false }, + }; } const dirOpenDir = switch (native_os) { @@ -14390,15 +14422,15 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp .pid = pid, .err_fd = err_pipe[0], .stdin = switch (options.stdin) { - .pipe => .{ .handle = stdin_pipe[1] }, + .pipe => .{ .handle = stdin_pipe[1], .flags = .{ .nonblocking = false } }, else => null, }, .stdout = switch (options.stdout) { - .pipe => .{ .handle = stdout_pipe[0] }, + .pipe => .{ .handle = stdout_pipe[0], .flags = .{ .nonblocking = false } }, else => null, }, .stderr = switch (options.stderr) { - .pipe => .{ .handle = stderr_pipe[0] }, + .pipe => .{ .handle = stderr_pipe[0], .flags = .{ .nonblocking = false } }, else => null, }, }; @@ -15052,9 +15084,9 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro return .{ .id = piProcInfo.hProcess, .thread_handle = piProcInfo.hThread, - .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h } else null, - .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h } else null, - .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h } else null, + .stdin = if (g_hChildStd_IN_Wr) |h| .{ .handle = h, .flags = .{ .nonblocking = false } } else null, + .stdout = if (g_hChildStd_OUT_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, + .stderr = if (g_hChildStd_ERR_Rd) |h| .{ .handle = h, .flags = .{ .nonblocking = true } } else null, .request_resource_usage_statistics = options.request_resource_usage_statistics, }; } @@ -16188,6 +16220,7 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { .pointer => @ptrFromInt(int), else => return error.UnsupportedOperation, }, + .flags = .{ .nonblocking = false }, }; } diff --git a/lib/std/Io/Threaded/test.zig b/lib/std/Io/Threaded/test.zig index ffda1e7601..593580d1f6 100644 --- a/lib/std/Io/Threaded/test.zig +++ b/lib/std/Io/Threaded/test.zig @@ -188,8 +188,8 @@ test "cancel blocked read from pipe" { }), else => { const pipe = try std.Io.Threaded.pipe2(.{}); - read_end = .{ .handle = pipe[0] }; - write_end = .{ .handle = pipe[1] }; + read_end = .{ .handle = pipe[0], .flags = .{ .nonblocking = false } }; + write_end = .{ .handle = pipe[1], .flags = .{ .nonblocking = false } }; }, } defer { diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index d0ee9e556f..0fefc77a32 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -979,6 +979,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff if (main_parent == .unused) continue; const file: Io.File = .{ .handle = main_storage.getIpcFd() orelse continue, + .flags = .{ .nonblocking = true }, }; const opt_saved_metadata = findOld(file.handle, old_ipc_metadata_fds, old_ipc_metadata); var bytes_read: usize = 0; diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 5838595fcf..e2a52473f3 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -126,8 +126,8 @@ test "pipe" { const io = testing.io; const fds = try std.Io.Threaded.pipe2(.{}); - const out: Io.File = .{ .handle = fds[0] }; - const in: Io.File = .{ .handle = fds[1] }; + const out: Io.File = .{ .handle = fds[0], .flags = .{ .nonblocking = false } }; + const in: Io.File = .{ .handle = fds[1], .flags = .{ .nonblocking = false } }; try in.writeStreamingAll(io, "hello"); var buf: [16]u8 = undefined; try expect((try out.readStreaming(io, &.{&buf})) == 5); @@ -150,7 +150,10 @@ test "memfd_create" { else => return error.SkipZigTest, } - const file: Io.File = .{ .handle = try posix.memfd_create("test", 0) }; + const file: Io.File = .{ + .handle = try posix.memfd_create("test", 0), + .flags = .{ .nonblocking = false }, + }; defer file.close(io); try file.writePositionalAll(io, "test", 0);