diff --git a/src/aio.zig b/src/aio.zig index ee51609..b97f72d 100644 --- a/src/aio.zig +++ b/src/aio.zig @@ -423,9 +423,6 @@ test "SymlinkAt" { } test "ChildExit" { - if (@import("builtin").target.os.tag != .linux) { - return error.SkipZigTest; - } const pid = try std.posix.fork(); if (pid == 0) { std.time.sleep(1 * std.time.ns_per_s); @@ -433,7 +430,13 @@ test "ChildExit" { } var term: std.process.Child.Term = undefined; try single(ChildExit{ .child = pid, .out_term = &term }); - try std.testing.expectEqual(69, term.Signal); + if (term == .Signal) { + try std.testing.expectEqual(69, term.Signal); + } else if (term == .Exited) { + try std.testing.expectEqual(69, term.Exited); + } else { + unreachable; + } } test "Socket" { diff --git a/src/aio/Fallback.zig b/src/aio/Fallback.zig index 87e9c1a..2a83657 100644 --- a/src/aio/Fallback.zig +++ b/src/aio/Fallback.zig @@ -239,7 +239,7 @@ fn cancelNotThreadSafe(self: *@This(), id: u16) enum { in_progress, not_found, o fn onThreadExecutor(self: *@This(), id: u16) void { var failure: Operation.Error = error.Success; - uopUnwrapCall(&self.sq.ops.nodes[id].used, posix.perform, .{}) catch |err| { + uopUnwrapCall(&self.sq.ops.nodes[id].used, posix.perform, .{self.sq.readiness[id]}) catch |err| { failure = err; }; self.completion_mutex.lock(); diff --git a/src/aio/common/posix.zig b/src/aio/common/posix.zig index 0629e86..368ed18 100644 --- a/src/aio/common/posix.zig +++ b/src/aio/common/posix.zig @@ -131,7 +131,7 @@ pub inline fn statusToTerm(status: u32) std.process.Child.Term { .{ .Unknown = status }; } -pub inline fn perform(op: anytype) Operation.Error!void { +pub inline fn perform(op: anytype, readiness: Readiness) Operation.Error!void { switch (comptime Operation.tagFromPayloadType(@TypeOf(op.*))) { .fsync => _ = try std.posix.fsync(op.file.handle), .read => op.out_read.* = try std.posix.pread(op.file.handle, op.buffer, op.offset), @@ -190,14 +190,9 @@ pub inline fn perform(op: anytype) Operation.Error!void { .mkdir_at => _ = try std.posix.mkdiratZ(op.dir.fd, op.path, op.mode), .symlink_at => _ = try std.posix.symlinkatZ(op.target, op.dir.fd, op.link_path), .child_exit => { - if (@hasDecl(std.posix.system, "waitid")) { - _ = std.posix.system.waitid(.PID, op.child, @constCast(&op._), std.posix.W.EXITED); - if (op.out_term) |term| { - term.* = statusToTerm(@intCast(op._.fields.common.second.sigchld.status)); - } - } else { - @panic("unsupported"); - } + _ = readiness; // TODO: prefer pidfd_wait on linux + const res = std.posix.waitpid(op.child, std.posix.W.NOHANG); + if (op.out_term) |term| term.* = statusToTerm(res.status); }, .socket => op.out_socket.* = try std.posix.socket(op.domain, op.flags, op.protocol), .close_socket => std.posix.close(op.socket), @@ -258,6 +253,23 @@ pub inline fn openReadiness(op: anytype) OpenReadinessError!Readiness { else => std.posix.unexpectedErrno(e), }; break :blk .{ .fd = @intCast(res), .mode = .in }; + } else if (comptime @hasDecl(std.posix.system, "kqueue")) { + const fd = try std.posix.kqueue(); + _ = std.posix.kevent(fd, &.{.{ + .ident = @intCast(op.child), + .filter = std.posix.system.EVFILT_PROC, + .flags = std.posix.system.EV_ADD | std.posix.system.EV_ENABLE | std.posix.system.EV_ONESHOT, + .fflags = std.posix.system.NOTE_EXIT, + .data = 0, + .udata = 0, + }}, &.{}, null) catch |err| return switch (err) { + error.EventNotFound => unreachable, + error.ProcessNotFound => unreachable, + error.AccessDenied => unreachable, + error.SystemResources => |e| e, + else => error.Unexpected, + }; + break :blk .{ .fd = fd, .mode = .in }; } else { @panic("unsupported"); } diff --git a/src/aio/ops.zig b/src/aio/ops.zig index 44237e7..f4f68e8 100644 --- a/src/aio/ops.zig +++ b/src/aio/ops.zig @@ -235,8 +235,8 @@ pub const ChildExit = struct { child: std.process.Child.Id, out_term: ?*std.process.Child.Term = null, _: switch (builtin.target.os.tag) { - .windows => @compileError("unsupported"), - else => std.posix.siginfo_t, + .linux => std.posix.siginfo_t, // only required for io_uring + else => void, } = undefined, out_id: ?*Id = null, out_error: ?*Error = null,