mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
std.Io.File: add non-blocking flag
On Windows, we need to know ahead of time whether a file was opened in synchronous mode or asynchronous mode. There may be advantages to tracking this state for POSIX operating systems as well.
This commit is contained in:
@@ -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 },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
+52
-19
@@ -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 },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user