Skip to content

Commit 545ef7c

Browse files
committed
linux: emulate wait4 using waitid
1 parent 91b3769 commit 545ef7c

File tree

1 file changed

+50
-9
lines changed

1 file changed

+50
-9
lines changed

lib/std/os/linux.zig

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,21 +1586,62 @@ 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 {
1594-
return syscall4(
1595-
.wait4,
1596-
@as(usize, @bitCast(@as(isize, pid))),
1597-
@intFromPtr(status),
1598-
flags,
1593+
pub fn wait4(pid: pid_t, status: ?*u32, flags: u32, usage: ?*rusage) usize {
1594+
if (@hasField(SYS, "wait4")) {
1595+
return syscall4(
1596+
.wait4,
1597+
@as(usize, @bitCast(@as(isize, pid))),
1598+
@intFromPtr(status),
1599+
flags,
1600+
@intFromPtr(usage),
1601+
);
1602+
}
1603+
1604+
// Emulate wait4 using waitid; adapted from musl/src/internal/emulate_wait4.c
1605+
1606+
const id_type: P = if (pid < -1 or pid == 0) .PGID else if (pid == -1) .ALL else .PID;
1607+
const id = if (pid < -1) -pid else pid;
1608+
1609+
var info: siginfo_t = undefined;
1610+
info.fields.common.first.piduid.pid = 0;
1611+
1612+
const r = syscall5(
1613+
.waitid,
1614+
@intFromEnum(id_type),
1615+
@bitCast(@as(isize, id)),
1616+
@intFromPtr(&info),
1617+
flags | W.EXITED,
15991618
@intFromPtr(usage),
16001619
);
1620+
if (@clz(r) == 0) return r; // r < 0
1621+
// WNOHANG passed and no children in waitable state
1622+
if (info.fields.common.first.piduid.pid == 0) return 0;
1623+
1624+
if (status) |s| {
1625+
const si_status: u32 = @bitCast(info.fields.common.second.sigchld.status);
1626+
s.* = switch (info.code) {
1627+
// CLD_EXITED
1628+
1 => (si_status & 0xff) << 8,
1629+
// CLD_KILLED
1630+
2 => si_status & 0x7f,
1631+
// CLD_DUMPED
1632+
3 => si_status & 0x7f | 0x80,
1633+
// CLD_TRAPPED, CLD_STOPPED
1634+
// see ptrace(2); the high bits of si_status can contain PTRACE_EVENT_ values which must be preserved
1635+
4, 5 => (si_status << 8) + 0x7f,
1636+
// CLD_CONTINUED
1637+
6 => 0xffff,
1638+
else => unreachable,
1639+
};
1640+
}
1641+
return @bitCast(@as(isize, info.fields.common.first.piduid.pid));
16011642
}
16021643

1603-
pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize {
1644+
pub fn waitid(id_type: P, id: pid_t, infop: *siginfo_t, flags: u32) usize {
16041645
return syscall5(.waitid, @intFromEnum(id_type), @as(usize, @bitCast(@as(isize, id))), @intFromPtr(infop), flags, 0);
16051646
}
16061647

0 commit comments

Comments
 (0)