commit 46658257f458b7c3c95d7e10cbde85403f7bdb44 (tree)
parent 30c8a759978c11620e90bf5117829c92c14bbf28
Author: breakmit <breakmit@noreply.codeberg.org>
Date: Fri, 6 Mar 2026 04:51:28 +0100
Io.Threaded.spawnPosix: implement passing file descriptors as stdio (#31379)
`std.process.spawn`: remove the TODO for nonblocking file stdio and document the behavior.
Fix a bug in Io.Uring.dup2 where the function does not return on success
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31379
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
Co-authored-by: breakmit <breakmit@noreply.codeberg.org>
Co-committed-by: breakmit <breakmit@noreply.codeberg.org>
Diffstat:
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/lib/std/Io/Dispatch.zig b/lib/std/Io/Dispatch.zig
@@ -4404,10 +4404,7 @@ fn setUpChildIo(
.close => closeFd(std_fileno),
.inherit => {},
.ignore => try ev.dup2(dev_null_fd, std_fileno),
- .file => |file| {
- if (file.flags.nonblocking) @panic("TODO implement setUpChildIo when nonblocking file is used");
- try ev.dup2(file.handle, std_fileno);
- },
+ .file => |file| try ev.dup2(file.handle, std_fileno),
}
}
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -15659,7 +15659,7 @@ fn setUpChildIo(stdio: process.SpawnOptions.StdIo, pipe_fd: i32, std_fileno: i32
.close => closeFd(std_fileno),
.inherit => {},
.ignore => try dup2(dev_null_fd, std_fileno),
- .file => @panic("TODO implement setUpChildIo when file is used"),
+ .file => |file| try dup2(file.handle, std_fileno),
}
}
diff --git a/lib/std/Io/Uring.zig b/lib/std/Io/Uring.zig
@@ -4550,10 +4550,7 @@ fn setUpChildIo(
.close => _ = linux.close(std_fileno),
.inherit => {},
.ignore => try dup2(sync, dev_null_fd, std_fileno),
- .file => |file| {
- if (file.flags.nonblocking) @panic("TODO implement setUpChildIo when nonblocking file is used");
- try dup2(sync, file.handle, std_fileno);
- },
+ .file => |file| try dup2(sync, file.handle, std_fileno),
}
}
@@ -4565,7 +4562,7 @@ pub fn dup2(sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) DupError!void
while (true) {
try sync.cancel_region.await(.nothing);
switch (linux.errno(linux.dup2(old_fd, new_fd))) {
- .SUCCESS => {},
+ .SUCCESS => return,
.BUSY, .INTR => {},
.INVAL => |err| return errnoBug(err), // invalid parameters
.BADF => |err| return errnoBug(err), // use after free
diff --git a/lib/std/process.zig b/lib/std/process.zig
@@ -409,6 +409,12 @@ pub const SpawnOptions = struct {
/// Inherit the corresponding stream from the parent process.
inherit,
/// Pass an already open file from the parent to the child.
+ ///
+ /// Nonblocking mode will be kept in the child process if present. This is
+ /// likely not supported by the child process. For example:
+ /// - Zig's std.Io.File.stdout() assumes blocking mode
+ /// - Rust explicity documents that nonblocking stdio may cause panics
+ /// - C++ standard streams do not support nonblocking file descriptors
file: File,
/// Pass a null stream to the child process by opening "/dev/null" on POSIX
/// and "NUL" on Windows.