Skip to content

Commit 7926078

Browse files
mitchellhnikneym
authored andcommitted
backend/kqueue: move wakeup state to dedicated struct
1 parent 291f21d commit 7926078

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.
@@ -320,34 +316,12 @@ pub const Loop = struct {
320316
self.thread_pool_completions.init();
321317
}
322318

323-
if (comptime builtin.target.os.tag == .macos) {
324-
// Add our event so that we wake up when our mach port receives an
325-
// event. We have to add here because we need a stable self pointer.
326-
const events = [_]Kevent{.{
327-
.ident = @as(usize, @intCast(self.mach_port.port)),
328-
.filter = std.c.EVFILT.MACHPORT,
329-
.flags = std.c.EV.ADD | std.c.EV.ENABLE,
330-
.fflags = darwin.MACH_RCV_MSG,
331-
.data = 0,
332-
.udata = 0,
333-
.ext = .{
334-
@intFromPtr(&self.mach_port_buffer),
335-
self.mach_port_buffer.len,
336-
},
337-
}};
338-
const n = kevent_syscall(
339-
self.kqueue_fd,
340-
&events,
341-
events[0..0],
342-
null,
343-
) catch |err| {
344-
// We reset initialization because we can't do anything
345-
// safely unless we get this mach port registered!
346-
self.flags.init = false;
347-
return err;
348-
};
349-
assert(n == 0);
350-
}
319+
self.wakeup_state.setup(self.kqueue_fd) catch |err| {
320+
// We reset initialization because we can't do anything
321+
// safely unless we get this mach port registered!
322+
self.flags.init = false;
323+
return err;
324+
};
351325
}
352326

353327
// The list of events, used as both a changelist and eventlist.
@@ -982,7 +956,7 @@ pub const Loop = struct {
982956
/// Sends an empty message to this loop's mach port so that it wakes
983957
/// up if it is blocking on kevent().
984958
fn wakeup(self: *Loop) !void {
985-
try self.mach_port.notify();
959+
try self.wakeup_state.wakeup();
986960
}
987961
};
988962

@@ -1449,6 +1423,76 @@ pub const Completion = struct {
14491423
}
14501424
};
14511425

1426+
/// The struct used for loop wakeup. This is only internal state.
1427+
const Wakeup = if (builtin.os.tag.isDarwin()) struct {
1428+
const Self = @This();
1429+
1430+
/// The mach port that this kqueue always has a filter for. Writing
1431+
/// an empty message to this port can be used to wake up the loop
1432+
/// at any time. Waking up the loop via this port won't trigger any
1433+
/// particular completion, it just forces tick to cycle.
1434+
mach_port: xev.Async,
1435+
mach_port_buffer: [32]u8 = undefined,
1436+
1437+
fn init() !Self {
1438+
const mach_port = try xev.Async.init();
1439+
errdefer mach_port.deinit();
1440+
return .{ .mach_port = mach_port };
1441+
}
1442+
1443+
fn deinit(self: *Self) void {
1444+
self.mach_port.deinit();
1445+
}
1446+
1447+
fn setup(self: *Self, kqueue_fd: posix.fd_t) !void {
1448+
const events = [_]Kevent{.{
1449+
.ident = @as(usize, @intCast(self.mach_port.port)),
1450+
.filter = std.c.EVFILT.MACHPORT,
1451+
.flags = std.c.EV.ADD | std.c.EV.ENABLE,
1452+
.fflags = darwin.MACH_RCV_MSG,
1453+
.data = 0,
1454+
.udata = 0,
1455+
.ext = .{
1456+
@intFromPtr(&self.mach_port_buffer),
1457+
self.mach_port_buffer.len,
1458+
},
1459+
}};
1460+
const n = try kevent_syscall(
1461+
kqueue_fd,
1462+
&events,
1463+
events[0..0],
1464+
null,
1465+
);
1466+
assert(n == 0);
1467+
}
1468+
1469+
fn wakeup(self: *Self) !void {
1470+
try self.mach_port.notify();
1471+
}
1472+
} else struct {
1473+
// TODO: We should use eventfd for FreeBSD. Until this is
1474+
// implemented, loop wakeup will crash on BSD.
1475+
const Self = @This();
1476+
1477+
fn init() !Self {
1478+
return .{};
1479+
}
1480+
1481+
fn deinit(self: *Self) void {
1482+
_ = self;
1483+
}
1484+
1485+
fn setup(self: *Self, kqueue_fd: posix.fd_t) !void {
1486+
_ = self;
1487+
_ = kqueue_fd;
1488+
}
1489+
1490+
fn wakeup(self: *Self) !void {
1491+
_ = self;
1492+
@panic("wakeup not implemented on this platform");
1493+
}
1494+
};
1495+
14521496
pub const OperationType = enum {
14531497
noop,
14541498
accept,

0 commit comments

Comments
 (0)