authorgravatar for mega.alpha100@gmail.comBernard Assan <mega.alpha100@gmail.com> 2026-04-16 11:54:46+00:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-08 20:33:19+02:00
log6fd38ce13f4cff552272fcc33c8a23d735ac0a49
tree80252825b789f991fd226440ad5cba45d541d298
parent8dfddf95fee5982d22512c0ac15278eabac5bcbb

Use iouring probing over kernel version checks

this will enable test passing on all linux kernels (particularly WSL) without version checks and making `skipKernelLessThan` redundant closes https://github.com/ziglang/zig/pull/24042 Signed-off-by: Bernard Assan <mega.alpha100@gmail.com>

1 files changed, 26 insertions(+), 57 deletions(-)

lib/std/os/linux/IoUring/test.zig+26-57
...@@ -475,9 +475,6 @@ test "close" {...@@ -475,9 +475,6 @@ test "close" {
475}475}
476476
477test "accept/connect/send/recv" {477test "accept/connect/send/recv" {
478 const io = testing.io;
479 _ = io;
480
481 var ring = IoUring.init(16, 0) catch |err| switch (err) {478 var ring = IoUring.init(16, 0) catch |err| switch (err) {
482 error.SystemOutdated => return error.SkipZigTest,479 error.SystemOutdated => return error.SkipZigTest,
483 error.PermissionDenied => return error.SkipZigTest,480 error.PermissionDenied => return error.SkipZigTest,
...@@ -620,7 +617,7 @@ test "timeout (after a relative time)" {...@@ -620,7 +617,7 @@ test "timeout (after a relative time)" {
620617
621 const ms = 10;618 const ms = 10;
622 const margin = 5;619 const margin = 5;
623 const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = ms * 1000000 };620 const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = ms * std.time.ns_per_ms };
624621
625 const started = std.Io.Clock.awake.now(io);622 const started = std.Io.Clock.awake.now(io);
626 const sqe = try ring.timeout(0x55555555, &ts, 0, 0);623 const sqe = try ring.timeout(0x55555555, &ts, 0, 0);
...@@ -730,9 +727,6 @@ test "timeout_remove" {...@@ -730,9 +727,6 @@ test "timeout_remove" {
730}727}
731728
732test "accept/connect/recv/link_timeout" {729test "accept/connect/recv/link_timeout" {
733 const io = testing.io;
734 _ = io;
735
736 var ring = IoUring.init(16, 0) catch |err| switch (err) {730 var ring = IoUring.init(16, 0) catch |err| switch (err) {
737 error.SystemOutdated => return error.SkipZigTest,731 error.SystemOutdated => return error.SkipZigTest,
738 error.PermissionDenied => return error.SkipZigTest,732 error.PermissionDenied => return error.SkipZigTest,
...@@ -748,7 +742,7 @@ test "accept/connect/recv/link_timeout" {...@@ -748,7 +742,7 @@ test "accept/connect/recv/link_timeout" {
748 const sqe_recv = try ring.recv(0xffffffff, socket_test_harness.server, .{ .buffer = buffer_recv[0..] }, 0);742 const sqe_recv = try ring.recv(0xffffffff, socket_test_harness.server, .{ .buffer = buffer_recv[0..] }, 0);
749 sqe_recv.flags |= linux.IOSQE_IO_LINK;743 sqe_recv.flags |= linux.IOSQE_IO_LINK;
750744
751 const ts = linux.kernel_timespec{ .sec = 0, .nsec = 1000000 };745 const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = std.time.ns_per_ms };
752 _ = try ring.link_timeout(0x22222222, &ts, 0);746 _ = try ring.link_timeout(0x22222222, &ts, 0);
753747
754 const nr_wait = try ring.submit();748 const nr_wait = try ring.submit();
...@@ -883,9 +877,6 @@ test "statx" {...@@ -883,9 +877,6 @@ test "statx" {
883}877}
884878
885test "accept/connect/recv/cancel" {879test "accept/connect/recv/cancel" {
886 const io = testing.io;
887 _ = io;
888
889 var ring = IoUring.init(16, 0) catch |err| switch (err) {880 var ring = IoUring.init(16, 0) catch |err| switch (err) {
890 error.SystemOutdated => return error.SkipZigTest,881 error.SystemOutdated => return error.SkipZigTest,
891 error.PermissionDenied => return error.SkipZigTest,882 error.PermissionDenied => return error.SkipZigTest,
...@@ -1568,9 +1559,6 @@ test "remove_buffers" {...@@ -1568,9 +1559,6 @@ test "remove_buffers" {
1568}1559}
15691560
1570test "provide_buffers: accept/connect/send/recv" {1561test "provide_buffers: accept/connect/send/recv" {
1571 const io = testing.io;
1572 _ = io;
1573
1574 var ring = IoUring.init(16, 0) catch |err| switch (err) {1562 var ring = IoUring.init(16, 0) catch |err| switch (err) {
1575 error.SystemOutdated => return error.SkipZigTest,1563 error.SystemOutdated => return error.SkipZigTest,
1576 error.PermissionDenied => return error.SkipZigTest,1564 error.PermissionDenied => return error.SkipZigTest,
...@@ -1777,11 +1765,6 @@ test "accept multishot" {...@@ -1777,11 +1765,6 @@ test "accept multishot" {
1777}1765}
17781766
1779test "accept/connect/send_zc/recv" {1767test "accept/connect/send_zc/recv" {
1780 try skipKernelLessThan(.{ .major = 6, .minor = 0, .patch = 0 });
1781
1782 const io = testing.io;
1783 _ = io;
1784
1785 var ring = IoUring.init(16, 0) catch |err| switch (err) {1768 var ring = IoUring.init(16, 0) catch |err| switch (err) {
1786 error.SystemOutdated => return error.SkipZigTest,1769 error.SystemOutdated => return error.SkipZigTest,
1787 error.PermissionDenied => return error.SkipZigTest,1770 error.PermissionDenied => return error.SkipZigTest,
...@@ -1789,6 +1772,13 @@ test "accept/connect/send_zc/recv" {...@@ -1789,6 +1772,13 @@ test "accept/connect/send_zc/recv" {
1789 };1772 };
1790 defer ring.deinit();1773 defer ring.deinit();
17911774
1775 const probe = ring.get_probe() catch return error.SkipZigTest;
1776 const ops_not_supported = !probe.is_supported(.ACCEPT) or
1777 !probe.is_supported(.CONNECT) or
1778 !probe.is_supported(.SEND_ZC) or
1779 !probe.is_supported(.RECV);
1780 if (ops_not_supported) return error.SkipZigTest;
1781
1792 const socket_test_harness = try createSocketTestHarness(&ring);1782 const socket_test_harness = try createSocketTestHarness(&ring);
1793 defer socket_test_harness.close();1783 defer socket_test_harness.close();
17941784
...@@ -1836,14 +1826,16 @@ test "accept/connect/send_zc/recv" {...@@ -1836,14 +1826,16 @@ test "accept/connect/send_zc/recv" {
1836}1826}
18371827
1838test "accept_direct" {1828test "accept_direct" {
1839 try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 });
1840
1841 var ring = IoUring.init(1, 0) catch |err| switch (err) {1829 var ring = IoUring.init(1, 0) catch |err| switch (err) {
1842 error.SystemOutdated => return error.SkipZigTest,1830 error.SystemOutdated => return error.SkipZigTest,
1843 error.PermissionDenied => return error.SkipZigTest,1831 error.PermissionDenied => return error.SkipZigTest,
1844 else => return err,1832 else => return err,
1845 };1833 };
1846 defer ring.deinit();1834 defer ring.deinit();
1835
1836 const probe = ring.get_probe() catch return error.SkipZigTest;
1837 if (!probe.is_supported(.ACCEPT)) return error.SkipZigTest;
1838
1847 var address: linux.sockaddr.in = .{1839 var address: linux.sockaddr.in = .{
1848 .port = 0,1840 .port = 0,
1849 .addr = @as(*align(1) const u32, @ptrCast(1841 .addr = @as(*align(1) const u32, @ptrCast(
...@@ -1921,8 +1913,6 @@ test "accept_direct" {...@@ -1921,8 +1913,6 @@ test "accept_direct" {
1921}1913}
19221914
1923test "accept_multishot_direct" {1915test "accept_multishot_direct" {
1924 try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 });
1925
1926 var ring = IoUring.init(1, 0) catch |err| switch (err) {1916 var ring = IoUring.init(1, 0) catch |err| switch (err) {
1927 error.SystemOutdated => return error.SkipZigTest,1917 error.SystemOutdated => return error.SkipZigTest,
1928 error.PermissionDenied => return error.SkipZigTest,1918 error.PermissionDenied => return error.SkipZigTest,
...@@ -1930,6 +1920,9 @@ test "accept_multishot_direct" {...@@ -1930,6 +1920,9 @@ test "accept_multishot_direct" {
1930 };1920 };
1931 defer ring.deinit();1921 defer ring.deinit();
19321922
1923 const probe = ring.get_probe() catch return error.SkipZigTest;
1924 if (!probe.is_supported(.ACCEPT)) return error.SkipZigTest;
1925
1933 var address: linux.sockaddr.in = .{1926 var address: linux.sockaddr.in = .{
1934 .port = 0,1927 .port = 0,
1935 .addr = @as(*align(1) const u32, @ptrCast(1928 .addr = @as(*align(1) const u32, @ptrCast(
...@@ -1984,8 +1977,6 @@ test "accept_multishot_direct" {...@@ -1984,8 +1977,6 @@ test "accept_multishot_direct" {
1984}1977}
19851978
1986test "socket" {1979test "socket" {
1987 try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 });
1988
1989 var ring = IoUring.init(1, 0) catch |err| switch (err) {1980 var ring = IoUring.init(1, 0) catch |err| switch (err) {
1990 error.SystemOutdated => return error.SkipZigTest,1981 error.SystemOutdated => return error.SkipZigTest,
1991 error.PermissionDenied => return error.SkipZigTest,1982 error.PermissionDenied => return error.SkipZigTest,
...@@ -1993,6 +1984,9 @@ test "socket" {...@@ -1993,6 +1984,9 @@ test "socket" {
1993 };1984 };
1994 defer ring.deinit();1985 defer ring.deinit();
19951986
1987 const probe = ring.get_probe() catch return error.SkipZigTest;
1988 if (!probe.is_supported(.SOCKET)) return error.SkipZigTest;
1989
1996 // prepare, submit socket operation1990 // prepare, submit socket operation
1997 _ = try ring.socket(0, linux.AF.INET, posix.SOCK.STREAM, 0, 0);1991 _ = try ring.socket(0, linux.AF.INET, posix.SOCK.STREAM, 0, 0);
1998 try testing.expectEqual(@as(u32, 1), try ring.submit());1992 try testing.expectEqual(@as(u32, 1), try ring.submit());
...@@ -2007,8 +2001,6 @@ test "socket" {...@@ -2007,8 +2001,6 @@ test "socket" {
2007}2001}
20082002
2009test "socket_direct/socket_direct_alloc/close_direct" {2003test "socket_direct/socket_direct_alloc/close_direct" {
2010 try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 });
2011
2012 var ring = IoUring.init(2, 0) catch |err| switch (err) {2004 var ring = IoUring.init(2, 0) catch |err| switch (err) {
2013 error.SystemOutdated => return error.SkipZigTest,2005 error.SystemOutdated => return error.SkipZigTest,
2014 error.PermissionDenied => return error.SkipZigTest,2006 error.PermissionDenied => return error.SkipZigTest,
...@@ -2016,6 +2008,9 @@ test "socket_direct/socket_direct_alloc/close_direct" {...@@ -2016,6 +2008,9 @@ test "socket_direct/socket_direct_alloc/close_direct" {
2016 };2008 };
2017 defer ring.deinit();2009 defer ring.deinit();
20182010
2011 const probe = ring.get_probe() catch return error.SkipZigTest;
2012 if (!probe.is_supported(.SOCKET) or !probe.is_supported(.CLOSE)) return error.SkipZigTest;
2013
2019 var registered_fds: [3]linux.fd_t = @splat(-1);2014 var registered_fds: [3]linux.fd_t = @splat(-1);
2020 try ring.register_files(registered_fds[0..]);2015 try ring.register_files(registered_fds[0..]);
20212016
...@@ -2090,8 +2085,6 @@ test "socket_direct/socket_direct_alloc/close_direct" {...@@ -2090,8 +2085,6 @@ test "socket_direct/socket_direct_alloc/close_direct" {
2090}2085}
20912086
2092test "openat_direct/close_direct" {2087test "openat_direct/close_direct" {
2093 try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 });
2094
2095 var ring = IoUring.init(2, 0) catch |err| switch (err) {2088 var ring = IoUring.init(2, 0) catch |err| switch (err) {
2096 error.SystemOutdated => return error.SkipZigTest,2089 error.SystemOutdated => return error.SkipZigTest,
2097 error.PermissionDenied => return error.SkipZigTest,2090 error.PermissionDenied => return error.SkipZigTest,
...@@ -2099,6 +2092,9 @@ test "openat_direct/close_direct" {...@@ -2099,6 +2092,9 @@ test "openat_direct/close_direct" {
2099 };2092 };
2100 defer ring.deinit();2093 defer ring.deinit();
21012094
2095 const probe = ring.get_probe() catch return error.SkipZigTest;
2096 if (!probe.is_supported(.OPENAT) or !probe.is_supported(.CLOSE)) return error.SkipZigTest;
2097
2102 var registered_fds: [3]linux.fd_t = @splat(-1);2098 var registered_fds: [3]linux.fd_t = @splat(-1);
2103 try ring.register_files(registered_fds[0..]);2099 try ring.register_files(registered_fds[0..]);
21042100
...@@ -2141,9 +2137,6 @@ test "openat_direct/close_direct" {...@@ -2141,9 +2137,6 @@ test "openat_direct/close_direct" {
2141}2137}
21422138
2143test "ring mapped buffers recv" {2139test "ring mapped buffers recv" {
2144 const io = testing.io;
2145 _ = io;
2146
2147 var ring = IoUring.init(16, 0) catch |err| switch (err) {2140 var ring = IoUring.init(16, 0) catch |err| switch (err) {
2148 error.SystemOutdated => return error.SkipZigTest,2141 error.SystemOutdated => return error.SkipZigTest,
2149 error.PermissionDenied => return error.SkipZigTest,2142 error.PermissionDenied => return error.SkipZigTest,
...@@ -2231,9 +2224,6 @@ test "ring mapped buffers recv" {...@@ -2231,9 +2224,6 @@ test "ring mapped buffers recv" {
2231}2224}
22322225
2233test "ring mapped buffers multishot recv" {2226test "ring mapped buffers multishot recv" {
2234 const io = testing.io;
2235 _ = io;
2236
2237 var ring = IoUring.init(16, 0) catch |err| switch (err) {2227 var ring = IoUring.init(16, 0) catch |err| switch (err) {
2238 error.SystemOutdated => return error.SkipZigTest,2228 error.SystemOutdated => return error.SkipZigTest,
2239 error.PermissionDenied => return error.SkipZigTest,2229 error.PermissionDenied => return error.SkipZigTest,
...@@ -2665,7 +2655,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {...@@ -2665,7 +2655,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
26652655
2666 // All good2656 // All good
26672657
2668 return SocketTestHarness{2658 return .{
2669 .listener = listener_socket,2659 .listener = listener_socket,
2670 .server = cqe_accept.res,2660 .server = cqe_accept.res,
2671 .client = client,2661 .client = client,
...@@ -2688,27 +2678,6 @@ fn createListenerSocket(address: *linux.sockaddr.in) !posix.socket_t {...@@ -2688,27 +2678,6 @@ fn createListenerSocket(address: *linux.sockaddr.in) !posix.socket_t {
2688 return listener_socket;2678 return listener_socket;
2689}2679}
26902680
2691/// For use in tests. Returns SkipZigTest if kernel version is less than required.
2692inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
2693 var uts: linux.utsname = undefined;
2694 const res = linux.uname(&uts);
2695 switch (linux.errno(res)) {
2696 .SUCCESS => {},
2697 else => |errno| return posix.unexpectedErrno(errno),
2698 }
2699
2700 const release = mem.sliceTo(&uts.release, 0);
2701 // Strips potential extra, as kernel version might not be semver compliant, example "6.8.9-300.fc40.x86_64"
2702 const extra_index = std.mem.findAny(u8, release, "-+");
2703 const stripped = release[0..(extra_index orelse release.len)];
2704 // Make sure the input don't rely on the extra we just stripped
2705 try testing.expect(required.pre == null and required.build == null);
2706
2707 var current = try std.SemanticVersion.parse(stripped);
2708 current.pre = null; // don't check pre field
2709 if (required.order(current) == .gt) return error.SkipZigTest;
2710}
2711
2712fn addrAny(addr: *linux.sockaddr.in) *linux.sockaddr {2681fn addrAny(addr: *linux.sockaddr.in) *linux.sockaddr {
2713 return @ptrCast(addr);2682 return @ptrCast(addr);
2714}2683}