forked from lithdew/pike
-
Notifications
You must be signed in to change notification settings - Fork 0
/
notifier_kqueue.zig
103 lines (80 loc) · 2.89 KB
/
notifier_kqueue.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const std = @import("std");
const pike = @import("pike.zig");
const posix = @import("os/posix.zig");
const os = std.os;
const net = std.net;
const mem = std.mem;
const time = std.time;
pub inline fn init() !void {}
pub inline fn deinit() void {}
pub const Handle = struct {
inner: os.fd_t,
wake_fn: fn (self: *Handle, batch: *pike.Batch, opts: pike.WakeOptions) void,
pub inline fn wake(self: *Handle, batch: *pike.Batch, opts: pike.WakeOptions) void {
self.wake_fn(self, batch, opts);
}
};
pub const Notifier = struct {
const Self = @This();
handle: os.fd_t,
pub fn init() !Self {
const handle = try os.kqueue();
errdefer os.close(handle);
return Self{ .handle = handle };
}
pub fn deinit(self: *const Self) void {
os.close(self.handle);
}
pub fn register(self: *const Self, handle: *const Handle, comptime opts: pike.PollOptions) !void {
if (handle.inner == -1) return;
var changelist = [_]os.Kevent{
.{
.ident = undefined,
.filter = undefined,
.flags = os.EV_ADD | os.EV_CLEAR,
.fflags = 0,
.data = 0,
.udata = undefined,
},
} ** 2;
comptime var changelist_len = 0;
comptime {
if (opts.read) {
changelist[changelist_len].filter = os.EVFILT_READ;
changelist_len += 1;
}
if (opts.write) {
changelist[changelist_len].filter = os.EVFILT_WRITE;
changelist_len += 1;
}
}
for (changelist[0..changelist_len]) |*event| {
event.ident = @intCast(usize, handle.inner);
event.udata = @ptrToInt(handle);
}
_ = try os.kevent(self.handle, changelist[0..changelist_len], &[0]os.Kevent{}, null);
}
pub fn poll(self: *const Self, timeout: i32) !void {
var events: [128]os.Kevent = undefined;
var batch: pike.Batch = .{};
defer pike.dispatch(batch, .{});
const timeout_spec = os.timespec{
.tv_sec = @divTrunc(timeout, time.ms_per_s),
.tv_nsec = @rem(timeout, time.ms_per_s) * time.ns_per_ms,
};
const num_events = try os.kevent(self.handle, &[0]os.Kevent{}, events[0..], &timeout_spec);
for (events[0..num_events]) |e| {
const handle = @intToPtr(*Handle, e.udata);
const notify = e.filter == os.EVFILT_USER;
const shutdown = e.flags & (os.EV_ERROR | os.EV_EOF) != 0;
const read_ready = e.filter == os.EVFILT_READ;
const write_ready = e.filter == os.EVFILT_WRITE;
handle.wake(&batch, .{
.notify = notify,
.shutdown = shutdown,
.read_ready = read_ready,
.write_ready = write_ready,
});
}
}
};