Skip to content

Commit a6320e6

Browse files
committed
std.posix: emulate wait4 using waitid on linux
1 parent 91b3769 commit a6320e6

File tree

2 files changed

+56
-10
lines changed

2 files changed

+56
-10
lines changed

lib/std/os/linux.zig

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,11 +1586,11 @@ pub fn unlinkat(dirfd: i32, path: [*:0]const u8, flags: u32) usize {
15861586
return syscall3(.unlinkat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), flags);
15871587
}
15881588

1589-
pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize {
1590-
return syscall4(.wait4, @as(usize, @bitCast(@as(isize, pid))), @intFromPtr(status), flags, 0);
1589+
pub fn waitpid(pid: pid_t, status: ?*u32, flags: u32) usize {
1590+
return wait4(pid, status, flags, null);
15911591
}
15921592

1593-
pub fn wait4(pid: pid_t, status: *u32, flags: u32, usage: ?*rusage) usize {
1593+
pub fn wait4(pid: pid_t, status: ?*u32, flags: u32, usage: ?*rusage) usize {
15941594
return syscall4(
15951595
.wait4,
15961596
@as(usize, @bitCast(@as(isize, pid))),
@@ -1600,8 +1600,15 @@ pub fn wait4(pid: pid_t, status: *u32, flags: u32, usage: ?*rusage) usize {
16001600
);
16011601
}
16021602

1603-
pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize {
1604-
return syscall5(.waitid, @intFromEnum(id_type), @as(usize, @bitCast(@as(isize, id))), @intFromPtr(infop), flags, 0);
1603+
pub fn waitid(id_type: P, id: pid_t, infop: *siginfo_t, flags: u32, usage: ?*rusage) usize {
1604+
return syscall5(
1605+
.waitid,
1606+
@intFromEnum(id_type),
1607+
@as(usize, @bitCast(@as(isize, id))),
1608+
@intFromPtr(infop),
1609+
flags,
1610+
@intFromPtr(usage),
1611+
);
16051612
}
16061613

16071614
pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize {

lib/std/posix.zig

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ pub fn errno(rc: anytype) E {
270270
if (use_libc) {
271271
return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
272272
}
273-
const signed: isize = @bitCast(rc);
273+
const signed: isize = if (@typeInfo(@TypeOf(rc)).int.signedness == .unsigned) @bitCast(@as(usize, rc)) else rc;
274274
const int = if (signed > -4096 and signed < 0) -signed else 0;
275275
return @enumFromInt(int);
276276
}
@@ -4420,7 +4420,9 @@ pub const WaitPidResult = struct {
44204420
/// Use this version of the `waitpid` wrapper if you spawned your child process using explicit
44214421
/// `fork` and `execve` method.
44224422
pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult {
4423-
var status: if (builtin.link_libc) c_int else u32 = undefined;
4423+
if (!use_libc and builtin.os.tag == .linux) return wait4(pid, flags, null);
4424+
4425+
var status: if (use_libc) c_int else u32 = undefined;
44244426
while (true) {
44254427
const rc = system.waitpid(pid, &status, @intCast(flags));
44264428
switch (errno(rc)) {
@@ -4437,12 +4439,11 @@ pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult {
44374439
}
44384440

44394441
pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult {
4440-
var status: if (builtin.link_libc) c_int else u32 = undefined;
44414442
while (true) {
4442-
const rc = system.wait4(pid, &status, @intCast(flags), ru);
4443+
const rc, const status = wait4_impl(pid, flags, ru);
44434444
switch (errno(rc)) {
44444445
.SUCCESS => return .{
4445-
.pid = @intCast(rc),
4446+
.pid = rc,
44464447
.status = @bitCast(status),
44474448
},
44484449
.INTR => continue,
@@ -4453,6 +4454,44 @@ pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult {
44534454
}
44544455
}
44554456

4457+
fn wait4_impl(pid: pid_t, flags: u32, ru: ?*rusage) struct { pid_t, if (use_libc) c_int else u32 } {
4458+
if (use_libc or builtin.os.tag != .linux) {
4459+
var status: if (use_libc) c_int else u32 = undefined;
4460+
const rc = system.wait4(pid, &status, @intCast(flags), ru);
4461+
return .{ rc, status };
4462+
}
4463+
4464+
// Emulate wait4 using waitid; adapted from musl/src/internal/emulate_wait4.c
4465+
4466+
const id_type: system.P = if (pid < -1 or pid == 0) .PGID else if (pid == -1) .ALL else .PID;
4467+
const id = if (pid < -1) -pid else pid;
4468+
4469+
var info: siginfo_t = undefined;
4470+
info.fields.common.first.piduid.pid = 0;
4471+
4472+
const r: isize = @bitCast(system.waitid(id_type, id, &info, flags | W.EXITED, ru));
4473+
if (r < 0) return .{ @intCast(r), 0 }; // r < 0
4474+
// WNOHANG passed and no children in waitable state
4475+
if (info.fields.common.first.piduid.pid == 0) return .{ 0, 0 };
4476+
4477+
const si_status: u32 = @bitCast(info.fields.common.second.sigchld.status);
4478+
const status = switch (info.code) {
4479+
// CLD_EXITED
4480+
1 => (si_status & 0xff) << 8,
4481+
// CLD_KILLED
4482+
2 => si_status & 0x7f,
4483+
// CLD_DUMPED
4484+
3 => si_status & 0x7f | 0x80,
4485+
// CLD_TRAPPED, CLD_STOPPED
4486+
// see ptrace(2); the high bits of si_status can contain PTRACE_EVENT_ values which must be preserved
4487+
4, 5 => (si_status << 8) + 0x7f,
4488+
// CLD_CONTINUED
4489+
6 => 0xffff,
4490+
else => unreachable,
4491+
};
4492+
return .{ info.fields.common.first.piduid.pid, status };
4493+
}
4494+
44564495
pub const FStatError = error{
44574496
SystemResources,
44584497

0 commit comments

Comments
 (0)