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.driver;
import eventcore.drivers.timer; import eventcore.drivers.timer;
import eventcore.internal.consumablequeue; import eventcore.internal.consumablequeue;
import eventcore.internal.utils : nogc_assert; import eventcore.internal.utils : mallocT, freeT, nogc_assert;
import eventcore.internal.win32; import eventcore.internal.win32;
import core.sync.mutex : Mutex; import core.sync.mutex : Mutex;
import core.time : Duration; import core.time : Duration;
@ -21,8 +21,9 @@ final class WinAPIEventDriverCore : EventDriverCore {
size_t m_waiterCount; size_t m_waiterCount;
DWORD m_tid; DWORD m_tid;
LoopTimeoutTimerDriver m_timers; LoopTimeoutTimerDriver m_timers;
HANDLE[] m_registeredEvents; HANDLE[MAXIMUM_WAIT_OBJECTS] m_registeredEvents;
void delegate() @safe nothrow[HANDLE] m_eventCallbacks; void delegate() @safe nothrow[MAXIMUM_WAIT_OBJECTS] m_registeredEventCallbacks;
DWORD m_registeredEventCount = 0;
HANDLE m_fileCompletionEvent; HANDLE m_fileCompletionEvent;
ConsumableQueue!IOEvent m_ioEvents; ConsumableQueue!IOEvent m_ioEvents;
@ -35,27 +36,36 @@ final class WinAPIEventDriverCore : EventDriverCore {
} }
this(LoopTimeoutTimerDriver timers) this(LoopTimeoutTimerDriver timers)
{ @nogc {
m_timers = timers; m_timers = timers;
m_tid = () @trusted { return GetCurrentThreadId(); } (); m_tid = () @trusted { return GetCurrentThreadId(); } ();
m_fileCompletionEvent = () @trusted { return CreateEventW(null, false, false, null); } (); m_fileCompletionEvent = () @trusted { return CreateEventW(null, false, false, null); } ();
registerEvent(m_fileCompletionEvent); registerEvent(m_fileCompletionEvent);
m_ioEvents = new ConsumableQueue!IOEvent; m_ioEvents = mallocT!(ConsumableQueue!IOEvent);
static if (__VERSION__ >= 2074) static if (__VERSION__ >= 2074)
m_threadCallbackMutex = new shared Mutex; m_threadCallbackMutex = mallocT!(shared(Mutex));
else { 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); 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; } override size_t waiterCount() { return m_waiterCount + m_timers.pendingCount; }
package void addWaiter() { m_waiterCount++; } package void addWaiter() @nogc { m_waiterCount++; }
package void removeWaiter() package void removeWaiter()
{ @nogc {
assert(m_waiterCount > 0, "Decrementing waiter count below zero."); assert(m_waiterCount > 0, "Decrementing waiter count below zero.");
m_waiterCount--; m_waiterCount--;
} }
@ -159,7 +169,7 @@ final class WinAPIEventDriverCore : EventDriverCore {
bool got_event; bool got_event;
DWORD timeout_msecs = max_wait == Duration.max ? INFINITE : cast(DWORD)min(max(max_wait.total!"msecs", 0), DWORD.max); 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); } (); timeout_msecs, QS_ALLEVENTS, MWMO_ALERTABLE|MWMO_INPUTAVAILABLE); } ();
while (!m_ioEvents.empty) { while (!m_ioEvents.empty) {
@ -168,9 +178,9 @@ final class WinAPIEventDriverCore : EventDriverCore {
} }
if (ret == WAIT_IO_COMPLETION) got_event = true; if (ret == WAIT_IO_COMPLETION) got_event = true;
else if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + m_registeredEvents.length) { else if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + m_registeredEventCount) {
if (auto pc = m_registeredEvents[ret - WAIT_OBJECT_0] in m_eventCallbacks) { if (auto cb = m_registeredEventCallbacks[ret - WAIT_OBJECT_0]) {
(*pc)(); cb();
got_event = true; got_event = true;
} }
} }
@ -209,9 +219,11 @@ final class WinAPIEventDriverCore : EventDriverCore {
package void registerEvent(HANDLE event, void delegate() @safe nothrow callback = null) package void registerEvent(HANDLE event, void delegate() @safe nothrow callback = null)
{ @nogc {
m_registeredEvents ~= event; assert(m_registeredEventCount < MAXIMUM_WAIT_OBJECTS, "Too many registered events.");
if (callback) m_eventCallbacks[event] = callback; m_registeredEvents[m_registeredEventCount] = event;
if (callback) m_registeredEventCallbacks[m_registeredEventCount] = callback;
m_registeredEventCount++;
} }
package SlotType* setupSlot(SlotType)(HANDLE h) package SlotType* setupSlot(SlotType)(HANDLE h)
@ -231,7 +243,7 @@ final class WinAPIEventDriverCore : EventDriverCore {
} }
package void discardEvents(scope OVERLAPPED_CORE*[] overlapped...) package void discardEvents(scope OVERLAPPED_CORE*[] overlapped...)
{ @nogc {
import std.algorithm.searching : canFind; import std.algorithm.searching : canFind;
m_ioEvents.filterPending!(evt => !overlapped.canFind(evt.overlapped)); 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.signals;
import eventcore.drivers.winapi.sockets; import eventcore.drivers.winapi.sockets;
import eventcore.drivers.winapi.watchers; import eventcore.drivers.winapi.watchers;
import eventcore.internal.utils : mallocT, freeT;
import core.sys.windows.windows; import core.sys.windows.windows;
static assert(HANDLE.sizeof <= FD.BaseType.sizeof); static assert(HANDLE.sizeof <= FD.BaseType.sizeof);
@ -39,23 +40,25 @@ final class WinAPIEventDriver : EventDriver {
static WinAPIEventDriver threadInstance; static WinAPIEventDriver threadInstance;
this() this()
@safe { @safe nothrow @nogc {
assert(threadInstance is null); assert(threadInstance is null);
threadInstance = this; threadInstance = this;
import std.exception : enforce; import std.exception : enforce;
WSADATA wd; WSADATA wd;
enforce(() @trusted { return WSAStartup(0x0202, &wd); } () == 0, "Failed to initialize WinSock");
m_signals = new WinAPIEventDriverSignals(); auto res = () @trusted { return WSAStartup(0x0202, &wd); } ();
m_timers = new LoopTimeoutTimerDriver(); assert(res == 0, "Failed to initialize WinSock");
m_core = new WinAPIEventDriverCore(m_timers);
m_events = new WinAPIEventDriverEvents(m_core); m_signals = mallocT!WinAPIEventDriverSignals();
m_files = new WinAPIEventDriverFiles(m_core); m_timers = mallocT!LoopTimeoutTimerDriver();
m_sockets = new WinAPIEventDriverSockets(m_core); m_core = mallocT!WinAPIEventDriverCore(m_timers);
m_dns = new WinAPIEventDriverDNS(); m_events = mallocT!WinAPIEventDriverEvents(m_core);
m_watchers = new WinAPIEventDriverWatchers(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: @safe: /*@nogc:*/ nothrow:
@ -75,8 +78,20 @@ final class WinAPIEventDriver : EventDriver {
{ {
if (!m_events) return; if (!m_events) return;
m_events.dispose(); m_events.dispose();
m_events = null; m_core.dispose();
assert(threadInstance !is null); assert(threadInstance !is null);
threadInstance = 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.drivers.winapi.core;
import eventcore.internal.win32; import eventcore.internal.win32;
import eventcore.internal.consumablequeue; import eventcore.internal.consumablequeue;
import eventcore.internal.utils : nogc_assert; import eventcore.internal.utils : mallocT, freeT, nogc_assert;
final class WinAPIEventDriverEvents : EventDriverEvents { final class WinAPIEventDriverEvents : EventDriverEvents {
@ -31,10 +31,10 @@ final class WinAPIEventDriverEvents : EventDriverEvents {
} }
this(WinAPIEventDriverCore core) this(WinAPIEventDriverCore core)
{ @nogc {
m_core = core; m_core = core;
m_event = () @trusted { return CreateEvent(null, false, false, null); } (); 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); InitializeCriticalSection(&m_mutex);
m_core.registerEvent(m_event, &triggerPending); m_core.registerEvent(m_event, &triggerPending);
} }
@ -42,7 +42,7 @@ final class WinAPIEventDriverEvents : EventDriverEvents {
void dispose() void dispose()
@trusted { @trusted {
scope (failure) assert(false); scope (failure) assert(false);
destroy(m_pending); freeT(m_pending);
} }
override EventID create() override EventID create()

View file

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

View file

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

View file

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