Replace AT,W,SHUT,SOCK with a packed struct Flag type

Use the new Flag types in IoUring

fix some test

Signed-off-by: Bernard Assan <mega.alpha100@gmail.com>
This commit is contained in:
Bernard Assan 2025-10-01 23:06:56 +00:00
parent 86ed53e28f
commit af2397777a
No known key found for this signature in database
GPG key ID: C2A2C53574321095
2 changed files with 121 additions and 87 deletions

View file

@ -3476,41 +3476,41 @@ pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1; pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2; pub const STDERR_FILENO = 2;
pub const AT = struct { /// matches AT_* and AT_STATX_*
/// Special value used to indicate openat should use the current working directory pub const At = packed struct(u32) {
pub const FDCWD = -100; _reserved: u8 = 0,
/// Do not follow symbolic links /// Do not follow symbolic links
pub const SYMLINK_NOFOLLOW = 0x100; symlink_nofollow: bool = false,
/// Remove directory instead of unlinking file /// Remove directory instead of unlinking file
pub const REMOVEDIR = 0x200; /// Or
/// File handle is needed to compare object identity and may not be usable
/// with open_by_handle_at(2)
removedir_or_handle_fid: bool = false,
/// Follow symbolic links. /// Follow symbolic links.
pub const SYMLINK_FOLLOW = 0x400; symlink_follow: bool = false,
/// Suppress terminal automount traversal /// Suppress terminal automount traversal
pub const NO_AUTOMOUNT = 0x800; no_automount: bool = false,
/// Allow empty relative pathname /// Allow empty relative pathname
pub const EMPTY_PATH = 0x1000; empty_path: bool = false,
/// Force the attributes to be sync'd with the server
/// Type of synchronisation required from statx() statx_force_sync: bool = false,
pub const STATX_SYNC_TYPE = 0x6000; /// Don't sync attributes with the server
statx_dont_sync: bool = false,
/// - Do whatever stat() does
pub const STATX_SYNC_AS_STAT = 0x0000;
/// - Force the attributes to be sync'd with the server
pub const STATX_FORCE_SYNC = 0x2000;
/// - Don't sync attributes with the server
pub const STATX_DONT_SYNC = 0x4000;
/// Apply to the entire subtree /// Apply to the entire subtree
pub const RECURSIVE = 0x8000; recursive: bool = false,
pub const HANDLE_FID = REMOVEDIR; /// Special value used to indicate openat should use the current working directory
pub const fdcwd = -100;
// https://github.com/torvalds/linux/blob/d3479214c05dbd07bc56f8823e7bd8719fcd39a9/tools/perf/trace/beauty/fs_at_flags.sh#L15
/// AT_STATX_SYNC_TYPE is not a bit, its a mask of
/// AT_STATX_SYNC_AS_STAT, AT_STATX_FORCE_SYNC and AT_STATX_DONT_SYNC
/// Type of synchronisation required from statx()
pub const statx_sync_type = 0x6000;
/// Do whatever stat() does
/// This is the default and is very much filesystem-specific
pub const statx_sync_as_stat: At = .{};
}; };
pub const FALLOC = struct { pub const FALLOC = struct {
@ -3656,30 +3656,36 @@ pub const X_OK = 1;
pub const W_OK = 2; pub const W_OK = 2;
pub const R_OK = 4; pub const R_OK = 4;
pub const W = struct { pub const W = packed struct(u32) {
pub const NOHANG = 1; nohang: bool = false,
pub const UNTRACED = 2; untraced_or_stopped: bool = false,
pub const STOPPED = 2; exited: bool = false,
pub const EXITED = 4; continued: bool = false,
pub const CONTINUED = 8; _unused: u20 = 0,
pub const NOWAIT = 0x1000000; nowait: bool = false,
_unused_1: u7 = 0,
pub fn EXITSTATUS(s: u32) u8 { pub fn EXITSTATUS(s: W) u8 {
return @as(u8, @intCast((s & 0xff00) >> 8)); return @intCast((@as(u32, @bitCast(s)) & 0xff00) >> 8);
} }
pub fn TERMSIG(s: u32) u32 {
return s & 0x7f; pub fn TERMSIG(s: W) u32 {
return @as(u32, @bitCast(s)) & 0x7f;
} }
pub fn STOPSIG(s: u32) u32 {
pub fn STOPSIG(s: W) u32 {
return EXITSTATUS(s); return EXITSTATUS(s);
} }
pub fn IFEXITED(s: u32) bool {
pub fn IFEXITED(s: W) bool {
return TERMSIG(s) == 0; return TERMSIG(s) == 0;
} }
pub fn IFSTOPPED(s: u32) bool {
return @as(u16, @truncate(((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00; pub fn IFSTOPPED(s: W) bool {
return @as(u16, @truncate(((@as(u32, @bitCast(s)) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
} }
pub fn IFSIGNALED(s: u32) bool {
pub fn IFSIGNALED(s: W) bool {
return (s & 0xffff) -% 1 < 0xff; return (s & 0xffff) -% 1 < 0xff;
} }
}; };
@ -3885,16 +3891,44 @@ pub const SHUT = struct {
pub const RDWR = 2; pub const RDWR = 2;
}; };
pub const SOCK = struct { /// SOCK_* Socket type and flags
pub const STREAM = if (is_mips) 2 else 1; pub const Sock = packed struct(u32) {
pub const DGRAM = if (is_mips) 1 else 2; type: Type,
pub const RAW = 3; flags: Flags = .{},
pub const RDM = 4;
pub const SEQPACKET = 5; /// matches sock_type in kernel
pub const DCCP = 6; pub const Type = enum(u7) {
pub const PACKET = 10; stream = if (is_mips) 2 else 1,
pub const CLOEXEC = if (is_sparc) 0o20000000 else 0o2000000; dgram = if (is_mips) 1 else 2,
pub const NONBLOCK = if (is_mips) 0o200 else if (is_sparc) 0o40000 else 0o4000; raw = 3,
rdm = 4,
seqpacket = 5,
dccp = 6,
packet = 10,
_,
};
// bit range is (8 - 32] of the u32
/// Flags for socket, socketpair, accept4
pub const Flags = if (is_sparc) packed struct(u25) {
_: u7 = 0, // start from u7 since Type comes before Flags
nonblock: bool = false,
_1: u7 = 0,
cloexec: bool = false,
_2: u9 = 0,
} else if (is_mips) packed struct(u25) {
nonblock: bool = false,
_: u11 = 0,
cloexec: bool = false,
_1: u12 = 0,
} else packed struct(u25) {
_: u4 = 0,
nonblock: bool = false,
_1: u7 = 0,
cloexec: bool = false,
_2: u12 = 0,
};
}; };
pub const TCP = struct { pub const TCP = struct {

View file

@ -492,7 +492,7 @@ pub fn accept(
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*posix.sockaddr, addr: ?*posix.sockaddr,
addrlen: ?*posix.socklen_t, addrlen: ?*posix.socklen_t,
flags: u32, flags: linux.Sock,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_accept(fd, addr, addrlen, flags); sqe.prep_accept(fd, addr, addrlen, flags);
@ -514,7 +514,7 @@ pub fn accept_multishot(
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*posix.sockaddr, addr: ?*posix.sockaddr,
addrlen: ?*posix.socklen_t, addrlen: ?*posix.socklen_t,
flags: u32, flags: linux.Sock,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_multishot_accept(fd, addr, addrlen, flags); sqe.prep_multishot_accept(fd, addr, addrlen, flags);
@ -539,7 +539,7 @@ pub fn accept_direct(
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*posix.sockaddr, addr: ?*posix.sockaddr,
addrlen: ?*posix.socklen_t, addrlen: ?*posix.socklen_t,
flags: u32, flags: linux.Sock,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_accept_direct(fd, addr, addrlen, flags, constants.FILE_INDEX_ALLOC); sqe.prep_accept_direct(fd, addr, addrlen, flags, constants.FILE_INDEX_ALLOC);
@ -555,7 +555,7 @@ pub fn accept_multishot_direct(
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*posix.sockaddr, addr: ?*posix.sockaddr,
addrlen: ?*posix.socklen_t, addrlen: ?*posix.socklen_t,
flags: u32, flags: linux.Sock,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_multishot_accept_direct(fd, addr, addrlen, flags); sqe.prep_multishot_accept_direct(fd, addr, addrlen, flags);
@ -931,7 +931,7 @@ pub fn statx(
user_data: u64, user_data: u64,
fd: linux.fd_t, fd: linux.fd_t,
path: [:0]const u8, path: [:0]const u8,
flags: u32, flags: linux.At,
mask: linux.Statx.Mask, mask: linux.Statx.Mask,
buf: *linux.Statx, buf: *linux.Statx,
) !*Sqe { ) !*Sqe {
@ -969,7 +969,7 @@ pub fn shutdown(
self: *IoUring, self: *IoUring,
user_data: u64, user_data: u64,
sockfd: posix.socket_t, sockfd: posix.socket_t,
how: u32, how: linux.At,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_shutdown(sockfd, how); sqe.prep_shutdown(sockfd, how);
@ -1001,7 +1001,7 @@ pub fn unlinkat(
user_data: u64, user_data: u64,
dir_fd: linux.fd_t, dir_fd: linux.fd_t,
path: [*:0]const u8, path: [*:0]const u8,
flags: u32, flags: linux.At,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_unlinkat(dir_fd, path, flags); sqe.prep_unlinkat(dir_fd, path, flags);
@ -1048,7 +1048,7 @@ pub fn linkat(
old_path: [*:0]const u8, old_path: [*:0]const u8,
new_dir_fd: linux.fd_t, new_dir_fd: linux.fd_t,
new_path: [*:0]const u8, new_path: [*:0]const u8,
flags: u32, flags: linux.At,
) !*Sqe { ) !*Sqe {
const sqe = try self.get_sqe(); const sqe = try self.get_sqe();
sqe.prep_linkat(old_dir_fd, old_path, new_dir_fd, new_path, flags); sqe.prep_linkat(old_dir_fd, old_path, new_dir_fd, new_path, flags);
@ -1329,7 +1329,7 @@ pub fn socket(
self: *IoUring, self: *IoUring,
user_data: u64, user_data: u64,
domain: linux.AF, domain: linux.AF,
socket_type: linux.SOCK, socket_type: linux.Sock,
protocol: u32, protocol: u32,
flags: u32, flags: u32,
) !*Sqe { ) !*Sqe {
@ -2079,7 +2079,7 @@ test "accept/connect/send/recv" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0xeeeeeeee, .user_data = 0xeeeeeeee,
.res = buffer_send.len, .res = buffer_send.len,
.flags = 0, .flags = .{},
}, cqe_send); }, cqe_send);
const cqe_recv = try ring.copy_cqe(); const cqe_recv = try ring.copy_cqe();
@ -2171,7 +2171,7 @@ test "sendmsg/recvmsg" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x11111111, .user_data = 0x11111111,
.res = buffer_send.len, .res = buffer_send.len,
.flags = 0, .flags = .{},
}, cqe_sendmsg); }, cqe_sendmsg);
const cqe_recvmsg = try ring.copy_cqe(); const cqe_recvmsg = try ring.copy_cqe();
@ -2306,7 +2306,7 @@ test "timeout_remove" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x99999999, .user_data = 0x99999999,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe); }, cqe);
} }
} }
@ -2457,7 +2457,7 @@ test "statx" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0xaaaaaaaa, .user_data = 0xaaaaaaaa,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe); }, cqe);
try testing.expect(buf.mask & linux.STATX_SIZE == linux.STATX_SIZE); try testing.expect(buf.mask & linux.STATX_SIZE == linux.STATX_SIZE);
@ -2504,13 +2504,13 @@ test "accept/connect/recv/cancel" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0xffffffff, .user_data = 0xffffffff,
.res = -@as(i32, @intFromEnum(linux.E.CANCELED)), .res = -@as(i32, @intFromEnum(linux.E.CANCELED)),
.flags = 0, .flags = .{},
}, cqe_recv); }, cqe_recv);
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x99999999, .user_data = 0x99999999,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe_cancel); }, cqe_cancel);
} }
@ -2645,7 +2645,7 @@ test "shutdown" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x445445445, .user_data = 0x445445445,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe); }, cqe);
} }
@ -2715,7 +2715,7 @@ test "renameat" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x12121212, .user_data = 0x12121212,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe); }, cqe);
// Validate that the old file doesn't exist anymore // Validate that the old file doesn't exist anymore
@ -2768,7 +2768,7 @@ test "unlinkat" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x12121212, .user_data = 0x12121212,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe); }, cqe);
// Validate that the file doesn't exist anymore // Validate that the file doesn't exist anymore
@ -2917,7 +2917,7 @@ test "linkat" {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0x12121212, .user_data = 0x12121212,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe); }, cqe);
// Validate the second file // Validate the second file
@ -3365,7 +3365,7 @@ fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
try testing.expectEqual(Cqe{ try testing.expectEqual(Cqe{
.user_data = 0xcccccccc, .user_data = 0xcccccccc,
.res = 0, .res = 0,
.flags = 0, .flags = .{},
}, cqe_connect); }, cqe_connect);
// All good // All good
@ -3811,7 +3811,7 @@ test "waitid" {
} }
var siginfo: posix.siginfo_t = undefined; var siginfo: posix.siginfo_t = undefined;
_ = try ring.waitid(0, .PID, pid, &siginfo, posix.W.EXITED, 0); _ = try ring.waitid(0, .PID, pid, &siginfo, .{ .exited = true }, 0);
try testing.expectEqual(1, try ring.submit()); try testing.expectEqual(1, try ring.submit());
@ -3884,7 +3884,7 @@ test BufferGroup {
try testing.expectEqual(1, submitted); try testing.expectEqual(1, submitted);
const cqe_send = try ring.copy_cqe(); const cqe_send = try ring.copy_cqe();
if (cqe_send.err() == .INVAL) return error.SkipZigTest; if (cqe_send.err() == .INVAL) return error.SkipZigTest;
try testing.expectEqual(Cqe{ .user_data = 1, .res = data.len, .flags = 0 }, cqe_send); try testing.expectEqual(Cqe{ .user_data = 1, .res = data.len, .flags = .{} }, cqe_send);
} }
// Server uses buffer group receive // Server uses buffer group receive
@ -3954,7 +3954,7 @@ test "ring mapped buffers recv" {
try testing.expectEqual(@as(u32, 1), try ring.submit()); try testing.expectEqual(@as(u32, 1), try ring.submit());
const cqe_send = try ring.copy_cqe(); const cqe_send = try ring.copy_cqe();
if (cqe_send.err() == .INVAL) return error.SkipZigTest; if (cqe_send.err() == .INVAL) return error.SkipZigTest;
try testing.expectEqual(Cqe{ .user_data = user_data, .res = data.len, .flags = 0 }, cqe_send); try testing.expectEqual(Cqe{ .user_data = user_data, .res = data.len, .flags = .{} }, cqe_send);
} }
var pos: usize = 0; var pos: usize = 0;
@ -4043,7 +4043,7 @@ test "ring mapped buffers multishot recv" {
try testing.expectEqual(@as(u32, 1), try ring.submit()); try testing.expectEqual(@as(u32, 1), try ring.submit());
const cqe_send = try ring.copy_cqe(); const cqe_send = try ring.copy_cqe();
if (cqe_send.err() == .INVAL) return error.SkipZigTest; if (cqe_send.err() == .INVAL) return error.SkipZigTest;
try testing.expectEqual(Cqe{ .user_data = user_data, .res = data.len, .flags = 0 }, cqe_send); try testing.expectEqual(Cqe{ .user_data = user_data, .res = data.len, .flags = .{} }, cqe_send);
} }
// start multishot recv // start multishot recv
@ -4251,7 +4251,7 @@ test "bind/listen/connect" {
const listen_fd = brk: { const listen_fd = brk: {
// Create socket // Create socket
_ = try ring.socket(1, addr.family, linux.SOCK.STREAM | linux.SOCK.CLOEXEC, proto, 0); _ = try ring.socket(1, addr.any.family, .{ .type = .stream, .flags = .{ .cloexec = true } }, proto, 0);
try testing.expectEqual(1, try ring.submit()); try testing.expectEqual(1, try ring.submit());
var cqe = try ring.copy_cqe(); var cqe = try ring.copy_cqe();
try testing.expectEqual(1, cqe.user_data); try testing.expectEqual(1, cqe.user_data);
@ -4653,7 +4653,7 @@ pub const Sqe = extern struct {
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*linux.sockaddr, addr: ?*linux.sockaddr,
addrlen: ?*linux.socklen_t, addrlen: ?*linux.socklen_t,
flags: linux.SOCK, flags: linux.Sock,
) void { ) void {
// `addr` holds a pointer to `sockaddr`, and `addr2` holds a pointer to socklen_t`. // `addr` holds a pointer to `sockaddr`, and `addr2` holds a pointer to socklen_t`.
// `addr2` maps to `sqe.off` (u64) instead of `sqe.len` (which is only a u32). // `addr2` maps to `sqe.off` (u64) instead of `sqe.len` (which is only a u32).
@ -4667,7 +4667,7 @@ pub const Sqe = extern struct {
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*linux.sockaddr, addr: ?*linux.sockaddr,
addrlen: ?*linux.socklen_t, addrlen: ?*linux.socklen_t,
flags: linux.SOCK, flags: linux.Sock,
file_index: u32, file_index: u32,
) void { ) void {
prep_accept(sqe, fd, addr, addrlen, flags); prep_accept(sqe, fd, addr, addrlen, flags);
@ -4679,7 +4679,7 @@ pub const Sqe = extern struct {
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*linux.sockaddr, addr: ?*linux.sockaddr,
addrlen: ?*linux.socklen_t, addrlen: ?*linux.socklen_t,
flags: linux.SOCK, flags: linux.Sock,
) void { ) void {
prep_accept(sqe, fd, addr, addrlen, flags); prep_accept(sqe, fd, addr, addrlen, flags);
sqe.ioprio = .{ .accept = .{ .MULTISHOT = true } }; sqe.ioprio = .{ .accept = .{ .MULTISHOT = true } };
@ -4691,7 +4691,7 @@ pub const Sqe = extern struct {
fd: linux.fd_t, fd: linux.fd_t,
addr: ?*linux.sockaddr, addr: ?*linux.sockaddr,
addrlen: ?*linux.socklen_t, addrlen: ?*linux.socklen_t,
flags: linux.SOCK, flags: linux.Sock,
) void { ) void {
prep_multishot_accept(sqe, fd, addr, addrlen, flags); prep_multishot_accept(sqe, fd, addr, addrlen, flags);
set_target_fixed_file(sqe, constants.FILE_INDEX_ALLOC); set_target_fixed_file(sqe, constants.FILE_INDEX_ALLOC);
@ -4994,9 +4994,9 @@ pub const Sqe = extern struct {
pub fn prep_shutdown( pub fn prep_shutdown(
sqe: *Sqe, sqe: *Sqe,
sockfd: linux.socket_t, sockfd: linux.socket_t,
how: linux.SHUT, how: linux.Shut,
) void { ) void {
sqe.prep_rw(.SHUTDOWN, sockfd, 0, how, 0); sqe.prep_rw(.SHUTDOWN, sockfd, 0, @intFromEnum(how), 0);
} }
pub fn prep_renameat( pub fn prep_renameat(
@ -5015,7 +5015,7 @@ pub const Sqe = extern struct {
@intFromPtr(new_path), @intFromPtr(new_path),
); );
sqe.len = @bitCast(new_dir_fd); sqe.len = @bitCast(new_dir_fd);
sqe.rw_flags = flags; sqe.rw_flags = @bitCast(flags);
} }
pub fn prep_unlinkat( pub fn prep_unlinkat(
@ -5058,7 +5058,7 @@ pub const Sqe = extern struct {
old_path: [*:0]const u8, old_path: [*:0]const u8,
new_dir_fd: linux.fd_t, new_dir_fd: linux.fd_t,
new_path: [*:0]const u8, new_path: [*:0]const u8,
flags: linux.AT, // only AT_EMPTY_PATH, AT_SYMLINK_FOLLOW flags: linux.At, // only AT_EMPTY_PATH, AT_SYMLINK_FOLLOW
) void { ) void {
sqe.prep_rw( sqe.prep_rw(
.LINKAT, .LINKAT,