Commit d6b0686b05

Andrew Kelley <andrew@ziglang.org>
2025-10-22 19:52:25
std.Io: add Kqueue implementation
1 parent a5c309a
Changed files (3)
lib/std/Io/IoUring.zig
@@ -1,9 +1,10 @@
-const std = @import("../std.zig");
+const EventLoop = @This();
 const builtin = @import("builtin");
+
+const std = @import("../std.zig");
+const Io = std.Io;
 const assert = std.debug.assert;
 const Allocator = std.mem.Allocator;
-const Io = std.Io;
-const EventLoop = @This();
 const Alignment = std.mem.Alignment;
 const IoUring = std.os.linux.IoUring;
 
lib/std/Io/Kqueue.zig
@@ -0,0 +1,535 @@
+const Kqueue = @This();
+const builtin = @import("builtin");
+
+const std = @import("../std.zig");
+const Io = std.Io;
+const Dir = std.Io.Dir;
+const File = std.Io.File;
+const net = std.Io.net;
+const assert = std.debug.assert;
+const Allocator = std.mem.Allocator;
+const Alignment = std.mem.Alignment;
+
+/// Must be a thread-safe allocator.
+gpa: Allocator,
+
+pub fn init(gpa: Allocator) Kqueue {
+    return .{
+        .gpa = gpa,
+    };
+}
+
+pub fn deinit(k: *Kqueue) void {
+    k.* = undefined;
+}
+
+pub fn io(k: *Kqueue) Io {
+    return .{
+        .userdata = k,
+        .vtable = &.{
+            .async = async,
+            .concurrent = concurrent,
+            .await = await,
+            .cancel = cancel,
+            .cancelRequested = cancelRequested,
+            .select = select,
+
+            .groupAsync = groupAsync,
+            .groupWait = groupWait,
+            .groupWaitUncancelable = groupWaitUncancelable,
+            .groupCancel = groupCancel,
+
+            .mutexLock = mutexLock,
+            .mutexLockUncancelable = mutexLockUncancelable,
+            .mutexUnlock = mutexUnlock,
+
+            .conditionWait = conditionWait,
+            .conditionWaitUncancelable = conditionWaitUncancelable,
+            .conditionWake = conditionWake,
+
+            .dirMake = dirMake,
+            .dirMakePath = dirMakePath,
+            .dirMakeOpenPath = dirMakeOpenPath,
+            .dirStat = dirStat,
+            .dirStatPath = dirStatPath,
+
+            .fileStat = fileStat,
+            .dirAccess = dirAccess,
+            .dirCreateFile = dirCreateFile,
+            .dirOpenFile = dirOpenFile,
+            .dirOpenDir = dirOpenDir,
+            .dirClose = dirClose,
+            .fileClose = fileClose,
+            .fileWriteStreaming = fileWriteStreaming,
+            .fileWritePositional = fileWritePositional,
+            .fileReadStreaming = fileReadStreaming,
+            .fileReadPositional = fileReadPositional,
+            .fileSeekBy = fileSeekBy,
+            .fileSeekTo = fileSeekTo,
+            .openSelfExe = openSelfExe,
+
+            .now = now,
+            .sleep = sleep,
+
+            .netListenIp = netListenIp,
+            .netListenUnix = netListenUnix,
+            .netAccept = netAccept,
+            .netBindIp = netBindIp,
+            .netConnectIp = netConnectIp,
+            .netConnectUnix = netConnectUnix,
+            .netClose = netClose,
+            .netRead = netRead,
+            .netWrite = netWrite,
+            .netSend = netSend,
+            .netReceive = netReceive,
+            .netInterfaceNameResolve = netInterfaceNameResolve,
+            .netInterfaceName = netInterfaceName,
+            .netLookup = netLookup,
+        },
+    };
+}
+
+fn async(
+    userdata: ?*anyopaque,
+    result: []u8,
+    result_alignment: std.mem.Alignment,
+    context: []const u8,
+    context_alignment: std.mem.Alignment,
+    start: *const fn (context: *const anyopaque, result: *anyopaque) void,
+) ?*Io.AnyFuture {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = result;
+    _ = result_alignment;
+    _ = context;
+    _ = context_alignment;
+    _ = start;
+    @panic("TODO");
+}
+
+fn concurrent(
+    userdata: ?*anyopaque,
+    result_len: usize,
+    result_alignment: std.mem.Alignment,
+    context: []const u8,
+    context_alignment: std.mem.Alignment,
+    start: *const fn (context: *const anyopaque, result: *anyopaque) void,
+) error{OutOfMemory}!*Io.AnyFuture {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = result_len;
+    _ = result_alignment;
+    _ = context;
+    _ = context_alignment;
+    _ = start;
+    @panic("TODO");
+}
+
+fn await(
+    userdata: ?*anyopaque,
+    any_future: *Io.AnyFuture,
+    result: []u8,
+    result_alignment: std.mem.Alignment,
+) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = any_future;
+    _ = result;
+    _ = result_alignment;
+    @panic("TODO");
+}
+
+fn cancel(
+    userdata: ?*anyopaque,
+    any_future: *Io.AnyFuture,
+    result: []u8,
+    result_alignment: std.mem.Alignment,
+) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = any_future;
+    _ = result;
+    _ = result_alignment;
+    @panic("TODO");
+}
+
+fn cancelRequested(userdata: ?*anyopaque) bool {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    @panic("TODO");
+}
+
+fn groupAsync(
+    userdata: ?*anyopaque,
+    group: *Io.Group,
+    context: []const u8,
+    context_alignment: std.mem.Alignment,
+    start: *const fn (*Io.Group, context: *const anyopaque) void,
+) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = group;
+    _ = context;
+    _ = context_alignment;
+    _ = start;
+    @panic("TODO");
+}
+
+fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) Io.Cancelable!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = group;
+    _ = token;
+    @panic("TODO");
+}
+
+fn groupWaitUncancelable(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = group;
+    _ = token;
+    @panic("TODO");
+}
+
+fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = group;
+    _ = token;
+    @panic("TODO");
+}
+
+fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) Io.Cancelable!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = futures;
+    @panic("TODO");
+}
+
+fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = prev_state;
+    _ = mutex;
+    @panic("TODO");
+}
+fn mutexLockUncancelable(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = prev_state;
+    _ = mutex;
+    @panic("TODO");
+}
+fn mutexUnlock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = prev_state;
+    _ = mutex;
+    @panic("TODO");
+}
+
+fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = cond;
+    _ = mutex;
+    @panic("TODO");
+}
+fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = cond;
+    _ = mutex;
+    @panic("TODO");
+}
+fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition.Wake) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = cond;
+    _ = wake;
+    @panic("TODO");
+}
+
+fn dirMake(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = mode;
+    @panic("TODO");
+}
+fn dirMakePath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = mode;
+    @panic("TODO");
+}
+fn dirMakeOpenPath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.OpenOptions) Dir.MakeOpenPathError!Dir {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = options;
+    @panic("TODO");
+}
+fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    @panic("TODO");
+}
+fn dirStatPath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.StatPathOptions) Dir.StatPathError!File.Stat {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = options;
+    @panic("TODO");
+}
+fn dirAccess(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.AccessOptions) Dir.AccessError!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = options;
+    @panic("TODO");
+}
+fn dirCreateFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = flags;
+    @panic("TODO");
+}
+fn dirOpenFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = flags;
+    @panic("TODO");
+}
+fn dirOpenDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.OpenOptions) Dir.OpenError!Dir {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    _ = sub_path;
+    _ = options;
+    @panic("TODO");
+}
+fn dirClose(userdata: ?*anyopaque, dir: Dir) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dir;
+    @panic("TODO");
+}
+fn fileStat(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    @panic("TODO");
+}
+fn fileClose(userdata: ?*anyopaque, file: File) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    @panic("TODO");
+}
+fn fileWriteStreaming(userdata: ?*anyopaque, file: File, buffer: [][]const u8) File.WriteStreamingError!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    _ = buffer;
+    @panic("TODO");
+}
+fn fileWritePositional(userdata: ?*anyopaque, file: File, buffer: [][]const u8, offset: u64) File.WritePositionalError!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    _ = buffer;
+    _ = offset;
+    @panic("TODO");
+}
+fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: [][]u8) File.ReadStreamingError!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    _ = data;
+    @panic("TODO");
+}
+fn fileReadPositional(userdata: ?*anyopaque, file: File, data: [][]u8, offset: u64) File.ReadPositionalError!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    _ = data;
+    _ = offset;
+    @panic("TODO");
+}
+fn fileSeekBy(userdata: ?*anyopaque, file: File, relative_offset: i64) File.SeekError!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    _ = relative_offset;
+    @panic("TODO");
+}
+fn fileSeekTo(userdata: ?*anyopaque, file: File, absolute_offset: u64) File.SeekError!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    _ = absolute_offset;
+    @panic("TODO");
+}
+fn openSelfExe(userdata: ?*anyopaque, file: File.OpenFlags) File.OpenSelfExeError!File {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = file;
+    @panic("TODO");
+}
+
+fn now(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = clock;
+    @panic("TODO");
+}
+fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = timeout;
+    @panic("TODO");
+}
+
+fn netListenIp(
+    userdata: ?*anyopaque,
+    address: net.IpAddress,
+    options: net.IpAddress.ListenOptions,
+) net.IpAddress.ListenError!net.Server {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = address;
+    _ = options;
+    @panic("TODO");
+}
+fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle) net.Server.AcceptError!net.Stream {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = server;
+    @panic("TODO");
+}
+fn netBindIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = address;
+    _ = options;
+    @panic("TODO");
+}
+fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = address;
+    _ = options;
+    @panic("TODO");
+}
+fn netListenUnix(
+    userdata: ?*anyopaque,
+    unix_address: *const net.UnixAddress,
+    options: net.UnixAddress.ListenOptions,
+) net.UnixAddress.ListenError!net.Socket.Handle {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = unix_address;
+    _ = options;
+    @panic("TODO");
+}
+fn netConnectUnix(
+    userdata: ?*anyopaque,
+    unix_address: *const net.UnixAddress,
+) net.UnixAddress.ConnectError!net.Socket.Handle {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = unix_address;
+    @panic("TODO");
+}
+fn netSend(
+    userdata: ?*anyopaque,
+    handle: net.Socket.Handle,
+    outgoing_messages: []net.OutgoingMessage,
+    flags: net.SendFlags,
+) struct { ?net.Socket.SendError, usize } {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = handle;
+    _ = outgoing_messages;
+    _ = flags;
+    @panic("TODO");
+}
+fn netReceive(
+    userdata: ?*anyopaque,
+    handle: net.Socket.Handle,
+    message_buffer: []net.IncomingMessage,
+    data_buffer: []u8,
+    flags: net.ReceiveFlags,
+    timeout: Io.Timeout,
+) struct { ?net.Socket.ReceiveTimeoutError, usize } {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = handle;
+    _ = message_buffer;
+    _ = data_buffer;
+    _ = flags;
+    _ = timeout;
+    @panic("TODO");
+}
+fn netRead(userdata: ?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = src;
+    _ = data;
+    @panic("TODO");
+}
+fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = dest;
+    _ = header;
+    _ = data;
+    _ = splat;
+    @panic("TODO");
+}
+fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = handle;
+    @panic("TODO");
+}
+fn netInterfaceNameResolve(
+    userdata: ?*anyopaque,
+    name: *const net.Interface.Name,
+) net.Interface.Name.ResolveError!net.Interface {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = name;
+    @panic("TODO");
+}
+fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = interface;
+    @panic("TODO");
+}
+fn netLookup(
+    userdata: ?*anyopaque,
+    host_name: net.HostName,
+    result: *Io.Queue(net.HostName.LookupResult),
+    options: net.HostName.LookupOptions,
+) void {
+    const k: *Kqueue = @ptrCast(@alignCast(userdata));
+    _ = k;
+    _ = host_name;
+    _ = result;
+    _ = options;
+    @panic("TODO");
+}
lib/std/Io.zig
@@ -559,6 +559,7 @@ const Io = @This();
 
 pub const Evented = switch (builtin.os.tag) {
     .linux => @import("Io/IoUring.zig"),
+    .dragonfly, .freebsd, .netbsd, .openbsd, .macos, .ios, .tvos, .visionos, .watchos => @import("Io/Kqueue.zig"),
     else => void,
 };
 pub const Threaded = @import("Io/Threaded.zig");