Add stub/partial implementation of WinAPI and kqueue based drivers.
This commit is contained in:
parent
201e4f6077
commit
c12fefadcf
107
source/eventcore/drivers/kqueue.d
Normal file
107
source/eventcore/drivers/kqueue.d
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
Base class for BSD socket based driver implementations.
|
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;
|
module eventcore.drivers.posix;
|
||||||
@safe: /*@nogc:*/ nothrow:
|
@safe: /*@nogc:*/ nothrow:
|
||||||
|
|
367
source/eventcore/drivers/winapi.d
Normal file
367
source/eventcore/drivers/winapi.d
Normal file
|
@ -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!");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue