Skip to content

Commit e88bb54

Browse files
committed
std.process.Child: use pid_fd
1 parent 150031b commit e88bb54

File tree

1 file changed

+55
-6
lines changed

1 file changed

+55
-6
lines changed

lib/std/process/Child.zig

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub const Id = switch (native_os) {
2929
id: Id,
3030
thread_handle: if (native_os == .windows) windows.HANDLE else void,
3131

32+
/// Linux only. May be unavailable on older kernel versions.
33+
pid_fd: ?posix.fd_t,
34+
3235
allocator: mem.Allocator,
3336

3437
/// The writing end of the child process's standard input pipe.
@@ -213,6 +216,7 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess {
213216
.argv = argv,
214217
.id = undefined,
215218
.thread_handle = undefined,
219+
.pid_fd = null,
216220
.err_pipe = null,
217221
.term = null,
218222
.env_map = null,
@@ -291,10 +295,22 @@ pub fn killPosix(self: *ChildProcess) !Term {
291295
self.cleanupStreams();
292296
return term;
293297
}
294-
posix.kill(self.id, posix.SIG.TERM) catch |err| switch (err) {
295-
error.ProcessNotFound => return error.AlreadyTerminated,
296-
else => return err,
297-
};
298+
if (self.pid_fd) |pid_fd| {
299+
if (native_os == .linux) {
300+
switch (linux.E.init(linux.pidfd_send_signal(pid_fd, posix.SIG.TERM, null, 0))) {
301+
.SUCCESS => {},
302+
.SRCH => return error.AlreadyTerminated,
303+
else => |err| return posix.unexpectedErrno(err),
304+
}
305+
} else {
306+
unreachable;
307+
}
308+
} else {
309+
posix.kill(self.id, posix.SIG.TERM) catch |err| switch (err) {
310+
error.ProcessNotFound => return error.AlreadyTerminated,
311+
else => return err,
312+
};
313+
}
298314
self.waitUnwrapped();
299315
return self.term.?;
300316
}
@@ -305,6 +321,7 @@ pub const WaitError = SpawnError || std.os.windows.GetProcessMemoryInfoError;
305321
pub fn wait(self: *ChildProcess) WaitError!Term {
306322
const term = if (native_os == .windows) try self.waitWindows() else self.waitPosix();
307323
self.id = undefined;
324+
self.pid_fd = null;
308325
return term;
309326
}
310327

@@ -451,6 +468,34 @@ fn waitUnwrappedWindows(self: *ChildProcess) WaitError!void {
451468

452469
fn waitUnwrapped(self: *ChildProcess) void {
453470
const res: posix.WaitPidResult = res: {
471+
if (self.pid_fd) |pid_fd| {
472+
if (native_os == .linux) {
473+
var info: linux.siginfo_t = undefined;
474+
var ru: linux.rusage = undefined;
475+
while (true) {
476+
switch (linux.E.init(linux.syscall5(.waitid, @intFromEnum(linux.P.PIDFD), @intCast(pid_fd), @intFromPtr(&info), linux.W.EXITED, @intFromPtr(&ru)))) {
477+
.SUCCESS => break,
478+
.INTR => continue,
479+
else => unreachable,
480+
}
481+
}
482+
if (self.request_resource_usage_statistics) {
483+
self.resource_usage_statistics.rusage = ru;
484+
}
485+
const status: u32 = @bitCast(info.fields.common.second.sigchld.status);
486+
break :res posix.WaitPidResult{
487+
.pid = info.fields.common.first.piduid.pid,
488+
.status = switch (info.code) {
489+
1 => (status & 0xff) << 8, // CLD_EXITED
490+
2, 3 => status & 0x7f, // CLD_KILLED, CLD_DUMPED
491+
else => unreachable,
492+
},
493+
};
494+
} else {
495+
unreachable;
496+
}
497+
}
498+
454499
if (self.request_resource_usage_statistics) {
455500
switch (native_os) {
456501
.linux, .macos, .ios => {
@@ -727,13 +772,17 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
727772
defer self.allocator.free(stack);
728773

729774
var clone_args = mem.zeroes(linux.clone_args);
730-
clone_args.flags = linux.CLONE.VM | linux.CLONE.VFORK | linux.CLONE.CLEAR_SIGHAND;
775+
var pid_fd: posix.fd_t = undefined;
776+
clone_args.flags = linux.CLONE.VM | linux.CLONE.VFORK | linux.CLONE.CLEAR_SIGHAND | linux.CLONE.PIDFD;
731777
clone_args.exit_signal = linux.SIG.CHLD;
732778
clone_args.stack = @intFromPtr(stack.ptr);
733779
clone_args.stack_size = stack_size;
780+
clone_args.pidfd = @intFromPtr(&pid_fd);
734781
var rc = linux.clone3(&clone_args, @sizeOf(linux.clone_args), spawnPosixChildHelper, @intFromPtr(&child_arg));
735782
switch (linux.E.init(rc)) {
736-
.SUCCESS => {},
783+
.SUCCESS => {
784+
self.pid_fd = pid_fd;
785+
},
737786
.AGAIN, .NOMEM => return error.SystemResources,
738787
.INVAL, .NOSYS => {
739788
// Fallback to use clone().

0 commit comments

Comments
 (0)