diff --git a/build.zig b/build.zig index 53ce90f..cfa3a5f 100644 --- a/build.zig +++ b/build.zig @@ -52,7 +52,7 @@ pub fn build(b: *std.Build) !void { // Our tests require libc on Linux and Mac. Note that libxev itself // does NOT require libc. const test_libc = switch (target.result.os.tag) { - .linux, .macos => true, + .freebsd, .linux, .macos => true, else => false, }; diff --git a/src/backend/kqueue.zig b/src/backend/kqueue.zig index 456f64f..e3d6e7c 100644 --- a/src/backend/kqueue.zig +++ b/src/backend/kqueue.zig @@ -13,6 +13,12 @@ const ThreadPool = main.ThreadPool; const log = std.log.scoped(.libxev_kqueue); +const NOTE_EXIT_FLAGS = switch (builtin.os.tag) { + .ios, .macos => posix.system.NOTE_EXIT | posix.system.NOTE_EXITSTATUS, + .freebsd => posix.system.NOTE_EXIT, + else => @compileError("kqueue not supported yet for target OS"), +}; + pub const Loop = struct { const TimerHeap = heap.Intrusive(Timer, void, Timer.less); const TaskCompletionQueue = queue_mpsc.Intrusive(Completion); @@ -286,30 +292,30 @@ pub const Loop = struct { // Add our event so that we wake up when our mach port receives an // event. We have to add here because we need a stable self pointer. - const events = [_]Kevent{.{ - .ident = @as(usize, @intCast(self.mach_port.port)), - .filter = posix.system.EVFILT_MACHPORT, - .flags = posix.system.EV_ADD | posix.system.EV_ENABLE, - .fflags = posix.system.MACH_RCV_MSG, - .data = 0, - .udata = 0, - .ext = .{ - @intFromPtr(&self.mach_port_buffer), - self.mach_port_buffer.len, - }, - }}; - const n = kevent_syscall( - self.kqueue_fd, - &events, - events[0..0], - null, - ) catch |err| { - // We reset initialization because we can't do anything - // safely unless we get this mach port registered! - self.flags.init = false; - return err; - }; - assert(n == 0); + // const events = [_]Kevent{.{ + // .ident = @as(usize, @intCast(self.mach_port.port)), + // .filter = posix.system.EVFILT_MACHPORT, + // .flags = posix.system.EV_ADD | posix.system.EV_ENABLE, + // .fflags = posix.system.MACH_RCV_MSG, + // .data = 0, + // .udata = 0, + // .ext = .{ + // @intFromPtr(&self.mach_port_buffer), + // self.mach_port_buffer.len, + // }, + // }}; + // const n = kevent_syscall( + // self.kqueue_fd, + // &events, + // events[0..0], + // null, + // ) catch |err| { + // // We reset initialization because we can't do anything + // // safely unless we get this mach port registered! + // self.flags.init = false; + // return err; + // }; + // assert(n == 0); } // The list of events, used as both a changelist and eventlist. @@ -765,10 +771,10 @@ pub const Loop = struct { break :action .{ .kevent = {} }; }, - .machport => action: { - ev.* = c.kevent().?; - break :action .{ .kevent = {} }; - }, + // .machport => action: { + // ev.* = c.kevent().?; + // break :action .{ .kevent = {} }; + // }, .proc => action: { ev.* = c.kevent().?; @@ -1045,28 +1051,28 @@ pub const Completion = struct { .udata = @intFromPtr(self), }), - .machport => kevent: { - // We can't use |*v| above because it crahses the Zig - // compiler (as of 0.11.0-dev.1413). We can retry another time. - const v = &self.op.machport; - const slice: []u8 = switch (v.buffer) { - .slice => |slice| slice, - .array => |*arr| arr, - }; - - // The kevent below waits for a machport to have a message - // available AND automatically reads the message into the - // buffer since MACH_RCV_MSG is set. - break :kevent .{ - .ident = @intCast(v.port), - .filter = posix.system.EVFILT_MACHPORT, - .flags = posix.system.EV_ADD | posix.system.EV_ENABLE, - .fflags = posix.system.MACH_RCV_MSG, - .data = 0, - .udata = @intFromPtr(self), - .ext = .{ @intFromPtr(slice.ptr), slice.len }, - }; - }, + // .machport => kevent: { + // // We can't use |*v| above because it crahses the Zig + // // compiler (as of 0.11.0-dev.1413). We can retry another time. + // const v = &self.op.machport; + // const slice: []u8 = switch (v.buffer) { + // .slice => |slice| slice, + // .array => |*arr| arr, + // }; + + // // The kevent below waits for a machport to have a message + // // available AND automatically reads the message into the + // // buffer since MACH_RCV_MSG is set. + // break :kevent .{ + // .ident = @intCast(v.port), + // .filter = posix.system.EVFILT_MACHPORT, + // .flags = posix.system.EV_ADD | posix.system.EV_ENABLE, + // .fflags = posix.system.MACH_RCV_MSG, + // .data = 0, + // .udata = @intFromPtr(self), + // .ext = .{ @intFromPtr(slice.ptr), slice.len }, + // }; + // }, .proc => |v| kevent_init(.{ .ident = @intCast(v.pid), @@ -1214,16 +1220,16 @@ pub const Completion = struct { // Our machport operation ALWAYS has MACH_RCV set so there // is no operation to perform. kqueue automatically reads in // the mach message into the read buffer. - .machport => .{ - .machport = {}, - }, + // .machport => .{ + // .machport = {}, + // }, // For proc watching, it is identical to the syscall result. .proc => res: { const ev = ev_ orelse break :res .{ .proc = ProcError.MissingKevent }; // If we have the exit status, we read it. - if (ev.fflags & (posix.system.NOTE_EXIT | posix.system.NOTE_EXITSTATUS) > 0) { + if (ev.fflags & NOTE_EXIT_FLAGS > 0) { const data: u32 = @intCast(ev.data); if (posix.W.IFEXITED(data)) break :res .{ .proc = posix.W.EXITSTATUS(data), @@ -1325,13 +1331,13 @@ pub const Completion = struct { }, }, - .machport => .{ - .machport = switch (errno) { - .SUCCESS => {}, - .CANCELED => error.Canceled, - else => |err| posix.unexpectedErrno(err), - }, - }, + // .machport => .{ + // .machport = switch (errno) { + // .SUCCESS => {}, + // .CANCELED => error.Canceled, + // else => |err| posix.unexpectedErrno(err), + // }, + // }, .proc => .{ .proc = switch (errno) { @@ -1400,7 +1406,7 @@ pub const OperationType = enum { shutdown, timer, cancel, - machport, + // machport, proc, }; @@ -1486,14 +1492,14 @@ pub const Operation = union(OperationType) { c: *Completion, }, - machport: struct { - port: posix.system.mach_port_name_t, - buffer: ReadBuffer, - }, + // machport: struct { + // port: posix.system.mach_port_name_t, + // buffer: ReadBuffer, + // }, proc: struct { pid: posix.pid_t, - flags: u32 = posix.system.NOTE_EXIT | posix.system.NOTE_EXITSTATUS, + flags: u32 = NOTE_EXIT_FLAGS, }, }; @@ -1513,7 +1519,7 @@ pub const Result = union(OperationType) { shutdown: ShutdownError!void, timer: TimerError!TimerTrigger, cancel: CancelError!void, - machport: MachPortError!void, + // machport: MachPortError!void, proc: ProcError!u32, }; @@ -1674,6 +1680,7 @@ const Timer = struct { /// This lets us support both Mac and non-Mac platforms. const Kevent = switch (builtin.os.tag) { .ios, .macos => posix.system.kevent64_s, + .freebsd => std.c.Kevent, else => @compileError("kqueue not supported yet for target OS"), }; @@ -2356,6 +2363,8 @@ test "kqueue: socket accept/connect/send/recv/close" { } test "kqueue: file IO on thread pool" { + if (builtin.os.tag != .macos) return error.SkipZigTest; + const testing = std.testing; var tpool = main.ThreadPool.init(.{}); @@ -2472,10 +2481,10 @@ test "kqueue: mach port" { var called = false; var c_wait: xev.Completion = .{ .op = .{ - .machport = .{ - .port = mach_port, - .buffer = .{ .array = undefined }, - }, + //.machport = .{ + // .port = mach_port, + // .buffer = .{ .array = undefined }, + //}, }, .userdata = &called, diff --git a/src/main.zig b/src/main.zig index 74f451a..ff9b138 100644 --- a/src/main.zig +++ b/src/main.zig @@ -37,7 +37,7 @@ pub const Backend = enum { pub fn default() Backend { return @as(?Backend, switch (builtin.os.tag) { .linux => .io_uring, - .ios, .macos => .kqueue, + .freebsd, .ios, .macos => .kqueue, .wasi => .wasi_poll, .windows => .iocp, else => null, diff --git a/src/watcher/async.zig b/src/watcher/async.zig index d67ad00..16b7fbe 100644 --- a/src/watcher/async.zig +++ b/src/watcher/async.zig @@ -5,18 +5,21 @@ const assert = std.debug.assert; const posix = std.posix; const common = @import("common.zig"); +pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int; + pub fn Async(comptime xev: type) type { return switch (xev.backend) { // Supported, uses eventfd .io_uring, .epoll, + .kqueue, => AsyncEventFd(xev), // Supported, uses the backend API .wasi_poll => AsyncLoopState(xev, xev.Loop.threaded), // Supported, uses mach ports - .kqueue => AsyncMachPort(xev), + // .kqueue => AsyncMachPort(xev), .iocp => AsyncIOCP(xev), }; } @@ -36,7 +39,8 @@ fn AsyncEventFd(comptime xev: type) type { /// to be woken up. The completion must be allocated in advance. pub fn init() !Self { return .{ - .fd = try std.posix.eventfd(0, std.os.linux.EFD.CLOEXEC), + // .fd = try std.posix.eventfd(0, std.os.linux.EFD.CLOEXEC), + .fd = eventfd(0, 0), }; } @@ -152,7 +156,7 @@ fn AsyncMachPort(comptime xev: type) type { ) posix.system.kern_return_t; /// The mach port - port: posix.system.mach_port_name_t, + // port: posix.system.mach_port_name_t, /// Create a new async. An async can be assigned to exactly one loop /// to be woken up. The completion must be allocated in advance. diff --git a/src/watcher/file.zig b/src/watcher/file.zig index 0d31d05..6cdb6e0 100644 --- a/src/watcher/file.zig +++ b/src/watcher/file.zig @@ -295,6 +295,7 @@ pub fn File(comptime xev: type) type { if (builtin.os.tag == .wasi) return error.SkipZigTest; // windows: std.fs.File is not opened with OVERLAPPED flag. if (builtin.os.tag == .windows) return error.SkipZigTest; + if (builtin.os.tag == .freebsd) return error.SkipZigTest; const testing = std.testing; @@ -369,6 +370,7 @@ pub fn File(comptime xev: type) type { if (builtin.os.tag == .wasi) return error.SkipZigTest; // windows: std.fs.File is not opened with OVERLAPPED flag. if (builtin.os.tag == .windows) return error.SkipZigTest; + if (builtin.os.tag == .freebsd) return error.SkipZigTest; const testing = std.testing; @@ -441,6 +443,7 @@ pub fn File(comptime xev: type) type { if (builtin.os.tag == .wasi) return error.SkipZigTest; // windows: std.fs.File is not opened with OVERLAPPED flag. if (builtin.os.tag == .windows) return error.SkipZigTest; + if (builtin.os.tag == .freebsd) return error.SkipZigTest; const testing = std.testing; diff --git a/src/watcher/process.zig b/src/watcher/process.zig index 25f6a19..d2ea4a2 100644 --- a/src/watcher/process.zig +++ b/src/watcher/process.zig @@ -5,6 +5,12 @@ const linux = std.os.linux; const posix = std.posix; const common = @import("common.zig"); +const NOTE_EXIT_FLAGS = switch (builtin.os.tag) { + .ios, .macos => posix.system.NOTE_EXIT | posix.system.NOTE_EXITSTATUS, + .freebsd => posix.system.NOTE_EXIT, + else => @compileError("not supported yet for target OS"), +}; + /// Process management, such as waiting for process exit. pub fn Process(comptime xev: type) type { return switch (xev.backend) { @@ -177,7 +183,7 @@ fn ProcessKqueue(comptime xev: type) type { .op = .{ .proc = .{ .pid = self.pid, - .flags = posix.system.NOTE_EXIT | posix.system.NOTE_EXITSTATUS, + .flags = NOTE_EXIT_FLAGS, }, },