Make the WinAPI driver initialization nogc.

This commit is contained in:
Sönke Ludwig 2018-10-22 22:05:37 +02:00
parent e7e4a0f5f5
commit 284d4f43c3
6 changed files with 72 additions and 45 deletions

View file

@ -5,7 +5,7 @@ version (Windows):
import eventcore.driver;
import eventcore.drivers.timer;
import eventcore.internal.consumablequeue;
import eventcore.internal.utils : nogc_assert;
import eventcore.internal.utils : mallocT, freeT, nogc_assert;
import eventcore.internal.win32;
import core.sync.mutex : Mutex;
import core.time : Duration;
@ -21,8 +21,9 @@ final class WinAPIEventDriverCore : EventDriverCore {
size_t m_waiterCount;
DWORD m_tid;
LoopTimeoutTimerDriver m_timers;
HANDLE[] m_registeredEvents;
void delegate() @safe nothrow[HANDLE] m_eventCallbacks;
HANDLE[MAXIMUM_WAIT_OBJECTS] m_registeredEvents;
void delegate() @safe nothrow[MAXIMUM_WAIT_OBJECTS] m_registeredEventCallbacks;
DWORD m_registeredEventCount = 0;
HANDLE m_fileCompletionEvent;
ConsumableQueue!IOEvent m_ioEvents;
@ -35,27 +36,36 @@ final class WinAPIEventDriverCore : EventDriverCore {
}
this(LoopTimeoutTimerDriver timers)
{
@nogc {
m_timers = timers;
m_tid = () @trusted { return GetCurrentThreadId(); } ();
m_fileCompletionEvent = () @trusted { return CreateEventW(null, false, false, null); } ();
registerEvent(m_fileCompletionEvent);
m_ioEvents = new ConsumableQueue!IOEvent;
m_ioEvents = mallocT!(ConsumableQueue!IOEvent);
static if (__VERSION__ >= 2074)
m_threadCallbackMutex = new shared Mutex;
m_threadCallbackMutex = mallocT!(shared(Mutex));
else {
() @trusted { m_threadCallbackMutex = cast(shared)new Mutex; } ();
() @trusted { m_threadCallbackMutex = cast(shared)mallocT!Mutex; } ();
}
m_threadCallbacks = new ConsumableQueue!(Tuple!(ThreadCallback, intptr_t));
m_threadCallbacks = mallocT!(ConsumableQueue!(Tuple!(ThreadCallback, intptr_t)));
m_threadCallbacks.reserve(1000);
}
void dispose()
@trusted {
try {
freeT(m_threadCallbacks);
freeT(m_threadCallbackMutex);
freeT(m_ioEvents);
} catch (Exception e) assert(false, e.msg);
}
override size_t waiterCount() { return m_waiterCount + m_timers.pendingCount; }
package void addWaiter() { m_waiterCount++; }
package void addWaiter() @nogc { m_waiterCount++; }
package void removeWaiter()
{
@nogc {
assert(m_waiterCount > 0, "Decrementing waiter count below zero.");
m_waiterCount--;
}
@ -159,7 +169,7 @@ final class WinAPIEventDriverCore : EventDriverCore {
bool got_event;
DWORD timeout_msecs = max_wait == Duration.max ? INFINITE : cast(DWORD)min(max(max_wait.total!"msecs", 0), DWORD.max);
auto ret = () @trusted { return MsgWaitForMultipleObjectsEx(cast(DWORD)m_registeredEvents.length, m_registeredEvents.ptr,
auto ret = () @trusted { return MsgWaitForMultipleObjectsEx(m_registeredEventCount, m_registeredEvents.ptr,
timeout_msecs, QS_ALLEVENTS, MWMO_ALERTABLE|MWMO_INPUTAVAILABLE); } ();
while (!m_ioEvents.empty) {
@ -168,9 +178,9 @@ final class WinAPIEventDriverCore : EventDriverCore {
}
if (ret == WAIT_IO_COMPLETION) got_event = true;
else if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + m_registeredEvents.length) {
if (auto pc = m_registeredEvents[ret - WAIT_OBJECT_0] in m_eventCallbacks) {
(*pc)();
else if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + m_registeredEventCount) {
if (auto cb = m_registeredEventCallbacks[ret - WAIT_OBJECT_0]) {
cb();
got_event = true;
}
}
@ -209,9 +219,11 @@ final class WinAPIEventDriverCore : EventDriverCore {
package void registerEvent(HANDLE event, void delegate() @safe nothrow callback = null)
{
m_registeredEvents ~= event;
if (callback) m_eventCallbacks[event] = callback;
@nogc {
assert(m_registeredEventCount < MAXIMUM_WAIT_OBJECTS, "Too many registered events.");
m_registeredEvents[m_registeredEventCount] = event;
if (callback) m_registeredEventCallbacks[m_registeredEventCount] = callback;
m_registeredEventCount++;
}
package SlotType* setupSlot(SlotType)(HANDLE h)
@ -231,7 +243,7 @@ final class WinAPIEventDriverCore : EventDriverCore {
}
package void discardEvents(scope OVERLAPPED_CORE*[] overlapped...)
{
@nogc {
import std.algorithm.searching : canFind;
m_ioEvents.filterPending!(evt => !overlapped.canFind(evt.overlapped));
}

View file

@ -18,6 +18,7 @@ import eventcore.drivers.winapi.files;
import eventcore.drivers.winapi.signals;
import eventcore.drivers.winapi.sockets;
import eventcore.drivers.winapi.watchers;
import eventcore.internal.utils : mallocT, freeT;
import core.sys.windows.windows;
static assert(HANDLE.sizeof <= FD.BaseType.sizeof);
@ -39,23 +40,25 @@ final class WinAPIEventDriver : EventDriver {
static WinAPIEventDriver threadInstance;
this()
@safe {
@safe nothrow @nogc {
assert(threadInstance is null);
threadInstance = this;
import std.exception : enforce;
WSADATA wd;
enforce(() @trusted { return WSAStartup(0x0202, &wd); } () == 0, "Failed to initialize WinSock");
m_signals = new WinAPIEventDriverSignals();
m_timers = new LoopTimeoutTimerDriver();
m_core = new WinAPIEventDriverCore(m_timers);
m_events = new WinAPIEventDriverEvents(m_core);
m_files = new WinAPIEventDriverFiles(m_core);
m_sockets = new WinAPIEventDriverSockets(m_core);
m_dns = new WinAPIEventDriverDNS();
m_watchers = new WinAPIEventDriverWatchers(m_core);
auto res = () @trusted { return WSAStartup(0x0202, &wd); } ();
assert(res == 0, "Failed to initialize WinSock");
m_signals = mallocT!WinAPIEventDriverSignals();
m_timers = mallocT!LoopTimeoutTimerDriver();
m_core = mallocT!WinAPIEventDriverCore(m_timers);
m_events = mallocT!WinAPIEventDriverEvents(m_core);
m_files = mallocT!WinAPIEventDriverFiles(m_core);
m_sockets = mallocT!WinAPIEventDriverSockets(m_core);
m_dns = mallocT!WinAPIEventDriverDNS();
m_watchers = mallocT!WinAPIEventDriverWatchers(m_core);
}
@safe: /*@nogc:*/ nothrow:
@ -75,8 +78,20 @@ final class WinAPIEventDriver : EventDriver {
{
if (!m_events) return;
m_events.dispose();
m_events = null;
m_core.dispose();
assert(threadInstance !is null);
threadInstance = null;
try () @trusted {
freeT(m_watchers);
freeT(m_dns);
freeT(m_sockets);
freeT(m_files);
freeT(m_events);
freeT(m_core);
freeT(m_timers);
freeT(m_signals);
} ();
catch (Exception e) assert(false, e.msg);
}
}

View file

@ -6,7 +6,7 @@ import eventcore.driver;
import eventcore.drivers.winapi.core;
import eventcore.internal.win32;
import eventcore.internal.consumablequeue;
import eventcore.internal.utils : nogc_assert;
import eventcore.internal.utils : mallocT, freeT, nogc_assert;
final class WinAPIEventDriverEvents : EventDriverEvents {
@ -31,10 +31,10 @@ final class WinAPIEventDriverEvents : EventDriverEvents {
}
this(WinAPIEventDriverCore core)
{
@nogc {
m_core = core;
m_event = () @trusted { return CreateEvent(null, false, false, null); } ();
m_pending = new ConsumableQueue!Trigger; // FIXME: avoid GC allocation
m_pending = mallocT!(ConsumableQueue!Trigger); // FIXME: avoid GC allocation
InitializeCriticalSection(&m_mutex);
m_core.registerEvent(m_event, &triggerPending);
}
@ -42,7 +42,7 @@ final class WinAPIEventDriverEvents : EventDriverEvents {
void dispose()
@trusted {
scope (failure) assert(false);
destroy(m_pending);
freeT(m_pending);
}
override EventID create()

View file

@ -17,7 +17,7 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
}
this(WinAPIEventDriverCore core)
{
@nogc {
m_core = core;
}

View file

@ -25,7 +25,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
this(WinAPIEventDriverCore core)
@trusted {
@trusted @nogc {
m_tid = GetCurrentThreadId();
m_core = core;
@ -406,7 +406,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
override void cancelRead(StreamSocketFD socket)
@trusted {
@trusted @nogc {
if (!m_sockets[socket].streamSocket.read.callback) return;
CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&m_sockets[socket].streamSocket.read.overlapped);
m_sockets[socket].streamSocket.read.callback = null;
@ -414,7 +414,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
override void cancelWrite(StreamSocketFD socket)
@trusted {
@trusted @nogc {
if (!m_sockets[socket].streamSocket.write.callback) return;
CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&m_sockets[socket].streamSocket.write.overlapped);
m_sockets[socket].streamSocket.write.callback = null;
@ -549,7 +549,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
override void cancelReceive(DatagramSocketFD socket)
@trusted {
@trusted @nogc {
if (!m_sockets[socket].datagramSocket.read.callback) return;
CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&m_sockets[socket].datagramSocket.read.overlapped);
m_sockets[socket].datagramSocket.read.callback = null;
@ -643,7 +643,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
override void cancelSend(DatagramSocketFD socket)
@trusted {
@trusted @nogc {
if (!m_sockets[socket].datagramSocket.write.callback) return;
CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&m_sockets[socket].datagramSocket.write.overlapped);
m_sockets[socket].datagramSocket.write.callback = null;
@ -719,7 +719,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
override bool releaseRef(SocketFD fd)
{
@nogc {
import taggedalgebraic : hasType;
auto slot = () @trusted { return &m_sockets[fd]; } ();
nogc_assert(slot.common.refCount > 0, "Releasing reference to unreferenced socket FD.");
@ -787,7 +787,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
private void* rawUserDataImpl(FD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
@system @nogc {
SocketSlot* fds = &m_sockets[descriptor].common;
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
@ -808,7 +808,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
package void clearSocketSlot(FD fd)
{
@nogc {
auto slot = () @trusted { return &m_sockets[fd]; } ();
if (slot.common.userDataDestructor)
() @trusted { slot.common.userDataDestructor(slot.common.userData.ptr); } ();
@ -889,8 +889,8 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
}
}
void setupWindowClass() nothrow
@trusted {
void setupWindowClass()
@trusted nothrow @nogc {
static __gshared registered = false;
if (registered) return;

View file

@ -16,7 +16,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
}
this(WinAPIEventDriverCore core)
{
@nogc {
m_core = core;
}