Skip to content

std: linux uring kernel interfaces #2525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions std/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
143 changes: 143 additions & 0 deletions std/os/bits/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
20 changes: 20 additions & 0 deletions std/os/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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")) {
Expand Down Expand Up @@ -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");
Expand Down
6 changes: 4 additions & 2 deletions std/testing.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down