1 module dast.async.selector.kqueue;
2 
3 import dast.async.core;
4 
5 version (OSX)
6 	version = Kqueue;
7 else version (iOS)
8 	version = Kqueue;
9 else version (TVOS)
10 	version = Kqueue;
11 else version (WatchOS)
12 	version = Kqueue;
13 
14 version (Kqueue)  : import core.time,
15 core.stdc.string,
16 core.stdc.errno,
17 core.sys.darwin.sys.event,
18 core.sys.posix.signal,
19 core.sys.posix.netinet.tcp,
20 core.sys.posix.netinet.in_,
21 core.sys.posix.unistd,
22 core.sys.posix.time,
23 dast.async.core;
24 
25 version (HaveTimer) import dast.async.timer.kqueue;
26 
27 alias Selector = Kqueue;
28 
29 class Kqueue : KqueueEventChannel {
30 	this() {
31 		_eventHandle = kqueue();
32 		register(handle);
33 	}
34 
35 	~this() nothrow {
36 		dispose();
37 	}
38 
39 	void dispose() nothrow {
40 		if (!_eventHandle)
41 			return;
42 		unregister(this);
43 
44 		.close(_eventHandle);
45 		_eventHandle = 0;
46 	}
47 
48 	bool register(SocketChannel watcher) @trusted nothrow
49 	in (watcher) {
50 		int err = -1;
51 		if (watcher.type != WT.Timer) {
52 			const fd = watcher.handle;
53 			if (fd < 0)
54 				return false;
55 			kevent_t[2] ev = void;
56 			const flags = watcher.flags;
57 			short read = EV_ADD | EV_ENABLE;
58 			short write = EV_ADD | EV_ENABLE;
59 			if (flags & WF.ETMode) {
60 				read |= EV_CLEAR;
61 				write |= EV_CLEAR;
62 			}
63 			EV_SET(&ev[0], fd, EVFILT_READ, read, 0, 0, cast(void*)watcher);
64 			EV_SET(&ev[1], fd, EVFILT_WRITE, write, 0, 0, cast(void*)watcher);
65 			if ((flags & WF.ReadWrite) == WF.ReadWrite)
66 				err = kevent(_eventHandle, &ev[0], 2, null, 0, null);
67 			else if (flags & WF.Read)
68 				err = kevent(_eventHandle, &ev[0], 1, null, 0, null);
69 			else if (flags & WF.Write)
70 				err = kevent(_eventHandle, &ev[1], 1, null, 0, null);
71 		} else {
72 			version (HaveTimer) {
73 				kevent_t ev;
74 				auto watch = cast(TimerBase)watcher;
75 				if (watch is null)
76 					return false;
77 				size_t time = watch.time < 20 ? 20 : watch.time; // in millisecond
78 				EV_SET(&ev, watch.handle, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_CLEAR,
79 					0, time, cast(void*)watcher);
80 				err = kevent(_eventHandle, &ev, 1, null, 0, null);
81 			}
82 		}
83 		return err >= 0;
84 	}
85 	/+
86 	bool reregister(SocketChannel watcher)
87 	in (watcher) {
88 		// Kqueue does not support reregister
89 		return false;
90 	}
91 +/
92 	bool unregister(SocketChannel watcher) @trusted nothrow
93 	in (watcher) {
94 		const fd = watcher.handle;
95 		if (fd < 0)
96 			return false;
97 
98 		int err = -1;
99 		if (watcher.type != WT.Timer) {
100 			kevent_t[2] ev = void;
101 			EV_SET(&ev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, cast(void*)watcher);
102 			EV_SET(&ev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, cast(void*)watcher);
103 			const flags = watcher.flags;
104 			if ((flags & WF.ReadWrite) == WF.ReadWrite)
105 				err = kevent(_eventHandle, &ev[0], 2, null, 0, null);
106 			else if (flags & WF.Read)
107 				err = kevent(_eventHandle, &ev[0], 1, null, 0, null);
108 			else if (flags & WF.Write)
109 				err = kevent(_eventHandle, &ev[1], 1, null, 0, null);
110 		} else {
111 			version (HaveTimer) {
112 				kevent_t ev;
113 				auto watch = cast(TimerBase)watcher;
114 				if (!watch)
115 					return false;
116 				EV_SET(&ev, fd, EVFILT_TIMER, EV_DELETE, 0, 0, cast(void*)watcher);
117 				err = kevent(_eventHandle, &ev, 1, null, 0, null);
118 			}
119 		}
120 		return err >= 0;
121 	}
122 
123 	// override bool weakUp()
124 	// {
125 	//     call();
126 	//     return true;
127 	// }
128 
129 	void onWeakUp() @system {
130 		kevent_t[64] events;
131 		const len = kevent(_eventHandle, null, 0, events.ptr, events.length, &tspec);
132 		if (len < 1)
133 			return;
134 		foreach (i; 0 .. len) {
135 			auto watch = cast(SocketChannel)(events[i].udata);
136 			if (events[i].flags & (EV_EOF | EV_ERROR)) {
137 				watch.close();
138 				continue;
139 			}
140 			version (HaveTimer)
141 				if (watch.type == WT.Timer) {
142 					watch.onRead();
143 					continue;
144 				}
145 			if (watch.isRegistered) {
146 				// if (events[i].filter & EVFILT_WRITE) {
147 				// debug (Log) trace("The channel socket is: ", typeid(watch));
148 				// assert(cast(SocketChannel)watch);
149 				// }
150 
151 				if (events[i].filter & EVFILT_READ)
152 					watch.onRead();
153 			}
154 		}
155 	}
156 
157 	private int _eventHandle;
158 }
159 
160 private immutable tspec = timespec(1, 1000 * 10);
161 
162 class KqueueEventChannel : SocketChannel {
163 	this(EventLoop loop) {
164 		super(loop);
165 		flags |= WF.Read;
166 		_pair = socketPair();
167 		_pair[0].blocking = false;
168 		_pair[1].blocking = false;
169 		handle = _pair[1].handle;
170 	}
171 
172 	~this() {
173 		close();
174 	}
175 
176 	/+ void call() {
177 		_pair[0].send("call");
178 	}+/
179 
180 	override void onRead() {
181 		ubyte[128] data = void;
182 		while (_pair[1].receive(data) > 0) {
183 		}
184 	}
185 
186 	Socket[2] _pair;
187 }