diff --git a/std/math.zig b/std/math.zig index 765df6280cd5..7464a9fc9748 100644 --- a/std/math.zig +++ b/std/math.zig @@ -680,6 +680,11 @@ pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alig return @alignCast(alignment, ptr); } +pub fn isPowerOfTwo(v: var) bool { + assert(v != 0); + return (v & (v - 1)) == 0; +} + pub fn floorPowerOfTwo(comptime T: type, value: T) T { var x = value; diff --git a/std/os/bits/linux.zig b/std/os/bits/linux.zig index 8b323fa5720f..0b355cd8198c 100644 --- a/std/os/bits/linux.zig +++ b/std/os/bits/linux.zig @@ -119,6 +119,23 @@ pub const O_RDONLY = 0o0; pub const O_WRONLY = 0o1; pub const O_RDWR = 0o2; +pub const kernel_rwf = u32; + +/// high priority request, poll if possible +pub const RWF_HIPRI = kernel_rwf(0x00000001); + +/// per-IO O_DSYNC +pub const RWF_DSYNC = kernel_rwf(0x00000002); + +/// per-IO O_SYNC +pub const RWF_SYNC = kernel_rwf(0x00000004); + +/// per-IO, return -EAGAIN if operation would block +pub const RWF_NOWAIT = kernel_rwf(0x00000008); + +/// per-IO O_APPEND +pub const RWF_APPEND = kernel_rwf(0x00000010); + pub const SEEK_SET = 0; pub const SEEK_CUR = 1; pub const SEEK_END = 2; @@ -950,3 +967,129 @@ pub const stack_t = extern struct { ss_flags: i32, ss_size: isize, }; + +pub const io_uring_params = extern struct { + sq_entries: u32, + cq_entries: u32, + flags: u32, + sq_thread_cpu: u32, + sq_thread_idle: u32, + resv: [5]u32, + sq_off: io_sqring_offsets, + cq_off: io_cqring_offsets, +}; + +// io_uring_params.flags + +/// io_context is polled +pub const IORING_SETUP_IOPOLL = (1 << 0); + +/// SQ poll thread +pub const IORING_SETUP_SQPOLL = (1 << 1); + +/// sq_thread_cpu is valid +pub const IORING_SETUP_SQ_AFF = (1 << 2); + +pub const io_sqring_offsets = extern struct { + /// offset of ring head + head: u32, + + /// offset of ring tail + tail: u32, + + /// ring mask value + ring_mask: u32, + + /// entries in ring + ring_entries: u32, + + /// ring flags + flags: u32, + + /// number of sqes not submitted + dropped: u32, + + /// sqe index array + array: u32, + + resv1: u32, + resv2: u64, +}; + +// io_sqring_offsets.flags + +/// needs io_uring_enter wakeup +pub const IORING_SQ_NEED_WAKEUP = 1 << 0; + +pub const io_cqring_offsets = extern struct { + head: u32, + tail: u32, + ring_mask: u32, + ring_entries: u32, + overflow: u32, + cqes: u32, + resv: [2]u64, +}; + +pub const io_uring_sqe = extern struct { + opcode: u8, + flags: u8, + ioprio: u16, + fd: i32, + off: u64, + addr: u64, + len: u32, + pub const union1 = extern union { + rw_flags: kernel_rwf, + fsync_flags: u32, + poll_event: u16, + }; + union1: union1, + user_data: u64, + pub const union2 = extern union { + buf_index: u16, + __pad2: [3]u64, + }; + union2: union2, +}; + +// io_uring_sqe.flags + +/// use fixed fileset +pub const IOSQE_FIXED_FILE = (1 << 0); + +pub const IORING_OP_NOP = 0; +pub const IORING_OP_READV = 1; +pub const IORING_OP_WRITEV = 2; +pub const IORING_OP_FSYNC = 3; +pub const IORING_OP_READ_FIXED = 4; +pub const IORING_OP_WRITE_FIXED = 5; +pub const IORING_OP_POLL_ADD = 6; +pub const IORING_OP_POLL_REMOVE = 7; + +// io_uring_sqe.fsync_flags +pub const IORING_FSYNC_DATASYNC = (1 << 0); + +// IO completion data structure (Completion Queue Entry) +pub const io_uring_cqe = extern struct { + /// io_uring_sqe.data submission passed back + user_data: u64, + + /// result code for this event + res: i32, + flags: u32, +}; + +pub const IORING_OFF_SQ_RING = 0; +pub const IORING_OFF_CQ_RING = 0x8000000; +pub const IORING_OFF_SQES = 0x10000000; + +// io_uring_enter flags +pub const IORING_ENTER_GETEVENTS = (1 << 0); +pub const IORING_ENTER_SQ_WAKEUP = (1 << 1); + +// io_uring_register opcodes and arguments +pub const IORING_REGISTER_BUFFERS = 0; +pub const IORING_UNREGISTER_BUFFERS = 1; +pub const IORING_REGISTER_FILES = 2; +pub const IORING_UNREGISTER_FILES = 3; diff --git a/std/os/linux.zig b/std/os/linux.zig index 61a13ff164ec..74e1c4844446 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -189,6 +189,10 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize { return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } +pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: u64, flags: kernel_rwf) usize { + return syscall5(SYS_preadv2, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset, flags); +} + pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize { return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); } @@ -201,6 +205,10 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } +pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64, flags: kernel_rwf) usize { + return syscall5(SYS_pwritev2, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset, flags); +} + // TODO https://github.com/ziglang/zig/issues/265 pub fn rmdir(path: [*]const u8) usize { if (@hasDecl(@This(), "SYS_rmdir")) { @@ -887,6 +895,18 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf return last_r; } +pub fn io_uring_setup(entries: u32, p: *io_uring_params) usize { + return syscall2(SYS_io_uring_setup, entries, @ptrToInt(p)); +} + +pub fn io_uring_enter(fd: i32, to_submit: u32, min_complete: u32, flags: u32, sig: ?*sigset_t) usize { + return syscall6(SYS_io_uring_enter, @bitCast(usize, isize(fd)), to_submit, min_complete, flags, @ptrToInt(sig), NSIG / 8); +} + +pub fn io_uring_register(fd: i32, opcode: u32, arg: ?*const c_void, nr_args: u32) usize { + return syscall4(SYS_io_uring_register, @bitCast(usize, isize(fd)), opcode, @ptrToInt(arg), nr_args); +} + test "" { if (is_the_target) { _ = @import("linux/test.zig"); diff --git a/std/testing.zig b/std/testing.zig index f4b10a3776e8..4568e024e2c3 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -78,8 +78,10 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual), - TypeId.Struct => { - @compileError("TODO implement testing.expectEqual for structs"); + TypeId.Struct => |structType| { + inline for (structType.fields) |field| { + expectEqual(@field(expected, field.name), @field(actual, field.name)); + } }, TypeId.Union => |union_info| {