| ... | @@ -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 | }; |
| 1640 | | 1640 | |
| | 1641 | const have_waitid = switch (native_os) { |
| | 1642 | .linux => @hasField(std.os.linux.SYS, "waitid"), |
| | 1643 | else => false, |
| | 1644 | }; |
| | 1645 | |
| 1641 | const have_wait4 = switch (native_os) { | 1646 | const 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 | }; |
| 1645 | | 1651 | |
| ... | @@ -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 | } |
| 13025 | | 13031 | |
| ... | @@ -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 | } |
| 13035 | | 13041 | |
| ... | @@ -13109,20 +13115,71 @@ fn childCleanupWindows(child: *process.Child) void { | ... | @@ -13109,20 +13115,71 @@ fn childCleanupWindows(child: *process.Child) void { |
| 13109 | } | 13115 | } |
| 13110 | } | 13116 | } |
| 13111 | | 13117 | |
| 13112 | fn childWaitPosix(t: *Threaded, child: *process.Child) process.Child.WaitError!process.Child.Term { | 13118 | fn childWaitPosix(current_thread: *Thread, child: *process.Child) process.Child.WaitError!process.Child.Term { |
| 13113 | _ = t; // TODO cancelation | 13119 | 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 | } |
| 13127 | | 13184 | |
| 13128 | fn statusToTerm(status: u32) process.Child.Term { | 13185 | fn 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 | } |
| 13138 | | 13195 | |
| 13139 | fn childKillPosix(t: *Threaded, child: *process.Child) !void { | 13196 | fn 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 | } |
| 13150 | | 13208 | |
| 13151 | fn childCleanupPosix(child: *process.Child) void { | 13209 | fn childCleanupPosix(child: *process.Child) void { |