IoUring: Working on Pipe2 flags

Build on the extensive work already done

IoUring: add fixed_fd_install, ftruncate, cmd_discard

Working on IoUring pipe flags

Signed-off-by: Bernard Assan <mega.alpha100@gmail.com>
This commit is contained in:
Bernard Assan 2025-10-23 17:31:00 +00:00
parent be63611c64
commit ac53361721
No known key found for this signature in database
GPG key ID: C2A2C53574321095
2 changed files with 281 additions and 5 deletions

View file

@ -494,6 +494,161 @@ pub const O = switch (native_arch) {
else => @compileError("missing std.os.linux.O constants for this architecture"), else => @compileError("missing std.os.linux.O constants for this architecture"),
}; };
pub const Pipe2 = switch (native_arch) {
.x86_64, .x86, .riscv32, .riscv64, .loongarch64 => packed struct(u32) {
_: u7 = 0,
EXCL: bool = false, //
_9: u3 = 0,
NONBLOCK: bool = false, //
_13: u2 = 0,
DIRECT: bool = false, //
_16: u4 = 0,
CLOEXEC: bool = false, //
_21: u12 = 0,
},
.aarch64, .aarch64_be, .arm, .armeb, .thumb, .thumbeb => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
_2: u4 = 0,
CREAT: bool = false,
EXCL: bool = false, //
NOCTTY: bool = false,
TRUNC: bool = false,
APPEND: bool = false,
NONBLOCK: bool = false, //
DSYNC: bool = false,
ASYNC: bool = false,
DIRECTORY: bool = false,
NOFOLLOW: bool = false,
DIRECT: bool = false, //
LARGEFILE: bool = false,
NOATIME: bool = false,
CLOEXEC: bool = false, //
SYNC: bool = false,
PATH: bool = false,
TMPFILE: bool = false,
_23: u9 = 0,
},
.sparc64 => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
_2: u1 = 0,
APPEND: bool = false,
_4: u2 = 0,
ASYNC: bool = false,
_7: u2 = 0,
CREAT: bool = false,
TRUNC: bool = false,
EXCL: bool = false, //
_12: u1 = 0,
DSYNC: bool = false,
NONBLOCK: bool = false, //
NOCTTY: bool = false,
DIRECTORY: bool = false,
NOFOLLOW: bool = false,
_18: u2 = 0,
DIRECT: bool = false, //
NOATIME: bool = false,
CLOEXEC: bool = false, //
SYNC: bool = false,
PATH: bool = false,
TMPFILE: bool = false,
_27: u6 = 0,
},
.mips, .mipsel, .mips64, .mips64el => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
_2: u1 = 0,
APPEND: bool = false,
DSYNC: bool = false,
_5: u2 = 0,
NONBLOCK: bool = false, //
CREAT: bool = false,
TRUNC: bool = false,
EXCL: bool = false, //
NOCTTY: bool = false,
ASYNC: bool = false,
LARGEFILE: bool = false,
SYNC: bool = false,
DIRECT: bool = false, //
DIRECTORY: bool = false,
NOFOLLOW: bool = false,
NOATIME: bool = false, //
CLOEXEC: bool = false,
_20: u1 = 0,
PATH: bool = false,
TMPFILE: bool = false,
_23: u9 = 0,
},
.powerpc, .powerpcle, .powerpc64, .powerpc64le => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
_2: u4 = 0,
CREAT: bool = false,
EXCL: bool = false, //
NOCTTY: bool = false,
TRUNC: bool = false,
APPEND: bool = false,
NONBLOCK: bool = false, //
DSYNC: bool = false,
ASYNC: bool = false,
DIRECTORY: bool = false,
NOFOLLOW: bool = false,
LARGEFILE: bool = false,
DIRECT: bool = false, //
NOATIME: bool = false,
CLOEXEC: bool = false, //
SYNC: bool = false,
PATH: bool = false,
TMPFILE: bool = false,
_23: u9 = 0,
},
.hexagon, .or1k, .s390x => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
_2: u4 = 0,
CREAT: bool = false,
EXCL: bool = false, //
NOCTTY: bool = false,
TRUNC: bool = false,
APPEND: bool = false,
NONBLOCK: bool = false, //
DSYNC: bool = false,
ASYNC: bool = false,
DIRECT: bool = false, //
LARGEFILE: bool = false,
DIRECTORY: bool = false,
NOFOLLOW: bool = false,
NOATIME: bool = false,
CLOEXEC: bool = false, //
_20: u1 = 0,
PATH: bool = false,
_22: u10 = 0,
// #define O_RSYNC 04010000
// #define O_SYNC 04010000
// #define O_TMPFILE 020200000
// #define O_NDELAY O_NONBLOCK
},
.m68k => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
_2: u4 = 0,
CREAT: bool = false,
EXCL: bool = false, //
NOCTTY: bool = false,
TRUNC: bool = false,
APPEND: bool = false,
NONBLOCK: bool = false, //
DSYNC: bool = false,
ASYNC: bool = false,
DIRECTORY: bool = false,
NOFOLLOW: bool = false,
DIRECT: bool = false, //
LARGEFILE: bool = false,
NOATIME: bool = false,
CLOEXEC: bool = false, //
_20: u1 = 0,
PATH: bool = false,
_22: u10 = 0,
},
else => @compileError("missing std.os.linux.O constants for this architecture"),
};
/// Set by startup code, used by `getauxval`. /// Set by startup code, used by `getauxval`.
pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
@ -745,7 +900,6 @@ pub fn futex_4arg(uaddr: *const u32, futex_op: FUTEX_OP, val: u32, timeout: ?*co
/// most recently woken, nor...) /// most recently woken, nor...)
/// ///
/// Requires at least kernel v5.16. /// Requires at least kernel v5.16.
// TODO: can't we use slices here? and assert `Futex2.waitone_max`
pub fn futex2_waitv( pub fn futex2_waitv(
/// The length of `futexes` slice must not exceed `Futex2.waitone_max` /// The length of `futexes` slice must not exceed `Futex2.waitone_max`
futexes: []const Futex2.WaitOne, futexes: []const Futex2.WaitOne,
@ -3757,8 +3911,11 @@ pub const Futex2 = struct {
/// `Bitset` with all bits set for the FUTEX_xxx_BITSET OPs to request a /// `Bitset` with all bits set for the FUTEX_xxx_BITSET OPs to request a
/// match of any bit. matches FUTEX_BITSET_MATCH_ANY /// match of any bit. matches FUTEX_BITSET_MATCH_ANY
pub const match_any: Bitset = @bitCast(@as(u64, 0x00000000ffffffff)); pub const match_any: Bitset = @bitCast(@as(u64, 0x0000_0000_ffff_ffff));
/// Bitset must not be empty, this is only useful in test /// An empty `Bitset` will not wake any threads because the kernel
/// requires at least one bit to be set in the bitmask to identify
/// which waiters should be woken up. Therefore, no action will be
/// taken if the bitset is zero, this is only useful in test
pub const empty: Bitset = .{}; pub const empty: Bitset = .{};
/// Create from raw u64 value /// Create from raw u64 value

View file

@ -1806,7 +1806,6 @@ pub fn futex_wait(
return sqe; return sqe;
} }
// TODO: ensure flags and Wait in futexv are correct
/// Available since kernel 6.7 /// Available since kernel 6.7
pub fn futex_waitv( pub fn futex_waitv(
self: *IoUring, self: *IoUring,
@ -1821,6 +1820,55 @@ pub fn futex_waitv(
return sqe; return sqe;
} }
pub fn fixed_fd_install(
self: *IoUring,
user_data: u64,
fd: linux.fd_t,
flags: uflags.FixedFd,
) !*Sqe {
const sqe = try self.get_sqe();
sqe.prep_fixed_fd_install(fd, flags);
sqe.user_data = user_data;
return sqe;
}
pub fn ftruncate(
self: *IoUring,
user_data: u64,
fd: linux.fd_t,
offset: u64,
) !*Sqe {
const sqe = try self.get_sqe();
sqe.prep_ftruncate(fd, offset);
sqe.user_data = user_data;
return sqe;
}
pub fn cmd_discard(
self: *IoUring,
user_data: u64,
fd: linux.fd_t,
offset: u64,
nbytes: u64,
) !*Sqe {
const sqe = try self.get_sqe();
sqe.prep_cmd_discard(fd, offset, nbytes);
sqe.user_data = user_data;
return sqe;
}
pub fn pipe(
self: *IoUring,
user_data: u64,
fds: *[2]linux.fd_t,
flags: uflags.,
) !*Sqe {
const sqe = try self.get_sqe();
sqe.prep_pipe(fds, offset, nbytes);
sqe.user_data = user_data;
return sqe;
}
pub fn register_buffers_sparse(self: *IoUring, nr: u32) !void { pub fn register_buffers_sparse(self: *IoUring, nr: u32) !void {
assert(self.fd >= 0); assert(self.fd >= 0);
@ -2332,7 +2380,7 @@ pub const Sqe = extern struct {
/// msg_flags | timeout_flags | accept_flags | cancel_flags | open_flags | /// msg_flags | timeout_flags | accept_flags | cancel_flags | open_flags |
/// statx_flags | fadvise_advice | splice_flags | rename_flags | /// statx_flags | fadvise_advice | splice_flags | rename_flags |
/// unlink_flags | hardlink_flags xattr_flags | msg_ring_flags | /// unlink_flags | hardlink_flags xattr_flags | msg_ring_flags |
/// uring_cmd_flags | waitid_flags | futex_flags install_fd_flags | /// uring_cmd_flags | waitid_flags | futex_flags | install_fd_flags |
/// nop_flags | pipe_flags /// nop_flags | pipe_flags
rw_flags: u32, rw_flags: u32,
/// data to be passed back at completion time /// data to be passed back at completion time
@ -3323,6 +3371,73 @@ pub const Sqe = extern struct {
sqe.rw_flags = flags; sqe.rw_flags = flags;
} }
pub fn prep_fixed_fd_install(
sqe: *Sqe,
fd: linux.fd_t,
flags: uflags.FixedFd,
) void {
sqe.prep_rw(
.fixed_fd_install,
fd,
undefined,
0,
0,
);
sqe.flags = .{ .fixed_file = true };
sqe.rw_flags = @bitCast(flags);
}
pub fn prep_ftruncate(
sqe: *Sqe,
fd: linux.fd_t,
offset: u64,
) void {
sqe.prep_rw(
.ftruncate,
fd,
undefined,
0,
offset,
);
}
pub fn prep_cmd_discard(
sqe: *Sqe,
fd: linux.fd_t,
offset: u64,
nbytes: u64,
) void {
sqe.prep_rw(
.uring_cmd,
fd,
undefined,
0,
0,
);
// sqe.off maps to sqe.cmd_op in liburing
sqe.off = constants.BLOCK_URING_CMD_DISCARD;
sqe.addr = offset;
sqe.addr3 = nbytes;
}
pub fn prep_pipe(
sqe: *Sqe,
fd: linux.fd_t,
offset: u64,
nbytes: u64,
) void {
sqe.prep_rw(
.uring_cmd,
fd,
undefined,
0,
0,
);
// sqe.off maps to sqe.cmd_op in liburing
sqe.off = constants.BLOCK_URING_CMD_DISCARD;
sqe.addr = offset;
sqe.addr3 = nbytes;
}
// TODO: maybe remove unused flag fields? // TODO: maybe remove unused flag fields?
pub fn prep_bind( pub fn prep_bind(
sqe: *Sqe, sqe: *Sqe,
@ -4143,6 +4258,10 @@ pub const ZcrxIfqRegister = extern struct {
// COMMIT: move IoUring constants to Constants // COMMIT: move IoUring constants to Constants
pub const constants = struct { pub const constants = struct {
/// io_uring block file commands, see IORING_OP_URING_CMD.
/// It's a different number space from ioctl(), reuse the block's code 0x12.
/// It is the value of ioctl.IO(0x12, 0) at runtime
pub const BLOCK_URING_CMD_DISCARD = 0x1200;
/// If sqe.file_index (splice_fd_in in Zig Struct) is set to this for /// If sqe.file_index (splice_fd_in in Zig Struct) is set to this for
/// opcodes that instantiate a new an available direct descriptor instead /// opcodes that instantiate a new an available direct descriptor instead
/// of having the application pass one direct descriptor /// of having the application pass one direct descriptor