@@ -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+
10961120pub 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