From c12fefadcf932871075167011939fdf3ade32d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 17 Oct 2016 21:59:00 +0200 Subject: [PATCH] Add stub/partial implementation of WinAPI and kqueue based drivers. --- source/eventcore/drivers/kqueue.d | 107 +++++++++ source/eventcore/drivers/posix.d | 2 +- source/eventcore/drivers/winapi.d | 367 ++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 source/eventcore/drivers/kqueue.d create mode 100644 source/eventcore/drivers/winapi.d diff --git a/source/eventcore/drivers/kqueue.d b/source/eventcore/drivers/kqueue.d new file mode 100644 index 0000000..4ed3316 --- /dev/null +++ b/source/eventcore/drivers/kqueue.d @@ -0,0 +1,107 @@ +/** + BSD kqueue based event driver implementation. + + Kqueue is an efficient API for asynchronous I/O on BSD flavors, including + OS X/macOS, suitable for large numbers of concurrently open sockets. +*/ +module eventcore.drivers.kqueue; +@safe: /*@nogc:*/ nothrow: + +version (FreeBSD) enum have_kqueue = true; +else version (OSX) enum have_kqueue = true; +else enum have_kqueue = false; + +static if (have_kqueue): + +public import eventcore.drivers.posix; +import eventcore.internal.utils; + +import core.time : Duration; +import core.sys.posix.sys.time : timespec; + +version (OSX) import core.sys.darwin.sys.event; +else version (FreeBSD) import core.sys.freebsd.sys.event; +else static assert(false, "Kqueue not supported on this OS."); + + +import core.sys.linux.epoll; + + +final class KqueueEventLoop : PosixEventLoop { + private { + int m_queue; + kevent[] m_fds; + kevent[] m_events; + } + + this() + { + m_queue = kqueue(); + enforce(m_queue >= 0, "Failed to create kqueue."); + } + + override bool doProcessEvents(Duration timeout) + @trusted { + import std.algorithm : min; + //assert(Fiber.getThis() is null, "processEvents may not be called from within a fiber!"); + + //print("wait %s", m_events.length); + timespec ts; + long secs, hnsecs; + dur.split!("seconds", "hnsecs")(secs, hnsecs); + ts.tv_sec = cast(time_t)secs; + ts.tv_nsec = hnsecs * 100; + + auto ret = kevent(m_queue, m_fds, m_fds.length, m_events, m_events.length, timeout == Duration.max ? null : &ts); + + if (ret > 0) { + foreach (ref evt; m_events[0 .. ret]) { + //print("event %s %s", evt.data.fd, evt.events); + auto fd = cast(FD)evt.ident; + if (evt.flags & EV_READ) notify!(EventType.read)(fd); + if (evt.flags & EV_WRITE) notify!(EventType.write)(fd); + if (evt.flags & EV_ERROR) notify!(EventType.status)(fd); + else if (evt.flags & EV_EOF) notify!(EventType.status)(fd); + // EV_SIGNAL, EV_TIMEOUT + } + return true; + } else return false; + } + + override void dispose() + { + + import core.sys.posix.unistd : close; + close(m_queue); + } + + override void registerFD(FD fd, EventMask mask) + { + //print("register %s %s", fd, mask); + auto idx = allocSlot(fd); + kevent* ev = &m_events[idx]; + ev.ident = fd; + ev.flags = EV_ADD|EV_ET|EV_ENABLE; + if (mask & EventMask.read) ev.filter |= EVFILT_READ; + if (mask & EventMask.write) ev.filter |= EVFILT_WRITE; + if (mask & EventMask.status) ev.events |= EPOLLERR|EPOLLRDHUP; + } + + override void unregisterFD(FD fd) + { + auto idx = m_eventMap[fd]; + m_events[idx].flags = EV_REMOVE; + } + + override void updateFD(FD fd, EventMask mask) + { + //print("update %s %s", fd, mask); + auto idx = m_eventMap[fd]; + epoll_event* ev = &m_events[idx]; + ev.filter = 0; + ev.events |= EPOLLET; + if (mask & EventMask.read) ev.filter |= EVFILT_READ; + if (mask & EventMask.write) ev.filter |= EVFILT_WRITE; + if (mask & EventMask.status) ev.events |= EPOLLERR|EPOLLRDHUP; + } +} diff --git a/source/eventcore/drivers/posix.d b/source/eventcore/drivers/posix.d index 8480586..6c39a52 100644 --- a/source/eventcore/drivers/posix.d +++ b/source/eventcore/drivers/posix.d @@ -1,7 +1,7 @@ /** Base class for BSD socket based driver implementations. - See_also: `eventcore.drivers.select`, `eventcore.drivers.epoll` + See_also: `eventcore.drivers.select`, `eventcore.drivers.epoll`, `eventcore.drivers.kqueue` */ module eventcore.drivers.posix; @safe: /*@nogc:*/ nothrow: diff --git a/source/eventcore/drivers/winapi.d b/source/eventcore/drivers/winapi.d new file mode 100644 index 0000000..209c7ec --- /dev/null +++ b/source/eventcore/drivers/winapi.d @@ -0,0 +1,367 @@ +/** + WinAPI based event driver implementation. + + This driver uses overlapped I/O to model asynchronous I/O operations + efficiently. The driver's event loop processes UI messages, so that + it integrates with GUI applications transparently. +*/ +module eventcore.drivers.winapi; + +version (Windows): + +import eventcore.driver; +import std.socket : Address; +import core.time : Duration; + + +final class WinAPIEventDriver : EventDriver { +@safe: /*@nogc:*/ nothrow: + + private { + WinAPIEventDriverCore m_core; + WinAPIEventDriverFiles m_files; + WinAPIEventDriverSockets m_sockets; + WinAPIEventDriverDNS m_dns; + WinAPIEventDriverTimers m_timers; + WinAPIEventDriverEvents m_events; + WinAPIEventDriverSignals m_signals; + WinAPIEventDriverWatchers m_watchers; + } + + this() + { + m_core = new WinAPIEventDriverCore(); + m_files = new WinAPIEventDriverFiles(); + m_sockets = new WinAPIEventDriverSockets(); + m_dns = new WinAPIEventDriverDNS(); + m_timers = new WinAPIEventDriverTimers(); + m_events = new WinAPIEventDriverEvents(); + m_signals = new WinAPIEventDriverSignals(); + m_watchers = new WinAPIEventDriverWatchers(); + } + + override @property WinAPIEventDriverCore core() { return m_core; } + override @property WinAPIEventDriverFiles files() { return m_files; } + override @property WinAPIEventDriverSockets sockets() { return m_sockets; } + override @property WinAPIEventDriverDNS dns() { return m_dns; } + override @property WinAPIEventDriverTimers timers() { return m_timers; } + override @property WinAPIEventDriverEvents events() { return m_events; } + override @property WinAPIEventDriverSignals signals() { return m_signals; } + override @property WinAPIEventDriverWatchers watchers() { return m_watchers; } + + override void dispose() + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverCore : EventDriverCore { +@safe: /*@nogc:*/ nothrow: + override size_t waiterCount() + { + assert(false, "TODO!"); + } + + override ExitReason processEvents(Duration timeout = Duration.max) + { + assert(false, "TODO!"); + } + + override void exit() + { + assert(false, "TODO!"); + } + + override void clearExitFlag() + { + assert(false, "TODO!"); + } + + protected override void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverSockets : EventDriverSockets { +@safe: /*@nogc:*/ nothrow: + override StreamSocketFD connectStream(scope Address peer_address, ConnectCallback on_connect) + { + assert(false, "TODO!"); + } + + override StreamListenSocketFD listenStream(scope Address bind_address, AcceptCallback on_accept) + { + assert(false, "TODO!"); + } + + override void waitForConnections(StreamListenSocketFD sock, AcceptCallback on_accept) + { + assert(false, "TODO!"); + } + + override ConnectionState getConnectionState(StreamSocketFD sock) + { + assert(false, "TODO!"); + } + + override void setTCPNoDelay(StreamSocketFD socket, bool enable) + { + assert(false, "TODO!"); + } + + override void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish) + { + assert(false, "TODO!"); + } + + override void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish) + { + assert(false, "TODO!"); + } + + override void waitForData(StreamSocketFD socket, IOCallback on_data_available) + { + assert(false, "TODO!"); + } + + override void shutdown(StreamSocketFD socket, bool shut_read = true, bool shut_write = true) + { + assert(false, "TODO!"); + } + + override void cancelRead(StreamSocketFD socket) + { + assert(false, "TODO!"); + } + + override void cancelWrite(StreamSocketFD socket) + { + assert(false, "TODO!"); + } + + override DatagramSocketFD createDatagramSocket(scope Address bind_address, scope Address target_address) + { + assert(false, "TODO!"); + } + + override void receive(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, DatagramIOCallback on_receive_finish) + { + assert(false, "TODO!"); + } + + override void cancelReceive(DatagramSocketFD socket) + { + assert(false, "TODO!"); + } + + override void send(DatagramSocketFD socket, const(ubyte)[] buffer, IOMode mode, DatagramIOCallback on_send_finish, Address target_address = null) + { + assert(false, "TODO!"); + } + + override void cancelSend(DatagramSocketFD socket) + { + assert(false, "TODO!"); + } + + override void addRef(SocketFD descriptor) + { + assert(false, "TODO!"); + } + + override bool releaseRef(SocketFD descriptor) + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverDNS : EventDriverDNS { +@safe: /*@nogc:*/ nothrow: + + DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished) + { + assert(false, "TODO!"); + } + + void cancelLookup(DNSLookupID handle) + { + assert(false, "TODO!"); + } +} + + +final class WinAPIEventDriverFiles : EventDriverFiles { +@safe: /*@nogc:*/ nothrow: + override FileFD open(string path, FileOpenMode mode) + { + assert(false, "TODO!"); + } + + override FileFD createTemp() + { + assert(false, "TODO!"); + } + + override void close(FileFD file) + { + assert(false, "TODO!"); + } + + override ulong getSize(FileFD file) + { + assert(false, "TODO!"); + } + + override void write(FileFD file, ulong offset, const(ubyte)[] buffer, FileIOCallback on_write_finish) + { + assert(false, "TODO!"); + } + + override void read(FileFD file, ulong offset, ubyte[] buffer, FileIOCallback on_read_finish) + { + assert(false, "TODO!"); + } + + override void cancelWrite(FileFD file) + { + assert(false, "TODO!"); + } + + override void cancelRead(FileFD file) + { + assert(false, "TODO!"); + } + + override void addRef(FileFD descriptor) + { + assert(false, "TODO!"); + } + + override bool releaseRef(FileFD descriptor) + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverEvents : EventDriverEvents { +@safe: /*@nogc:*/ nothrow: + override EventID create() + { + assert(false, "TODO!"); + } + + override void trigger(EventID event, bool notify_all = true) + { + assert(false, "TODO!"); + } + + override void trigger(EventID event, bool notify_all = true) shared + { + assert(false, "TODO!"); + } + + override void wait(EventID event, EventCallback on_event) + { + assert(false, "TODO!"); + } + + override void cancelWait(EventID event, EventCallback on_event) + { + assert(false, "TODO!"); + } + + override void addRef(EventID descriptor) + { + assert(false, "TODO!"); + } + + override bool releaseRef(EventID descriptor) + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverSignals : EventDriverSignals { +@safe: /*@nogc:*/ nothrow: + override SignalListenID listen(int sig, SignalCallback on_signal) + { + assert(false, "TODO!"); + } + + override void addRef(SignalListenID descriptor) + { + assert(false, "TODO!"); + } + + override bool releaseRef(SignalListenID descriptor) + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverTimers : EventDriverTimers { +@safe: /*@nogc:*/ nothrow: + override TimerID create() + { + assert(false, "TODO!"); + } + + override void set(TimerID timer, Duration timeout, Duration repeat = Duration.zero) + { + assert(false, "TODO!"); + } + + override void stop(TimerID timer) + { + assert(false, "TODO!"); + } + + override bool isPending(TimerID timer) + { + assert(false, "TODO!"); + } + + override bool isPeriodic(TimerID timer) + { + assert(false, "TODO!"); + } + + override void wait(TimerID timer, TimerCallback callback) + { + assert(false, "TODO!"); + } + + override void cancelWait(TimerID timer) + { + assert(false, "TODO!"); + } + + override void addRef(TimerID descriptor) + { + assert(false, "TODO!"); + } + + override bool releaseRef(TimerID descriptor) + { + assert(false, "TODO!"); + } +} + +final class WinAPIEventDriverWatchers : EventDriverWatchers { +@safe: /*@nogc:*/ nothrow: + override WatcherID watchDirectory(string path, bool recursive, FileChangesCallback callback) + { + assert(false, "TODO!"); + } + + override void addRef(WatcherID descriptor) + { + assert(false, "TODO!"); + } + + override bool releaseRef(WatcherID descriptor) + { + assert(false, "TODO!"); + } +}