diff --git a/src/ourio.zig b/src/ourio.zig index 05fdc63..f4d8b65 100644 --- a/src/ourio.zig +++ b/src/ourio.zig @@ -494,6 +494,7 @@ pub const Op = enum { connect, statx, readv, + open, /// userfd is meant to send file descriptors between Ring instances (using msgRing) userfd, @@ -551,6 +552,11 @@ pub const Request = union(Op) { fd: posix.fd_t, vecs: []const posix.iovec, }, + open: struct { + path: [:0]const u8, + flags: posix.O, + mode: posix.mode_t, + }, userfd, usermsg, @@ -573,6 +579,7 @@ pub const Result = union(Op) { connect: ResultError!void, statx: ResultError!*Statx, readv: ResultError!usize, + open: ResultError!posix.fd_t, userfd: anyerror!posix.fd_t, usermsg: u16, diff --git a/src/ourio/Kqueue.zig b/src/ourio/Kqueue.zig index 36a1e07..adce939 100644 --- a/src/ourio/Kqueue.zig +++ b/src/ourio/Kqueue.zig @@ -332,6 +332,14 @@ fn prepTask(self: *Kqueue, task: *io.Task) !void { self.synchronous_queue.push(task); }, + .open => |req| { + self.synchronous_queue.push(task); + + if (posix.open(req.path, req.flags, req.mode)) |fd| { + task.result = .{ .open = fd }; + } else |_| task.result = .{ .open = error.Unexpected }; + }, + .poll => |req| { self.in_flight.push(task); if (req.mask & posix.POLL.IN != 0) { @@ -440,6 +448,7 @@ fn cancelTask(self: *Kqueue, task: *io.Task) !void { .close, .msg_ring, .noop, + .open, .socket, .statx, .userfd, @@ -686,6 +695,7 @@ fn handleSynchronousCompletion( .close, .msg_ring, .noop, + .open, .socket, .statx, .userfd, @@ -719,6 +729,7 @@ fn handleSynchronousCompletion( .deadline => .{ .deadline = error.Canceled }, .msg_ring => .{ .msg_ring = error.Canceled }, .noop => unreachable, + .open => .{ .open = error.Canceled }, .poll => .{ .poll = error.Canceled }, .readv => .{ .readv = error.Canceled }, .recv => .{ .recv = error.Canceled }, @@ -761,6 +772,7 @@ fn handleCompletion( .deadline, .msg_ring, .noop, + .open, .socket, .statx, .timer, diff --git a/src/ourio/Mock.zig b/src/ourio/Mock.zig index 0eb0f5a..71d5a79 100644 --- a/src/ourio/Mock.zig +++ b/src/ourio/Mock.zig @@ -18,6 +18,7 @@ connect_cb: ?*const fn (*io.Task) io.Result = null, deadline_cb: ?*const fn (*io.Task) io.Result = null, msg_ring_cb: ?*const fn (*io.Task) io.Result = null, noop_cb: ?*const fn (*io.Task) io.Result = null, +open_cb: ?*const fn (*io.Task) io.Result = null, poll_cb: ?*const fn (*io.Task) io.Result = null, readv_cb: ?*const fn (*io.Task) io.Result = null, recv_cb: ?*const fn (*io.Task) io.Result = null, @@ -69,6 +70,7 @@ pub fn submit(self: *Mock, queue: *Queue(io.Task, .in_flight)) !void { .deadline => if (self.deadline_cb) |cb| cb(task) else return error.NoMockCallback, .msg_ring => if (self.msg_ring_cb) |cb| cb(task) else return error.NoMockCallback, .noop => if (self.noop_cb) |cb| cb(task) else return error.NoMockCallback, + .open => if (self.open_cb) |cb| cb(task) else return error.NoMockCallback, .poll => if (self.poll_cb) |cb| cb(task) else return error.NoMockCallback, .readv => if (self.readv_cb) |cb| cb(task) else return error.NoMockCallback, .recv => if (self.recv_cb) |cb| cb(task) else return error.NoMockCallback, diff --git a/src/ourio/Uring.zig b/src/ourio/Uring.zig index c2f1649..351c131 100644 --- a/src/ourio/Uring.zig +++ b/src/ourio/Uring.zig @@ -232,6 +232,13 @@ fn prepTask(self: *Uring, task: *io.Task) void { self.prepDeadline(task, sqe); }, + .open => |req| { + const sqe = self.getSqe(); + sqe.prep_openat(posix.AT.FDCWD, req.path, req.flags, req.mode); + sqe.user_data = @intFromPtr(task); + self.prepDeadline(task, sqe); + }, + // user* is only sent internally between rings and higher level wrappers .userfd, .usermsg, .userptr => unreachable, } @@ -368,6 +375,13 @@ pub fn reapCompletions(self: *Uring, rt: *io.Ring) anyerror!void { else => |e| unexpectedError(e), } }, + .open => .{ .open = switch (cqeToE(cqe.res)) { + .SUCCESS => @intCast(cqe.res), + .INVAL => io.ResultError.Invalid, + .CANCELED => io.ResultError.Canceled, + else => |e| unexpectedError(e), + } }, + .usermsg => .{ .usermsg = @intCast(cqe.res) }, // userfd should never reach the runtime