authorgravatar for breakmit@noreply.codeberg.orgbreakmit <breakmit@noreply.codeberg.org> 2026-03-06 04:51:28+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-06 04:51:28+01:00
log46658257f458b7c3c95d7e10cbde85403f7bdb44
treedcc40a21a71128f1abb936e6af006153d4905d33
parent30c8a759978c11620e90bf5117829c92c14bbf28

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>

4 files changed, 10 insertions(+), 10 deletions(-)

lib/std/Io/Dispatch.zig+1-4
......@@ -4404,10 +4404,7 @@ fn setUpChildIo(
44044404 .close => closeFd(std_fileno),
44054405 .inherit => {},
44064406 .ignore => try ev.dup2(dev_null_fd, std_fileno),
4407 .file => |file| {
4408 if (file.flags.nonblocking) @panic("TODO implement setUpChildIo when nonblocking file is used");
4409 try ev.dup2(file.handle, std_fileno);
4410 },
4407 .file => |file| try ev.dup2(file.handle, std_fileno),
44114408 }
44124409}
44134410
lib/std/Io/Threaded.zig+1-1
......@@ -15659,7 +15659,7 @@ fn setUpChildIo(stdio: process.SpawnOptions.StdIo, pipe_fd: i32, std_fileno: i32
1565915659 .close => closeFd(std_fileno),
1566015660 .inherit => {},
1566115661 .ignore => try dup2(dev_null_fd, std_fileno),
15662 .file => @panic("TODO implement setUpChildIo when file is used"),
15662 .file => |file| try dup2(file.handle, std_fileno),
1566315663 }
1566415664}
1566515665
lib/std/Io/Uring.zig+2-5
......@@ -4550,10 +4550,7 @@ fn setUpChildIo(
45504550 .close => _ = linux.close(std_fileno),
45514551 .inherit => {},
45524552 .ignore => try dup2(sync, dev_null_fd, std_fileno),
4553 .file => |file| {
4554 if (file.flags.nonblocking) @panic("TODO implement setUpChildIo when nonblocking file is used");
4555 try dup2(sync, file.handle, std_fileno);
4556 },
4553 .file => |file| try dup2(sync, file.handle, std_fileno),
45574554 }
45584555}
45594556
......@@ -4565,7 +4562,7 @@ pub fn dup2(sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) DupError!void
45654562 while (true) {
45664563 try sync.cancel_region.await(.nothing);
45674564 switch (linux.errno(linux.dup2(old_fd, new_fd))) {
4568 .SUCCESS => {},
4565 .SUCCESS => return,
45694566 .BUSY, .INTR => {},
45704567 .INVAL => |err| return errnoBug(err), // invalid parameters
45714568 .BADF => |err| return errnoBug(err), // use after free
lib/std/process.zig+6
......@@ -409,6 +409,12 @@ pub const SpawnOptions = struct {
409409 /// Inherit the corresponding stream from the parent process.
410410 inherit,
411411 /// Pass an already open file from the parent to the child.
412 ///
413 /// Nonblocking mode will be kept in the child process if present. This is
414 /// likely not supported by the child process. For example:
415 /// - Zig's std.Io.File.stdout() assumes blocking mode
416 /// - Rust explicity documents that nonblocking stdio may cause panics
417 /// - C++ standard streams do not support nonblocking file descriptors
412418 file: File,
413419 /// Pass a null stream to the child process by opening "/dev/null" on POSIX
414420 /// and "NUL" on Windows.