authorgravatar for hnakamur@users.noreply.github.comHiroaki Nakamura <hnakamur@users.noreply.github.com> 2021-11-24 03:32:25+09:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-23 12:32:25-06:00
logf5c0c0803fab4a18d612cc8b8649566463cf5d60
treef9746d11ecb47d0d567beb31eaa3cfd822a68c01
parente08b6149ab8fb80ad8fa4983ad3aca8ef3303a9f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10151 from hnakamur/zig

io_uring: adds link_timeout

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

lib/std/os/linux/io_uring.zig+100
......@@ -607,6 +607,34 @@ pub const IO_Uring = struct {
607607 return sqe;
608608 }
609609
610 /// Queues (but does not submit) an SQE to add a link timeout operation.
611 /// Returns a pointer to the SQE.
612 ///
613 /// You need to set linux.IOSQE_IO_LINK to flags of the target operation
614 /// and then call this method right after the target operation.
615 /// See https://lwn.net/Articles/803932/ for detail.
616 ///
617 /// If the dependent request finishes before the linked timeout, the timeout
618 /// is canceled. If the timeout finishes before the dependent request, the
619 /// dependent request will be canceled.
620 ///
621 /// The completion event result of the link_timeout will be
622 /// `-ETIME` if the timeout finishes before the dependent request
623 /// (in this case, the completion event result of the dependent request will
624 /// be `-ECANCELED`), or
625 /// `-EALREADY` if the dependent request finishes before the linked timeout.
626 pub fn link_timeout(
627 self: *IO_Uring,
628 user_data: u64,
629 ts: *const os.linux.kernel_timespec,
630 flags: u32,
631 ) !*io_uring_sqe {
632 const sqe = try self.get_sqe();
633 io_uring_prep_link_timeout(sqe, ts, flags);
634 sqe.user_data = user_data;
635 return sqe;
636 }
637
610638 /// Queues (but does not submit) an SQE to perform a `poll(2)`.
611639 /// Returns a pointer to the SQE.
612640 pub fn poll_add(
......@@ -1170,6 +1198,15 @@ pub fn io_uring_prep_timeout_remove(sqe: *io_uring_sqe, timeout_user_data: u64,
11701198 };
11711199}
11721200
1201pub fn io_uring_prep_link_timeout(
1202 sqe: *io_uring_sqe,
1203 ts: *const os.linux.kernel_timespec,
1204 flags: u32,
1205) void {
1206 linux.io_uring_prep_rw(.LINK_TIMEOUT, sqe, -1, @ptrToInt(ts), 1, 0);
1207 sqe.rw_flags = flags;
1208}
1209
11731210pub fn io_uring_prep_poll_add(
11741211 sqe: *io_uring_sqe,
11751212 fd: os.fd_t,
......@@ -1803,6 +1840,69 @@ test "timeout_remove" {
18031840 }, cqe_timeout_remove);
18041841}
18051842
1843test "timeout_link_chain1" {
1844 if (builtin.os.tag != .linux) return error.SkipZigTest;
1845
1846 var ring = IO_Uring.init(8, 0) catch |err| switch (err) {
1847 error.SystemOutdated => return error.SkipZigTest,
1848 error.PermissionDenied => return error.SkipZigTest,
1849 else => return err,
1850 };
1851 defer ring.deinit();
1852
1853 var fds = try os.pipe();
1854 defer {
1855 os.close(fds[0]);
1856 os.close(fds[1]);
1857 }
1858
1859 var buffer = [_]u8{0} ** 128;
1860 const iovecs = [_]os.iovec{os.iovec{ .iov_base = &buffer, .iov_len = buffer.len }};
1861 const sqe_readv = try ring.readv(0x11111111, fds[0], &iovecs, 0);
1862 sqe_readv.flags |= linux.IOSQE_IO_LINK;
1863
1864 const ts = os.linux.kernel_timespec{ .tv_sec = 0, .tv_nsec = 1000000 };
1865 const seq_link_timeout = try ring.link_timeout(0x22222222, &ts, 0);
1866 seq_link_timeout.flags |= linux.IOSQE_IO_LINK;
1867
1868 _ = try ring.nop(0x33333333);
1869
1870 const nr_wait = try ring.submit();
1871 try testing.expectEqual(@as(u32, 3), nr_wait);
1872
1873 var i: usize = 0;
1874 while (i < nr_wait) : (i += 1) {
1875 const cqe = try ring.copy_cqe();
1876 switch (cqe.user_data) {
1877 // poll cancel really should return -ECANCEL...
1878 0x11111111 => {
1879 if (cqe.res != -@as(i32, @enumToInt(linux.E.INTR)) and
1880 cqe.res != -@as(i32, @enumToInt(linux.E.CANCELED)))
1881 {
1882 std.debug.print("Req 0x{x} got {d}\n", .{ cqe.user_data, cqe.res });
1883 try testing.expect(false);
1884 }
1885 },
1886 0x22222222 => {
1887 // FASTPOLL kernels can cancel successfully
1888 if (cqe.res != -@as(i32, @enumToInt(linux.E.ALREADY)) and
1889 cqe.res != -@as(i32, @enumToInt(linux.E.TIME)))
1890 {
1891 std.debug.print("Req 0x{x} got {d}\n", .{ cqe.user_data, cqe.res });
1892 try testing.expect(false);
1893 }
1894 },
1895 0x33333333 => {
1896 if (cqe.res != -@as(i32, @enumToInt(linux.E.CANCELED))) {
1897 std.debug.print("Req 0x{x} got {d}\n", .{ cqe.user_data, cqe.res });
1898 try testing.expect(false);
1899 }
1900 },
1901 else => @panic("should not happen"),
1902 }
1903 }
1904}
1905
18061906test "fallocate" {
18071907 if (builtin.os.tag != .linux) return error.SkipZigTest;
18081908