Skip to content

Commit b1d5fae

Browse files
mitchellhSythivo
authored andcommitted
backend/kqueue: move wakeup state to dedicated struct
1 parent 73edbe7 commit b1d5fae

File tree

1 file changed

+83
-39
lines changed

1 file changed

+83
-39
lines changed

src/backend/kqueue.zig

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,8 @@ pub const Loop = struct {
4545
/// The fd of the kqueue.
4646
kqueue_fd: posix.fd_t,
4747

48-
/// The mach port that this kqueue always has a filter for. Writing
49-
/// an empty message to this port can be used to wake up the loop
50-
/// at any time. Waking up the loop via this port won't trigger any
51-
/// particular completion, it just forces tick to cycle.
52-
mach_port: xev.Async,
53-
mach_port_buffer: [32]u8 = undefined,
48+
/// The wakeup mechanism (mach ports on Apple, eventfd on BSD).
49+
wakeup_state: Wakeup,
5450

5551
/// The number of active completions. This DOES NOT include completions that
5652
/// are queued in the submissions queue.
@@ -105,12 +101,12 @@ pub const Loop = struct {
105101
const fd = try posix.kqueue();
106102
errdefer posix.close(fd);
107103

108-
const mach_port = try xev.Async.init();
109-
errdefer mach_port.deinit();
104+
const wakeup_state: Wakeup = try .init();
105+
errdefer wakeup_state.deinit();
110106

111107
var res: Loop = .{
112108
.kqueue_fd = fd,
113-
.mach_port = mach_port,
109+
.wakeup_state = wakeup_state,
114110
.thread_pool = options.thread_pool,
115111
.thread_pool_completions = undefined,
116112
.cached_now = undefined,
@@ -124,7 +120,7 @@ pub const Loop = struct {
124120
/// were unprocessed are lost -- their callbacks will never be called.
125121
pub fn deinit(self: *Loop) void {
126122
posix.close(self.kqueue_fd);
127-
if (comptime builtin.os.tag == .macos) self.mach_port.deinit();
123+
self.wakeup_state.deinit();
128124
}
129125

130126
/// Stop the loop. This can only be called from the main thread.
@@ -360,34 +356,12 @@ pub const Loop = struct {
360356
self.thread_pool_completions.init();
361357
}
362358

363-
if (comptime builtin.target.os.tag == .macos) {
364-
// Add our event so that we wake up when our mach port receives an
365-
// event. We have to add here because we need a stable self pointer.
366-
const events = [_]Kevent{.{
367-
.ident = @as(usize, @intCast(self.mach_port.port)),
368-
.filter = posix.system.EVFILT.MACHPORT,
369-
.flags = posix.system.EV.ADD | posix.system.EV.ENABLE,
370-
.fflags = darwin.MACH_RCV_MSG,
371-
.data = 0,
372-
.udata = 0,
373-
.ext = .{
374-
@intFromPtr(&self.mach_port_buffer),
375-
self.mach_port_buffer.len,
376-
},
377-
}};
378-
const n = kevent_syscall(
379-
self.kqueue_fd,
380-
&events,
381-
events[0..0],
382-
null,
383-
) catch |err| {
384-
// We reset initialization because we can't do anything
385-
// safely unless we get this mach port registered!
386-
self.flags.init = false;
387-
return err;
388-
};
389-
assert(n == 0);
390-
}
359+
self.wakeup_state.setup(self.kqueue_fd) catch |err| {
360+
// We reset initialization because we can't do anything
361+
// safely unless we get this mach port registered!
362+
self.flags.init = false;
363+
return err;
364+
};
391365
}
392366

393367
// The list of events, used as both a changelist and eventlist.
@@ -1037,7 +1011,7 @@ pub const Loop = struct {
10371011
/// Sends an empty message to this loop's mach port so that it wakes
10381012
/// up if it is blocking on kevent().
10391013
fn wakeup(self: *Loop) !void {
1040-
try self.mach_port.notify();
1014+
try self.wakeup_state.wakeup();
10411015
}
10421016
};
10431017

@@ -1508,6 +1482,76 @@ pub const Completion = struct {
15081482
}
15091483
};
15101484

1485+
/// The struct used for loop wakeup. This is only internal state.
1486+
const Wakeup = if (builtin.os.tag.isDarwin()) struct {
1487+
const Self = @This();
1488+
1489+
/// The mach port that this kqueue always has a filter for. Writing
1490+
/// an empty message to this port can be used to wake up the loop
1491+
/// at any time. Waking up the loop via this port won't trigger any
1492+
/// particular completion, it just forces tick to cycle.
1493+
mach_port: xev.Async,
1494+
mach_port_buffer: [32]u8 = undefined,
1495+
1496+
fn init() !Self {
1497+
const mach_port = try xev.Async.init();
1498+
errdefer mach_port.deinit();
1499+
return .{ .mach_port = mach_port };
1500+
}
1501+
1502+
fn deinit(self: *Self) void {
1503+
self.mach_port.deinit();
1504+
}
1505+
1506+
fn setup(self: *Self, kqueue_fd: posix.fd_t) !void {
1507+
const events = [_]Kevent{.{
1508+
.ident = @as(usize, @intCast(self.mach_port.port)),
1509+
.filter = std.c.EVFILT.MACHPORT,
1510+
.flags = std.c.EV.ADD | std.c.EV.ENABLE,
1511+
.fflags = darwin.MACH_RCV_MSG,
1512+
.data = 0,
1513+
.udata = 0,
1514+
.ext = .{
1515+
@intFromPtr(&self.mach_port_buffer),
1516+
self.mach_port_buffer.len,
1517+
},
1518+
}};
1519+
const n = try kevent_syscall(
1520+
kqueue_fd,
1521+
&events,
1522+
events[0..0],
1523+
null,
1524+
);
1525+
assert(n == 0);
1526+
}
1527+
1528+
fn wakeup(self: *Self) !void {
1529+
try self.mach_port.notify();
1530+
}
1531+
} else struct {
1532+
// TODO: We should use eventfd for FreeBSD. Until this is
1533+
// implemented, loop wakeup will crash on BSD.
1534+
const Self = @This();
1535+
1536+
fn init() !Self {
1537+
return .{};
1538+
}
1539+
1540+
fn deinit(self: *Self) void {
1541+
_ = self;
1542+
}
1543+
1544+
fn setup(self: *Self, kqueue_fd: posix.fd_t) !void {
1545+
_ = self;
1546+
_ = kqueue_fd;
1547+
}
1548+
1549+
fn wakeup(self: *Self) !void {
1550+
_ = self;
1551+
@panic("wakeup not implemented on this platform");
1552+
}
1553+
};
1554+
15111555
pub const OperationType = enum {
15121556
noop,
15131557
accept,

0 commit comments

Comments
 (0)