From d3745b176eff84832c8e6c9223fb38633481905c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlad=20P=C4=83n=C4=83zan?= Date: Tue, 13 Feb 2024 21:12:54 +0100 Subject: [PATCH] add iouring waitid operation --- src/backend/io_uring.zig | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/backend/io_uring.zig b/src/backend/io_uring.zig index 7fb63fd..890b848 100644 --- a/src/backend/io_uring.zig +++ b/src/backend/io_uring.zig @@ -543,6 +543,7 @@ pub const Loop = struct { }, .cancel => |v| linux.io_uring_prep_cancel(sqe, @intCast(@intFromPtr(v.c)), 0), + .waitid => |v| linux.io_uring_prep_waitid(sqe, v.id_type, v.id, v.infop, v.options, 0), } // Our sqe user data always points back to the completion. @@ -789,6 +790,13 @@ pub const Completion = struct { else => |errno| std.os.unexpectedErrno(errno), }, }, + + .waitid => .{ + .waitid = if (res >= 0) {} else switch (@as(std.os.E, @enumFromInt(-res))) { + .CHILD => error.NotFound, + else => |errno| std.os.unexpectedErrno(errno), + }, + }, }; return self.callback(self.userdata, loop, self, result); @@ -873,6 +881,9 @@ pub const OperationType = enum { /// Cancel an existing operation. cancel, + + /// Waitid + waitid, }; /// The result type based on the operation type. For a callback, the @@ -895,6 +906,7 @@ pub const Result = union(OperationType) { timer: TimerError!TimerTrigger, timer_remove: TimerRemoveError!void, cancel: CancelError!void, + waitid: WaitidError!void, }; /// All the supported operations of this event loop. These are always @@ -996,6 +1008,13 @@ pub const Operation = union(OperationType) { cancel: struct { c: *Completion, }, + + waitid: struct { + id_type: linux.P, + id: i32, + infop: *linux.siginfo_t, + options: u32, + }, }; /// ReadBuffer are the various options for reading. @@ -1093,6 +1112,11 @@ pub const TimerRemoveError = error{ Unexpected, }; +pub const WaitidError = error{ + NotFound, + Unexpected, +}; + pub const TimerTrigger = enum { /// Timer completed due to linked request completing in time. request, @@ -1769,3 +1793,47 @@ test "io_uring: socket read cancellation" { try testing.expectEqual(OperationType.read, @as(OperationType, read_result)); try testing.expectError(error.Canceled, read_result.read); } + +test "io_uring: waitid" { + const testing = std.testing; + + if (@import("builtin").os.isAtLeast(.linux, .{ .major = 6, .minor = 7, .patch = 0 }) == false) { + return error.SkipZigTest; + } + + var loop = try Loop.init(.{}); + defer loop.deinit(); + + const pid = try std.os.fork(); + if (pid == 0) { + std.os.exit(7); + } + var siginfo: std.os.siginfo_t = undefined; + var waitid_error: ?WaitidError = null; + var c_waitid = Completion{ + .op = .{ + .waitid = .{ + .id_type = .PID, + .id = pid, + .infop = &siginfo, + .options = std.os.W.EXITED, + }, + }, + .userdata = &waitid_error, + .callback = (struct { + fn callback(ud: ?*anyopaque, _: *xev.Loop, _: *xev.Completion, r: xev.Result) xev.CallbackAction { + const ptr = @as(*?WaitidError, @ptrCast(@alignCast(ud.?))); + r.waitid catch |err| { + ptr.* = err; + }; + return .disarm; + } + }).callback, + }; + loop.add(&c_waitid); + try loop.run(.until_done); + + try testing.expectEqual(null, waitid_error); + try testing.expectEqual(pid, siginfo.fields.common.first.piduid.pid); + try testing.expectEqual(7, siginfo.fields.common.second.sigchld.status); +}