Skip to content

Commit d3745b1

Browse files
committed
add iouring waitid operation
1 parent 4e67818 commit d3745b1

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

src/backend/io_uring.zig

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ pub const Loop = struct {
543543
},
544544

545545
.cancel => |v| linux.io_uring_prep_cancel(sqe, @intCast(@intFromPtr(v.c)), 0),
546+
.waitid => |v| linux.io_uring_prep_waitid(sqe, v.id_type, v.id, v.infop, v.options, 0),
546547
}
547548

548549
// Our sqe user data always points back to the completion.
@@ -789,6 +790,13 @@ pub const Completion = struct {
789790
else => |errno| std.os.unexpectedErrno(errno),
790791
},
791792
},
793+
794+
.waitid => .{
795+
.waitid = if (res >= 0) {} else switch (@as(std.os.E, @enumFromInt(-res))) {
796+
.CHILD => error.NotFound,
797+
else => |errno| std.os.unexpectedErrno(errno),
798+
},
799+
},
792800
};
793801

794802
return self.callback(self.userdata, loop, self, result);
@@ -873,6 +881,9 @@ pub const OperationType = enum {
873881

874882
/// Cancel an existing operation.
875883
cancel,
884+
885+
/// Waitid
886+
waitid,
876887
};
877888

878889
/// The result type based on the operation type. For a callback, the
@@ -895,6 +906,7 @@ pub const Result = union(OperationType) {
895906
timer: TimerError!TimerTrigger,
896907
timer_remove: TimerRemoveError!void,
897908
cancel: CancelError!void,
909+
waitid: WaitidError!void,
898910
};
899911

900912
/// All the supported operations of this event loop. These are always
@@ -996,6 +1008,13 @@ pub const Operation = union(OperationType) {
9961008
cancel: struct {
9971009
c: *Completion,
9981010
},
1011+
1012+
waitid: struct {
1013+
id_type: linux.P,
1014+
id: i32,
1015+
infop: *linux.siginfo_t,
1016+
options: u32,
1017+
},
9991018
};
10001019

10011020
/// ReadBuffer are the various options for reading.
@@ -1093,6 +1112,11 @@ pub const TimerRemoveError = error{
10931112
Unexpected,
10941113
};
10951114

1115+
pub const WaitidError = error{
1116+
NotFound,
1117+
Unexpected,
1118+
};
1119+
10961120
pub const TimerTrigger = enum {
10971121
/// Timer completed due to linked request completing in time.
10981122
request,
@@ -1769,3 +1793,47 @@ test "io_uring: socket read cancellation" {
17691793
try testing.expectEqual(OperationType.read, @as(OperationType, read_result));
17701794
try testing.expectError(error.Canceled, read_result.read);
17711795
}
1796+
1797+
test "io_uring: waitid" {
1798+
const testing = std.testing;
1799+
1800+
if (@import("builtin").os.isAtLeast(.linux, .{ .major = 6, .minor = 7, .patch = 0 }) == false) {
1801+
return error.SkipZigTest;
1802+
}
1803+
1804+
var loop = try Loop.init(.{});
1805+
defer loop.deinit();
1806+
1807+
const pid = try std.os.fork();
1808+
if (pid == 0) {
1809+
std.os.exit(7);
1810+
}
1811+
var siginfo: std.os.siginfo_t = undefined;
1812+
var waitid_error: ?WaitidError = null;
1813+
var c_waitid = Completion{
1814+
.op = .{
1815+
.waitid = .{
1816+
.id_type = .PID,
1817+
.id = pid,
1818+
.infop = &siginfo,
1819+
.options = std.os.W.EXITED,
1820+
},
1821+
},
1822+
.userdata = &waitid_error,
1823+
.callback = (struct {
1824+
fn callback(ud: ?*anyopaque, _: *xev.Loop, _: *xev.Completion, r: xev.Result) xev.CallbackAction {
1825+
const ptr = @as(*?WaitidError, @ptrCast(@alignCast(ud.?)));
1826+
r.waitid catch |err| {
1827+
ptr.* = err;
1828+
};
1829+
return .disarm;
1830+
}
1831+
}).callback,
1832+
};
1833+
loop.add(&c_waitid);
1834+
try loop.run(.until_done);
1835+
1836+
try testing.expectEqual(null, waitid_error);
1837+
try testing.expectEqual(pid, siginfo.fields.common.first.piduid.pid);
1838+
try testing.expectEqual(7, siginfo.fields.common.second.sigchld.status);
1839+
}

0 commit comments

Comments
 (0)