authorgravatar for hnakamur@gmail.comHiroaki Nakamura <hnakamur@gmail.com> 2021-12-01 22:24:02+09:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-01 14:30:33-08:00
log0714832c21169493a0a857237fbface612e3d5e0
treec024a0dc7dfe5d836dcec91976fb895b1a18640e
parent70dcdcb73d42e69df50f3a4b721a7ecb30153758

Fix test for io_uring link_timeout

The old test "timeout_link_chain1" was ported from liburing test_timeout_link_chain1 https://github.com/axboe/liburing/blob/509873c4454012c5810c728695c21911c82acdc4/test/link-timeout.c#L539-L628 However it turns out that both fails with EBADF (-9) on Linux kernel 5.4. The this new test skips properly on Linux kernel 5.4 and passes on Linux kernel 5.11.

1 files changed, 48 insertions(+), 28 deletions(-)

lib/std/os/linux/io_uring.zig+48-28
......@@ -1840,42 +1840,73 @@ test "timeout_remove" {
18401840 }, cqe_timeout_remove);
18411841}
18421842
1843test "timeout_link_chain1" {
1843test "accept/connect/recv/link_timeout" {
18441844 if (builtin.os.tag != .linux) return error.SkipZigTest;
18451845
1846 var ring = IO_Uring.init(8, 0) catch |err| switch (err) {
1846 var ring = IO_Uring.init(16, 0) catch |err| switch (err) {
18471847 error.SystemOutdated => return error.SkipZigTest,
18481848 error.PermissionDenied => return error.SkipZigTest,
18491849 else => return err,
18501850 };
18511851 defer ring.deinit();
18521852
1853 var fds = try os.pipe();
1854 defer {
1855 os.close(fds[0]);
1856 os.close(fds[1]);
1853 const address = try net.Address.parseIp4("127.0.0.1", 3131);
1854 const kernel_backlog = 1;
1855 const server = try os.socket(address.any.family, os.SOCK.STREAM | os.SOCK.CLOEXEC, 0);
1856 defer os.close(server);
1857 try os.setsockopt(server, os.SOL.SOCKET, os.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
1858 try os.bind(server, &address.any, address.getOsSockLen());
1859 try os.listen(server, kernel_backlog);
1860
1861 var buffer_recv = [_]u8{ 0, 1, 0, 1, 0 };
1862
1863 var accept_addr: os.sockaddr = undefined;
1864 var accept_addr_len: os.socklen_t = @sizeOf(@TypeOf(accept_addr));
1865 _ = try ring.accept(0xaaaaaaaa, server, &accept_addr, &accept_addr_len, 0);
1866 try testing.expectEqual(@as(u32, 1), try ring.submit());
1867
1868 const client = try os.socket(address.any.family, os.SOCK.STREAM | os.SOCK.CLOEXEC, 0);
1869 defer os.close(client);
1870 _ = try ring.connect(0xcccccccc, client, &address.any, address.getOsSockLen());
1871 try testing.expectEqual(@as(u32, 1), try ring.submit());
1872
1873 var cqe_accept = try ring.copy_cqe();
1874 if (cqe_accept.err() == .INVAL) return error.SkipZigTest;
1875 var cqe_connect = try ring.copy_cqe();
1876 if (cqe_connect.err() == .INVAL) return error.SkipZigTest;
1877
1878 // The accept/connect CQEs may arrive in any order, the connect CQE will sometimes come first:
1879 if (cqe_accept.user_data == 0xcccccccc and cqe_connect.user_data == 0xaaaaaaaa) {
1880 const a = cqe_accept;
1881 const b = cqe_connect;
1882 cqe_accept = b;
1883 cqe_connect = a;
18571884 }
18581885
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;
1886 try testing.expectEqual(@as(u64, 0xaaaaaaaa), cqe_accept.user_data);
1887 if (cqe_accept.res <= 0) std.debug.print("\ncqe_accept.res={}\n", .{cqe_accept.res});
1888 try testing.expect(cqe_accept.res > 0);
1889 try testing.expectEqual(@as(u32, 0), cqe_accept.flags);
1890 try testing.expectEqual(linux.io_uring_cqe{
1891 .user_data = 0xcccccccc,
1892 .res = 0,
1893 .flags = 0,
1894 }, cqe_connect);
1895
1896 const sqe_recv = try ring.recv(0xffffffff, cqe_accept.res, buffer_recv[0..], 0);
1897 sqe_recv.flags |= linux.IOSQE_IO_LINK;
18631898
18641899 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);
1900 _ = try ring.link_timeout(0x22222222, &ts, 0);
18691901
18701902 const nr_wait = try ring.submit();
1871 try testing.expectEqual(@as(u32, 3), nr_wait);
1903 try testing.expectEqual(@as(u32, 2), nr_wait);
18721904
18731905 var i: usize = 0;
18741906 while (i < nr_wait) : (i += 1) {
18751907 const cqe = try ring.copy_cqe();
18761908 switch (cqe.user_data) {
1877 // poll cancel really should return -ECANCEL...
1878 0x11111111 => {
1909 0xffffffff => {
18791910 if (cqe.res != -@as(i32, @enumToInt(linux.E.INTR)) and
18801911 cqe.res != -@as(i32, @enumToInt(linux.E.CANCELED)))
18811912 {
......@@ -1884,20 +1915,9 @@ test "timeout_link_chain1" {
18841915 }
18851916 },
18861917 0x22222222 => {
1887 // FASTPOLL kernels can cancel successfully
18881918 if (cqe.res != -@as(i32, @enumToInt(linux.E.ALREADY)) and
18891919 cqe.res != -@as(i32, @enumToInt(linux.E.TIME)))
18901920 {
1891 if (cqe.res == -@as(i32, @enumToInt(linux.E.BADF))) {
1892 // https://github.com/ziglang/zig/issues/10247
1893 return error.SkipZigTest;
1894 }
1895 std.debug.print("Req 0x{x} got {d}\n", .{ cqe.user_data, cqe.res });
1896 try testing.expect(false);
1897 }
1898 },
1899 0x33333333 => {
1900 if (cqe.res != -@as(i32, @enumToInt(linux.E.CANCELED))) {
19011921 std.debug.print("Req 0x{x} got {d}\n", .{ cqe.user_data, cqe.res });
19021922 try testing.expect(false);
19031923 }