authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-02 20:19:32-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-04 00:27:08-08:00
logc6b75b61b7dc914c46de86aa764958f6954d28a4
treebb11834317287dc2d9ae28ae0f25decdd1a6458c
parentd97e4ca0d1de34c8987e675b4d61312e42a1d984

std: fix child processes on riscv32-linux


3 files changed, 94 insertions(+), 60 deletions(-)

lib/std/Io/Threaded.zig+75-17
...@@ -1638,8 +1638,14 @@ const have_fchmod = switch (native_os) {...@@ -1638,8 +1638,14 @@ const have_fchmod = switch (native_os) {
1638 else => true,1638 else => true,
1639};1639};
16401640
1641const have_waitid = switch (native_os) {
1642 .linux => @hasField(std.os.linux.SYS, "waitid"),
1643 else => false,
1644};
1645
1641const have_wait4 = switch (native_os) {1646const have_wait4 = switch (native_os) {
1642 .dragonfly, .freebsd, .netbsd, .openbsd, .illumos, .linux, .serenity, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => true,1647 .linux => @hasField(std.os.linux.SYS, "wait4"),
1648 .dragonfly, .freebsd, .netbsd, .openbsd, .illumos, .serenity, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => true,
1643 else => false,1649 else => false,
1644};1650};
16451651
...@@ -13019,7 +13025,7 @@ fn childWait(userdata: ?*anyopaque, child: *std.process.Child) process.Child.Wai...@@ -13019,7 +13025,7 @@ fn childWait(userdata: ?*anyopaque, child: *std.process.Child) process.Child.Wai
13019 const t: *Threaded = @ptrCast(@alignCast(userdata));13025 const t: *Threaded = @ptrCast(@alignCast(userdata));
13020 switch (native_os) {13026 switch (native_os) {
13021 .windows => return childWaitWindows(t, child),13027 .windows => return childWaitWindows(t, child),
13022 else => return childWaitPosix(t, child),13028 else => return childWaitPosix(Thread.getCurrent(t), child),
13023 }13029 }
13024}13030}
1302513031
...@@ -13029,7 +13035,7 @@ fn childKill(userdata: ?*anyopaque, child: *std.process.Child) void {...@@ -13029,7 +13035,7 @@ fn childKill(userdata: ?*anyopaque, child: *std.process.Child) void {
13029 if (is_windows) {13035 if (is_windows) {
13030 childKillWindows(t, child, 1) catch childCleanupWindows(child);13036 childKillWindows(t, child, 1) catch childCleanupWindows(child);
13031 } else {13037 } else {
13032 childKillPosix(t, child) catch childCleanupPosix(child);13038 childKillPosix(Thread.getCurrent(t), child) catch childCleanupPosix(child);
13033 }13039 }
13034}13040}
1303513041
...@@ -13109,20 +13115,71 @@ fn childCleanupWindows(child: *process.Child) void {...@@ -13109,20 +13115,71 @@ fn childCleanupWindows(child: *process.Child) void {
13109 }13115 }
13110}13116}
1311113117
13112fn childWaitPosix(t: *Threaded, child: *process.Child) process.Child.WaitError!process.Child.Term {13118fn childWaitPosix(current_thread: *Thread, child: *process.Child) process.Child.WaitError!process.Child.Term {
13113 _ = t; // TODO cancelation13119 defer childCleanupPosix(child);
13120
13114 const pid = child.id.?;13121 const pid = child.id.?;
13115 const res: posix.WaitPidResult = res: {13122
13116 if (child.request_resource_usage_statistics and have_wait4) {13123 var ru: posix.rusage = undefined;
13117 var ru: posix.rusage = undefined;13124 const ru_ptr = if (child.request_resource_usage_statistics) &ru else null;
13118 const res = posix.wait4(pid, 0, &ru);13125
13119 child.resource_usage_statistics.rusage = ru;13126 if (have_wait4) {
13120 break :res res;13127 var status: if (builtin.link_libc) c_int else u32 = undefined;
13121 }13128 try current_thread.beginSyscall();
13122 break :res posix.waitpid(pid, 0);13129 while (true) switch (posix.errno(posix.system.wait4(pid, &status, 0, ru_ptr))) {
13130 .SUCCESS => {
13131 current_thread.endSyscall();
13132 if (ru_ptr) |p| child.resource_usage_statistics.rusage = p.*;
13133 return statusToTerm(@bitCast(status));
13134 },
13135 .INTR => {
13136 try current_thread.checkCancel();
13137 continue;
13138 },
13139 .CHILD => |err| return current_thread.endSyscallErrnoBug(err), // Double-free.
13140 else => |err| return current_thread.endSyscallUnexpectedErrno(err),
13141 };
13142 }
13143
13144 if (have_waitid) {
13145 const linux = std.os.linux; // Bypass libc which has the wrong signature.
13146 var info: linux.siginfo_t = undefined;
13147 try current_thread.beginSyscall();
13148 while (true) switch (linux.errno(linux.waitid(.PID, pid, &info, linux.W.EXITED, ru_ptr))) {
13149 .SUCCESS => {
13150 current_thread.endSyscall();
13151 if (ru_ptr) |p| child.resource_usage_statistics.rusage = p.*;
13152 const status: u32 = @bitCast(info.fields.common.second.sigchld.status);
13153 const code: linux.CLD = @enumFromInt(info.code);
13154 return switch (code) {
13155 .EXITED => .{ .exited = @truncate(status) },
13156 .KILLED, .DUMPED => .{ .signal = @enumFromInt(status) },
13157 .TRAPPED, .STOPPED => .{ .stopped = status },
13158 _, .CONTINUED => .{ .unknown = status },
13159 };
13160 },
13161 .INTR => {
13162 try current_thread.checkCancel();
13163 continue;
13164 },
13165 .CHILD => |err| return current_thread.endSyscallErrnoBug(err), // Double-free.
13166 else => |err| return current_thread.endSyscallUnexpectedErrno(err),
13167 };
13168 }
13169
13170 var status: if (builtin.link_libc) c_int else u32 = undefined;
13171 while (true) switch (posix.errno(posix.system.waitpid(pid, &status, 0))) {
13172 .SUCCESS => {
13173 current_thread.endSyscall();
13174 return statusToTerm(@bitCast(status));
13175 },
13176 .INTR => {
13177 try current_thread.checkCancel();
13178 continue;
13179 },
13180 .CHILD => |err| return current_thread.endSyscallErrnoBug(err), // Double-free.
13181 else => |err| return current_thread.endSyscallUnexpectedErrno(err),
13123 };13182 };
13124 childCleanupPosix(child);
13125 return statusToTerm(res.status);
13126}13183}
1312713184
13128fn statusToTerm(status: u32) process.Child.Term {13185fn statusToTerm(status: u32) process.Child.Term {
...@@ -13136,7 +13193,8 @@ fn statusToTerm(status: u32) process.Child.Term {...@@ -13136,7 +13193,8 @@ fn statusToTerm(status: u32) process.Child.Term {
13136 .{ .unknown = status };13193 .{ .unknown = status };
13137}13194}
1313813195
13139fn childKillPosix(t: *Threaded, child: *process.Child) !void {13196fn childKillPosix(current_thread: *Thread, child: *process.Child) !void {
13197 // Intentionally uncancelable.
13140 while (true) switch (posix.errno(posix.system.kill(child.id.?, .TERM))) {13198 while (true) switch (posix.errno(posix.system.kill(child.id.?, .TERM))) {
13141 .SUCCESS => break,13199 .SUCCESS => break,
13142 .INTR => continue,13200 .INTR => continue,
...@@ -13145,7 +13203,7 @@ fn childKillPosix(t: *Threaded, child: *process.Child) !void {...@@ -13145,7 +13203,7 @@ fn childKillPosix(t: *Threaded, child: *process.Child) !void {
13145 .SRCH => |err| return errnoBug(err),13203 .SRCH => |err| return errnoBug(err),
13146 else => |err| return posix.unexpectedErrno(err),13204 else => |err| return posix.unexpectedErrno(err),
13147 };13205 };
13148 _ = try childWaitPosix(t, child);13206 _ = try childWaitPosix(current_thread, child);
13149}13207}
1315013208
13151fn childCleanupPosix(child: *process.Child) void {13209fn childCleanupPosix(child: *process.Child) void {
lib/std/os/linux.zig+19-2
...@@ -1598,8 +1598,15 @@ pub fn wait4(pid: pid_t, status: *u32, flags: u32, usage: ?*rusage) usize {...@@ -1598,8 +1598,15 @@ pub fn wait4(pid: pid_t, status: *u32, flags: u32, usage: ?*rusage) usize {
1598 );1598 );
1599}1599}
16001600
1601pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize {1601pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32, usage: ?*rusage) usize {
1602 return syscall5(.waitid, @intFromEnum(id_type), @as(usize, @bitCast(@as(isize, id))), @intFromPtr(infop), flags, 0);1602 return syscall5(
1603 .waitid,
1604 @intFromEnum(id_type),
1605 @as(usize, @bitCast(@as(isize, id))),
1606 @intFromPtr(infop),
1607 flags,
1608 @intFromPtr(usage),
1609 );
1603}1610}
16041611
1605pub const F = struct {1612pub const F = struct {
...@@ -6205,6 +6212,16 @@ const siginfo_fields_union = extern union {...@@ -6205,6 +6212,16 @@ const siginfo_fields_union = extern union {
6205 },6212 },
6206};6213};
62076214
6215pub const CLD = enum(i32) {
6216 EXITED = 1,
6217 KILLED = 2,
6218 DUMPED = 3,
6219 TRAPPED = 4,
6220 STOPPED = 5,
6221 CONTINUED = 6,
6222 _,
6223};
6224
6208pub const siginfo_t = if (is_mips)6225pub const siginfo_t = if (is_mips)
6209 extern struct {6226 extern struct {
6210 signo: SIG,6227 signo: SIG,
lib/std/posix.zig-41
...@@ -1690,47 +1690,6 @@ pub fn getsockoptError(sockfd: fd_t) ConnectError!void {...@@ -1690,47 +1690,6 @@ pub fn getsockoptError(sockfd: fd_t) ConnectError!void {
1690 }1690 }
1691}1691}
16921692
1693pub const WaitPidResult = struct {
1694 pid: pid_t,
1695 status: u32,
1696};
1697
1698/// Use this version of the `waitpid` wrapper if you spawned your child process using explicit
1699/// `fork` and `execve` method.
1700pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult {
1701 var status: if (builtin.link_libc) c_int else u32 = undefined;
1702 while (true) {
1703 const rc = system.waitpid(pid, &status, @intCast(flags));
1704 switch (errno(rc)) {
1705 .SUCCESS => return .{
1706 .pid = @intCast(rc),
1707 .status = @bitCast(status),
1708 },
1709 .INTR => continue,
1710 .CHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
1711 .INVAL => unreachable, // Invalid flags.
1712 else => unreachable,
1713 }
1714 }
1715}
1716
1717pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult {
1718 var status: if (builtin.link_libc) c_int else u32 = undefined;
1719 while (true) {
1720 const rc = system.wait4(pid, &status, @intCast(flags), ru);
1721 switch (errno(rc)) {
1722 .SUCCESS => return .{
1723 .pid = @intCast(rc),
1724 .status = @bitCast(status),
1725 },
1726 .INTR => continue,
1727 .CHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
1728 .INVAL => unreachable, // Invalid flags.
1729 else => unreachable,
1730 }
1731 }
1732}
1733
1734pub const FStatError = std.Io.File.StatError;1693pub const FStatError = std.Io.File.StatError;
17351694
1736/// Return information about a file descriptor.1695/// Return information about a file descriptor.