Implement basic event processing and timers for the WinAPI driver.

This commit is contained in:
Sönke Ludwig 2017-01-21 16:39:48 +01:00
parent 373cf45b1e
commit 12e59b9c3c
2 changed files with 125 additions and 18 deletions

View file

@ -13,7 +13,7 @@ Driver | Linux | Windows | OS X | FreeBSD
------------------|-------|---------|------|--------
SelectEventDriver | yes | yes | yes¹ | yes¹
EpollEventDriver | yes | no | no | no
WinAPIEventDriver | no | yes¹ | no | no
WinAPIEventDriver | no | yes | no | no
KqueueEventDriver | no | no | yes¹ | yes¹
¹ planned, but not currenly implemented

View file

@ -10,41 +10,49 @@ module eventcore.drivers.winapi;
version (Windows):
import eventcore.driver;
import eventcore.drivers.timer;
import std.socket : Address;
import core.time : Duration;
import core.sys.windows.windows;
import core.sys.windows.winsock2;
final class WinAPIEventDriver : EventDriver {
@safe: /*@nogc:*/ nothrow:
private {
WinAPIEventDriverCore m_core;
WinAPIEventDriverFiles m_files;
WinAPIEventDriverSockets m_sockets;
WinAPIEventDriverDNS m_dns;
WinAPIEventDriverTimers m_timers;
LoopTimeoutTimerDriver m_timers;
WinAPIEventDriverEvents m_events;
WinAPIEventDriverSignals m_signals;
WinAPIEventDriverWatchers m_watchers;
}
this()
{
m_core = new WinAPIEventDriverCore();
@safe {
import std.exception : enforce;
WSADATA wd;
enforce(() @trusted { return WSAStartup(0x0202, &wd); } () == 0, "Failed to initialize WinSock");
m_events = new WinAPIEventDriverEvents();
m_signals = new WinAPIEventDriverSignals();
m_timers = new LoopTimeoutTimerDriver();
m_core = new WinAPIEventDriverCore(m_timers);
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();
}
@safe: /*@nogc:*/ nothrow:
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 LoopTimeoutTimerDriver timers() { return m_timers; }
override @property WinAPIEventDriverEvents events() { return m_events; }
override @property shared(WinAPIEventDriverEvents) events() shared { return m_events; }
override @property WinAPIEventDriverSignals signals() { return m_signals; }
@ -52,30 +60,78 @@ final class WinAPIEventDriver : EventDriver {
override void dispose()
{
assert(false, "TODO!");
}
}
final class WinAPIEventDriverCore : EventDriverCore {
@safe: /*@nogc:*/ nothrow:
override size_t waiterCount()
{
assert(false, "TODO!");
private {
bool m_exit;
size_t m_waiterCount;
DWORD m_tid;
LoopTimeoutTimerDriver m_timers;
HANDLE[] m_registeredEvents;
HANDLE m_fileCompletionEvent;
}
this(LoopTimeoutTimerDriver timers)
{
m_timers = timers;
m_tid = () @trusted { return GetCurrentThreadId(); } ();
m_fileCompletionEvent = () @trusted { return CreateEventW(null, false, false, null); } ();
m_registeredEvents ~= m_fileCompletionEvent;
}
override size_t waiterCount() { return m_waiterCount; }
override ExitReason processEvents(Duration timeout = Duration.max)
{
assert(false, "TODO!");
import std.algorithm : min;
import core.time : hnsecs, seconds;
if (m_exit) {
m_exit = false;
return ExitReason.exited;
}
bool got_event;
if (timeout <= 0.seconds) {
got_event = doProcessEvents(0.seconds);
got_event |= m_timers.process(currStdTime);
return got_event ? ExitReason.idle : ExitReason.timeout;
} else {
long now = currStdTime;
do {
auto nextto = min(m_timers.getNextTimeout(now), timeout);
got_event |= doProcessEvents(nextto);
long prev_step = now;
now = currStdTime;
got_event |= m_timers.process(now);
if (m_exit) {
m_exit = false;
return ExitReason.exited;
}
if (timeout != Duration.max)
timeout -= (now - prev_step).hnsecs;
} while (timeout > 0.seconds);
}
if (!waiterCount) return ExitReason.outOfWaiters;
if (got_event) return ExitReason.idle;
return ExitReason.timeout;
}
override void exit()
{
assert(false, "TODO!");
@trusted {
m_exit = true;
PostThreadMessageW(m_tid, WM_QUIT, 0, 0);
}
override void clearExitFlag()
{
assert(false, "TODO!");
m_exit = false;
}
protected override void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system
@ -87,6 +143,50 @@ final class WinAPIEventDriverCore : EventDriverCore {
{
assert(false, "TODO!");
}
private bool doProcessEvents(Duration max_wait)
{
import core.time : seconds;
import std.algorithm.comparison : min;
bool got_event;
if (max_wait > 0.seconds) {
DWORD timeout_msecs = max_wait == Duration.max ? INFINITE : cast(DWORD)min(max_wait.total!"msecs", DWORD.max);
auto ret = () @trusted { return MsgWaitForMultipleObjectsEx(cast(DWORD)m_registeredEvents.length, m_registeredEvents.ptr,
timeout_msecs, QS_ALLEVENTS, MWMO_ALERTABLE|MWMO_INPUTAVAILABLE); } ();
/*if (ret == WAIT_OBJECT_0) {
got_event = true;
Win32TCPConnection[] to_remove;
foreach( fw; m_fileWriters.byKey )
if( fw.testFileWritten() )
to_remove ~= fw;
foreach( fw; to_remove )
m_fileWriters.remove(fw);
}*/
}
MSG msg;
//uint cnt = 0;
while (() @trusted { return PeekMessageW(&msg, null, 0, 0, PM_REMOVE); } ()) {
if( msg.message == WM_QUIT ) {
m_exit = true;
return false;
}
() @trusted {
TranslateMessage(&msg);
DispatchMessageW(&msg);
} ();
got_event = true;
// process timers every now and then so that they don't get stuck
//if (++cnt % 10 == 0) processTimers();
}
return got_event;
}
}
final class WinAPIEventDriverSockets : EventDriverSockets {
@ -386,3 +486,10 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
assert(false, "TODO!");
}
}
private long currStdTime()
@safe nothrow {
import std.datetime : Clock;
scope (failure) assert(false);
return Clock.currStdTime;
}