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 }