std.Io: add Kqueue implementation

This commit is contained in:
Andrew Kelley 2025-10-22 10:52:25 -07:00
parent a5c309a692
commit d6b0686b05
3 changed files with 540 additions and 3 deletions

View File

@ -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");

View File

@ -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;

535
lib/std/Io/Kqueue.zig Normal file
View File

@ -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");
}