authorgravatar for vlad@panazan.roVlad Pănăzan <vlad@panazan.ro> 2024-02-11 15:47:03+01:00
committergravatar for vlad@panazan.roVlad Pănăzan <vlad@panazan.ro> 2024-02-11 15:47:03+01:00
logd2789908ed02c286ef968d2d90cc38fd24ca0e10
tree78a2633e8089446597c5e0f682b95b6e2ee1eda7
parent20ea0012f049c6519ef83b577d1f43d72e243b31

io_uring: add waitid operation

This is the equivalent of a waitid(2) syscall and can be used to be notified about child process state changes. Available since kernel 6.7

1 files changed, 56 insertions(+), 0 deletions(-)

lib/std/os/linux/io_uring.zig+56
...@@ -1114,6 +1114,23 @@ pub const IO_Uring = struct {...@@ -1114,6 +1114,23 @@ pub const IO_Uring = struct {
1114 return sqe;1114 return sqe;
1115 }1115 }
11161116
1117 /// Queues (but does not submit) an SQE to perform a `waitid(2)`.
1118 /// Returns a pointer to the SQE.
1119 pub fn waitid(
1120 self: *IO_Uring,
1121 user_data: u64,
1122 id_type: linux.P,
1123 id: i32,
1124 infop: *linux.siginfo_t,
1125 options: u32,
1126 flags: u32,
1127 ) !*linux.io_uring_sqe {
1128 const sqe = try self.get_sqe();
1129 io_uring_prep_waitid(sqe, id_type, id, infop, options, flags);
1130 sqe.user_data = user_data;
1131 return sqe;
1132 }
1133
1117 /// Registers an array of file descriptors.1134 /// Registers an array of file descriptors.
1118 /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must1135 /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must
1119 /// retrieve a reference to the file, and once I/O has completed the file reference must be1136 /// retrieve a reference to the file, and once I/O has completed the file reference must be
...@@ -1962,6 +1979,19 @@ pub fn io_uring_prep_socket_direct_alloc(...@@ -1962,6 +1979,19 @@ pub fn io_uring_prep_socket_direct_alloc(
1962 __io_uring_set_target_fixed_file(sqe, linux.IORING_FILE_INDEX_ALLOC);1979 __io_uring_set_target_fixed_file(sqe, linux.IORING_FILE_INDEX_ALLOC);
1963}1980}
19641981
1982pub fn io_uring_prep_waitid(
1983 sqe: *linux.io_uring_sqe,
1984 id_type: linux.P,
1985 id: i32,
1986 infop: *linux.siginfo_t,
1987 options: u32,
1988 flags: u32,
1989) void {
1990 io_uring_prep_rw(.WAITID, sqe, id, 0, @intFromEnum(id_type), @intFromPtr(infop));
1991 sqe.rw_flags = flags;
1992 sqe.splice_fd_in = @bitCast(options);
1993}
1994
1965test "structs/offsets/entries" {1995test "structs/offsets/entries" {
1966 if (builtin.os.tag != .linux) return error.SkipZigTest;1996 if (builtin.os.tag != .linux) return error.SkipZigTest;
19671997
...@@ -4148,6 +4178,32 @@ test "openat_direct/close_direct" {...@@ -4148,6 +4178,32 @@ test "openat_direct/close_direct" {
4148 try ring.unregister_files();4178 try ring.unregister_files();
4149}4179}
41504180
4181test "waitid" {
4182 try skipKernelLessThan(.{ .major = 6, .minor = 7, .patch = 0 });
4183
4184 var ring = IO_Uring.init(16, 0) catch |err| switch (err) {
4185 error.SystemOutdated => return error.SkipZigTest,
4186 error.PermissionDenied => return error.SkipZigTest,
4187 else => return err,
4188 };
4189 defer ring.deinit();
4190
4191 const pid = try os.fork();
4192 if (pid == 0) {
4193 os.exit(7);
4194 }
4195
4196 var siginfo: os.siginfo_t = undefined;
4197 _ = try ring.waitid(0, .PID, pid, &siginfo, os.W.EXITED, 0);
4198
4199 try testing.expectEqual(1, try ring.submit());
4200
4201 const cqe_waitid = try ring.copy_cqe();
4202 try testing.expectEqual(0, cqe_waitid.res);
4203 try testing.expectEqual(pid, siginfo.fields.common.first.piduid.pid);
4204 try testing.expectEqual(7, siginfo.fields.common.second.sigchld.status);
4205}
4206
4151/// For use in tests. Returns SkipZigTest is kernel version is less than required.4207/// For use in tests. Returns SkipZigTest is kernel version is less than required.
4152inline fn skipKernelLessThan(required: std.SemanticVersion) !void {4208inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
4153 if (builtin.os.tag != .linux) return error.SkipZigTest;4209 if (builtin.os.tag != .linux) return error.SkipZigTest;