Make the Posix driver initialization nogc.
This commit is contained in:
parent
a4eaafce9a
commit
e7e4a0f5f5
|
@ -352,13 +352,31 @@ interface EventDriverSockets {
|
||||||
|
|
||||||
/** Retrieves a reference to a user-defined value associated with a descriptor.
|
/** Retrieves a reference to a user-defined value associated with a descriptor.
|
||||||
*/
|
*/
|
||||||
@property final ref T userData(T, FD)(FD descriptor)
|
@property final ref T userData(T, FD)(FD descriptor) @trusted
|
||||||
@trusted {
|
if (!hasNoGCLifetime!T)
|
||||||
|
{
|
||||||
import std.conv : emplace;
|
import std.conv : emplace;
|
||||||
static void init(void* ptr) { emplace(cast(T*)ptr); }
|
static void init(void* ptr) { emplace(cast(T*)ptr); }
|
||||||
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
|
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
|
||||||
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
|
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
|
||||||
}
|
}
|
||||||
|
/// ditto
|
||||||
|
@property final ref T userData(T, FD)(FD descriptor) @trusted @nogc
|
||||||
|
if (hasNoGCLifetime!T)
|
||||||
|
{
|
||||||
|
import std.conv : emplace;
|
||||||
|
static void init(void* ptr) @nogc { emplace(cast(T*)ptr); }
|
||||||
|
static void destr(void* ptr) @nogc { destroy(*cast(T*)ptr); }
|
||||||
|
|
||||||
|
scope getter = {
|
||||||
|
return cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
|
||||||
|
};
|
||||||
|
|
||||||
|
static if (__traits(compiles, () nothrow @trusted { getter(); }))
|
||||||
|
return *(cast(T* delegate() @nogc nothrow)getter)();
|
||||||
|
else
|
||||||
|
return *(cast(T* delegate() @nogc)getter)();
|
||||||
|
}
|
||||||
|
|
||||||
/// Low-level user data access. Use `getUserData` instead.
|
/// Low-level user data access. Use `getUserData` instead.
|
||||||
protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
|
protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
|
||||||
|
@ -368,6 +386,14 @@ interface EventDriverSockets {
|
||||||
protected void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
|
protected void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum hasNoGCLifetime(T) = __traits(compiles, () @nogc @trusted { import std.conv : emplace; T b = void; emplace!T(&b); destroy(b); });
|
||||||
|
unittest {
|
||||||
|
static struct S1 {}
|
||||||
|
static struct S2 { ~this() { new int; } }
|
||||||
|
static assert(hasNoGCLifetime!S1);
|
||||||
|
static assert(!hasNoGCLifetime!S2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Performs asynchronous DNS queries.
|
/** Performs asynchronous DNS queries.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -43,7 +43,7 @@ final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriver
|
||||||
}
|
}
|
||||||
|
|
||||||
this(Events events, Signals signals)
|
this(Events events, Signals signals)
|
||||||
{
|
@nogc {
|
||||||
m_events = events;
|
m_events = events;
|
||||||
setupEvent();
|
setupEvent();
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriver
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupEvent()
|
private void setupEvent()
|
||||||
{
|
@nogc {
|
||||||
if (m_event == EventID.invalid) {
|
if (m_event == EventID.invalid) {
|
||||||
m_event = m_events.createInternal();
|
m_event = m_events.createInternal();
|
||||||
m_events.wait(m_event, &onDNSSignal);
|
m_events.wait(m_event, &onDNSSignal);
|
||||||
|
|
|
@ -64,16 +64,16 @@ final class PosixEventDriver(Loop : PosixEventLoop) : EventDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
this()
|
this()
|
||||||
{
|
@nogc @trusted {
|
||||||
m_loop = new Loop;
|
m_loop = mallocT!Loop;
|
||||||
m_sockets = new SocketsDriver(m_loop);
|
m_sockets = mallocT!SocketsDriver(m_loop);
|
||||||
m_events = new EventsDriver(m_loop, m_sockets);
|
m_events = mallocT!EventsDriver(m_loop, m_sockets);
|
||||||
m_signals = new SignalsDriver(m_loop);
|
m_signals = mallocT!SignalsDriver(m_loop);
|
||||||
m_timers = new TimerDriver;
|
m_timers = mallocT!TimerDriver;
|
||||||
m_core = new CoreDriver(m_loop, m_timers, m_events);
|
m_core = mallocT!CoreDriver(m_loop, m_timers, m_events);
|
||||||
m_dns = new DNSDriver(m_events, m_signals);
|
m_dns = mallocT!DNSDriver(m_events, m_signals);
|
||||||
m_files = new FileDriver(m_events);
|
m_files = mallocT!FileDriver(m_events);
|
||||||
m_watchers = new WatcherDriver(m_events);
|
m_watchers = mallocT!WatcherDriver(m_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
// force overriding these in the (final) sub classes to avoid virtual calls
|
// force overriding these in the (final) sub classes to avoid virtual calls
|
||||||
|
@ -96,6 +96,19 @@ final class PosixEventDriver(Loop : PosixEventLoop) : EventDriver {
|
||||||
m_core.dispose();
|
m_core.dispose();
|
||||||
m_loop.dispose();
|
m_loop.dispose();
|
||||||
m_loop = null;
|
m_loop = null;
|
||||||
|
|
||||||
|
try () @trusted {
|
||||||
|
freeT(m_watchers);
|
||||||
|
freeT(m_files);
|
||||||
|
freeT(m_dns);
|
||||||
|
freeT(m_core);
|
||||||
|
freeT(m_timers);
|
||||||
|
freeT(m_signals);
|
||||||
|
freeT(m_events);
|
||||||
|
freeT(m_sockets);
|
||||||
|
freeT(m_loop);
|
||||||
|
} ();
|
||||||
|
catch (Exception e) assert(false, e.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,29 +134,32 @@ final class PosixEventDriverCore(Loop : PosixEventLoop, Timers : EventDriverTime
|
||||||
ConsumableQueue!(Tuple!(ThreadCallback, intptr_t)) m_threadCallbacks;
|
ConsumableQueue!(Tuple!(ThreadCallback, intptr_t)) m_threadCallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected this(Loop loop, Timers timers, Events events)
|
this(Loop loop, Timers timers, Events events)
|
||||||
{
|
@nogc {
|
||||||
m_loop = loop;
|
m_loop = loop;
|
||||||
m_timers = timers;
|
m_timers = timers;
|
||||||
m_events = events;
|
m_events = events;
|
||||||
m_wakeupEvent = events.createInternal();
|
m_wakeupEvent = events.createInternal();
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void dispose()
|
final void dispose()
|
||||||
{
|
{
|
||||||
executeThreadCallbacks();
|
executeThreadCallbacks();
|
||||||
m_events.releaseRef(m_wakeupEvent);
|
m_events.releaseRef(m_wakeupEvent);
|
||||||
atomicStore(m_threadCallbackMutex, null);
|
|
||||||
m_wakeupEvent = EventID.invalid; // FIXME: this needs to be synchronized!
|
m_wakeupEvent = EventID.invalid; // FIXME: this needs to be synchronized!
|
||||||
|
try {
|
||||||
|
() @trusted { freeT(m_threadCallbackMutex); } ();
|
||||||
|
() @trusted { freeT(m_threadCallbacks); } ();
|
||||||
|
} catch (Exception e) assert(false, e.msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@property size_t waiterCount() const { return m_loop.m_waiterCount + m_timers.pendingCount; }
|
@property size_t waiterCount() const { return m_loop.m_waiterCount + m_timers.pendingCount; }
|
||||||
|
@ -274,11 +290,11 @@ package class PosixEventLoop {
|
||||||
protected abstract bool doProcessEvents(Duration dur);
|
protected abstract bool doProcessEvents(Duration dur);
|
||||||
|
|
||||||
/// Registers the FD for general notification reception.
|
/// Registers the FD for general notification reception.
|
||||||
protected abstract void registerFD(FD fd, EventMask mask, bool edge_triggered = true);
|
protected abstract void registerFD(FD fd, EventMask mask, bool edge_triggered = true) @nogc;
|
||||||
/// Unregisters the FD for general notification reception.
|
/// Unregisters the FD for general notification reception.
|
||||||
protected abstract void unregisterFD(FD fd, EventMask mask);
|
protected abstract void unregisterFD(FD fd, EventMask mask) @nogc;
|
||||||
/// Updates the event mask to use for listening for notifications.
|
/// Updates the event mask to use for listening for notifications.
|
||||||
protected abstract void updateFD(FD fd, EventMask old_mask, EventMask new_mask, bool edge_triggered = true);
|
protected abstract void updateFD(FD fd, EventMask old_mask, EventMask new_mask, bool edge_triggered = true) @nogc;
|
||||||
|
|
||||||
final protected void notify(EventType evt)(FD fd)
|
final protected void notify(EventType evt)(FD fd)
|
||||||
{
|
{
|
||||||
|
@ -342,7 +358,7 @@ package class PosixEventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
package final void* rawUserDataImpl(size_t descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
|
package final void* rawUserDataImpl(size_t descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
|
||||||
@system {
|
@system @nogc {
|
||||||
FDSlot* fds = &m_fds[descriptor].common;
|
FDSlot* fds = &m_fds[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).");
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
numbers of concurrently open sockets.
|
numbers of concurrently open sockets.
|
||||||
*/
|
*/
|
||||||
module eventcore.drivers.posix.epoll;
|
module eventcore.drivers.posix.epoll;
|
||||||
@safe: /*@nogc:*/ nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
version (linux):
|
version (linux):
|
||||||
|
|
||||||
|
@ -22,17 +22,16 @@ static if (!is(typeof(SOCK_CLOEXEC)))
|
||||||
enum SOCK_CLOEXEC = 0x80000;
|
enum SOCK_CLOEXEC = 0x80000;
|
||||||
|
|
||||||
final class EpollEventLoop : PosixEventLoop {
|
final class EpollEventLoop : PosixEventLoop {
|
||||||
@safe: nothrow:
|
@safe nothrow:
|
||||||
|
|
||||||
private {
|
private {
|
||||||
int m_epoll;
|
int m_epoll;
|
||||||
epoll_event[] m_events;
|
epoll_event[100] m_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
this()
|
this()
|
||||||
{
|
@nogc {
|
||||||
m_epoll = () @trusted { return epoll_create1(SOCK_CLOEXEC); } ();
|
m_epoll = () @trusted { return epoll_create1(SOCK_CLOEXEC); } ();
|
||||||
m_events.length = 100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override bool doProcessEvents(Duration timeout)
|
override bool doProcessEvents(Duration timeout)
|
||||||
|
@ -60,7 +59,7 @@ final class EpollEventLoop : PosixEventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
override void dispose()
|
override void dispose()
|
||||||
{
|
@nogc {
|
||||||
import core.sys.posix.unistd : close;
|
import core.sys.posix.unistd : close;
|
||||||
close(m_epoll);
|
close(m_epoll);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ module eventcore.drivers.posix.events;
|
||||||
import eventcore.driver;
|
import eventcore.driver;
|
||||||
import eventcore.drivers.posix.driver;
|
import eventcore.drivers.posix.driver;
|
||||||
import eventcore.internal.consumablequeue : ConsumableQueue;
|
import eventcore.internal.consumablequeue : ConsumableQueue;
|
||||||
import eventcore.internal.utils : nogc_assert;
|
import eventcore.internal.utils : nogc_assert, mallocT, freeT;
|
||||||
|
|
||||||
|
|
||||||
version (linux) {
|
version (linux) {
|
||||||
nothrow @nogc extern (C) int eventfd(uint initval, int flags);
|
nothrow @nogc extern (C) int eventfd(uint initval, int flags);
|
||||||
|
@ -25,21 +26,12 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
Loop m_loop;
|
Loop m_loop;
|
||||||
Sockets m_sockets;
|
Sockets m_sockets;
|
||||||
ubyte[ulong.sizeof] m_buf;
|
ubyte[ulong.sizeof] m_buf;
|
||||||
version (linux) {}
|
|
||||||
else {
|
|
||||||
// TODO: avoid the overhead of a mutex backed map here
|
|
||||||
import core.sync.mutex : Mutex;
|
|
||||||
Mutex m_eventsMutex;
|
|
||||||
EventID[DatagramSocketFD] m_events;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this(Loop loop, Sockets sockets)
|
this(Loop loop, Sockets sockets)
|
||||||
{
|
@nogc {
|
||||||
m_loop = loop;
|
m_loop = loop;
|
||||||
m_sockets = sockets;
|
m_sockets = sockets;
|
||||||
version (linux) {}
|
|
||||||
else m_eventsMutex = new Mutex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
package @property Loop loop() { return m_loop; }
|
package @property Loop loop() { return m_loop; }
|
||||||
|
@ -50,14 +42,14 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
|
|
||||||
package(eventcore) EventID createInternal(bool is_internal = true)
|
package(eventcore) EventID createInternal(bool is_internal = true)
|
||||||
{
|
@nogc {
|
||||||
version (linux) {
|
version (linux) {
|
||||||
auto eid = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
auto eid = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||||
if (eid == -1) return EventID.invalid;
|
if (eid == -1) return EventID.invalid;
|
||||||
auto id = cast(EventID)eid;
|
auto id = cast(EventID)eid;
|
||||||
// FIXME: avoid dynamic memory allocation for the queue
|
// FIXME: avoid dynamic memory allocation for the queue
|
||||||
m_loop.initFD(id, FDFlags.internal,
|
m_loop.initFD(id, FDFlags.internal,
|
||||||
EventSlot(new ConsumableQueue!EventCallback, false, is_internal));
|
EventSlot(mallocT!(ConsumableQueue!EventCallback), false, is_internal));
|
||||||
m_loop.registerFD(id, EventMask.read);
|
m_loop.registerFD(id, EventMask.read);
|
||||||
m_loop.setNotifyCallback!(EventType.read)(id, &onEvent);
|
m_loop.setNotifyCallback!(EventType.read)(id, &onEvent);
|
||||||
releaseRef(id); // setNotifyCallback increments the reference count, but we need a value of 1 upon return
|
releaseRef(id); // setNotifyCallback increments the reference count, but we need a value of 1 upon return
|
||||||
|
@ -83,7 +75,7 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
} else {
|
} else {
|
||||||
// fake missing socketpair support on Windows
|
// fake missing socketpair support on Windows
|
||||||
import std.socket : InternetAddress;
|
import std.socket : InternetAddress;
|
||||||
auto addr = new InternetAddress(0x7F000001, 0);
|
scope addr = new InternetAddress(0x7F000001, 0);
|
||||||
auto s = m_sockets.createDatagramSocketInternal(addr, null, true);
|
auto s = m_sockets.createDatagramSocketInternal(addr, null, true);
|
||||||
if (s == DatagramSocketFD.invalid) return EventID.invalid;
|
if (s == DatagramSocketFD.invalid) return EventID.invalid;
|
||||||
fd[0] = cast(sock_t)s;
|
fd[0] = cast(sock_t)s;
|
||||||
|
@ -106,18 +98,16 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sockets.receive(s, m_buf, IOMode.once, &onSocketData);
|
m_sockets.receiveNoGC(s, m_buf, IOMode.once, &onSocketData);
|
||||||
|
|
||||||
// use the second socket as the event ID and as the sending end for
|
// use the second socket as the event ID and as the sending end for
|
||||||
// other threads
|
// other threads
|
||||||
auto id = cast(EventID)fd[1];
|
auto id = cast(EventID)fd[1];
|
||||||
try {
|
try m_sockets.userData!EventID(s) = id;
|
||||||
synchronized (m_eventsMutex)
|
catch (Exception e) assert(false, e.msg);
|
||||||
m_events[s] = id;
|
|
||||||
} catch (Exception e) assert(false, e.msg);
|
|
||||||
// FIXME: avoid dynamic memory allocation for the queue
|
// FIXME: avoid dynamic memory allocation for the queue
|
||||||
m_loop.initFD(id, FDFlags.internal,
|
m_loop.initFD(id, FDFlags.internal,
|
||||||
EventSlot(new ConsumableQueue!EventCallback, false, is_internal, s));
|
EventSlot(mallocT!(ConsumableQueue!EventCallback), false, is_internal, s));
|
||||||
assert(getRC(id) == 1);
|
assert(getRC(id) == 1);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +132,7 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void trigger(EventID event, bool notify_all)
|
final override void trigger(EventID event, bool notify_all)
|
||||||
shared @trusted {
|
shared @trusted @nogc {
|
||||||
import core.atomic : atomicStore;
|
import core.atomic : atomicStore;
|
||||||
auto thisus = cast(PosixEventDriverEvents)this;
|
auto thisus = cast(PosixEventDriverEvents)this;
|
||||||
assert(event < thisus.m_loop.m_fds.length, "Invalid event ID passed to shared triggerEvent.");
|
assert(event < thisus.m_loop.m_fds.length, "Invalid event ID passed to shared triggerEvent.");
|
||||||
|
@ -154,7 +144,7 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void wait(EventID event, EventCallback on_event)
|
final override void wait(EventID event, EventCallback on_event)
|
||||||
{
|
@nogc {
|
||||||
if (!isInternal(event)) m_loop.m_waiterCount++;
|
if (!isInternal(event)) m_loop.m_waiterCount++;
|
||||||
getSlot(event).waiters.put(on_event);
|
getSlot(event).waiters.put(on_event);
|
||||||
}
|
}
|
||||||
|
@ -183,13 +173,12 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
version (linux) {}
|
version (linux) {}
|
||||||
else {
|
else {
|
||||||
private void onSocketData(DatagramSocketFD s, IOStatus, size_t, scope RefAddress)
|
private void onSocketData(DatagramSocketFD s, IOStatus, size_t, scope RefAddress)
|
||||||
{
|
@nogc {
|
||||||
m_sockets.receive(s, m_buf, IOMode.once, &onSocketData);
|
m_sockets.receiveNoGC(s, m_buf, IOMode.once, &onSocketData);
|
||||||
EventID evt;
|
|
||||||
try {
|
try {
|
||||||
synchronized (m_eventsMutex)
|
EventID evt = m_sockets.userData!EventID(s);
|
||||||
evt = m_events[s];
|
scope doit = { onEvent(evt); }; // cast to nogc
|
||||||
onEvent(evt);
|
() @trusted { (cast(void delegate() @nogc)doit)(); } ();
|
||||||
} catch (Exception e) assert(false, e.msg);
|
} catch (Exception e) assert(false, e.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,13 +190,13 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
|
|
||||||
final override bool releaseRef(EventID descriptor)
|
final override bool releaseRef(EventID descriptor)
|
||||||
{
|
@nogc {
|
||||||
nogc_assert(getRC(descriptor) > 0, "Releasing reference to unreferenced event FD.");
|
nogc_assert(getRC(descriptor) > 0, "Releasing reference to unreferenced event FD.");
|
||||||
if (--getRC(descriptor) == 0) {
|
if (--getRC(descriptor) == 0) {
|
||||||
if (!isInternal(descriptor))
|
if (!isInternal(descriptor))
|
||||||
m_loop.m_waiterCount -= getSlot(descriptor).waiters.length;
|
m_loop.m_waiterCount -= getSlot(descriptor).waiters.length;
|
||||||
() @trusted nothrow {
|
() @trusted nothrow {
|
||||||
try .destroy(getSlot(descriptor).waiters);
|
try freeT(getSlot(descriptor).waiters);
|
||||||
catch (Exception e) nogc_assert(false, e.msg);
|
catch (Exception e) nogc_assert(false, e.msg);
|
||||||
} ();
|
} ();
|
||||||
version (linux) {
|
version (linux) {
|
||||||
|
@ -216,10 +205,6 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
auto rs = getSlot(descriptor).recvSocket;
|
auto rs = getSlot(descriptor).recvSocket;
|
||||||
m_sockets.cancelReceive(rs);
|
m_sockets.cancelReceive(rs);
|
||||||
m_sockets.releaseRef(rs);
|
m_sockets.releaseRef(rs);
|
||||||
try {
|
|
||||||
synchronized (m_eventsMutex)
|
|
||||||
m_events.remove(rs);
|
|
||||||
} catch (Exception e) nogc_assert(false, e.msg);
|
|
||||||
}
|
}
|
||||||
m_loop.clearFD!EventSlot(descriptor);
|
m_loop.clearFD!EventSlot(descriptor);
|
||||||
version (Posix) close(cast(int)descriptor);
|
version (Posix) close(cast(int)descriptor);
|
||||||
|
@ -235,9 +220,9 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventSlot* getSlot(EventID id)
|
private EventSlot* getSlot(EventID id)
|
||||||
{
|
@nogc {
|
||||||
nogc_assert(id < m_loop.m_fds.length, "Invalid event ID.");
|
nogc_assert(id < m_loop.m_fds.length, "Invalid event ID.");
|
||||||
return () @trusted { return &m_loop.m_fds[id].event(); } ();
|
return () @trusted @nogc { return &m_loop.m_fds[id].event(); } ();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ref uint getRC(EventID id)
|
private ref uint getRC(EventID id)
|
||||||
|
@ -246,7 +231,7 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool isInternal(EventID id)
|
private bool isInternal(EventID id)
|
||||||
{
|
@nogc {
|
||||||
return getSlot(id).isInternal;
|
return getSlot(id).isInternal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,14 +34,14 @@ alias KqueueEventDriver = PosixEventDriver!KqueueEventLoop;
|
||||||
final class KqueueEventLoop : PosixEventLoop {
|
final class KqueueEventLoop : PosixEventLoop {
|
||||||
private {
|
private {
|
||||||
int m_queue;
|
int m_queue;
|
||||||
kevent_t[] m_changes;
|
size_t m_changeCount = 0;
|
||||||
kevent_t[] m_events;
|
kevent_t[100] m_changes;
|
||||||
|
kevent_t[100] m_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
this()
|
this()
|
||||||
@safe nothrow {
|
@safe nothrow @nogc {
|
||||||
m_queue = () @trusted { return kqueue(); } ();
|
m_queue = () @trusted { return kqueue(); } ();
|
||||||
m_events.length = 100;
|
|
||||||
assert(m_queue >= 0, "Failed to create kqueue.");
|
assert(m_queue >= 0, "Failed to create kqueue.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,8 @@ final class KqueueEventLoop : PosixEventLoop {
|
||||||
ts.tv_sec = cast(time_t)secs;
|
ts.tv_sec = cast(time_t)secs;
|
||||||
ts.tv_nsec = cast(uint)hnsecs * 100;
|
ts.tv_nsec = cast(uint)hnsecs * 100;
|
||||||
|
|
||||||
auto ret = kevent(m_queue, m_changes.ptr, cast(int)m_changes.length, m_events.ptr, cast(int)m_events.length, timeout == Duration.max ? null : &ts);
|
auto ret = kevent(m_queue, m_changes.ptr, cast(int)m_changeCount, m_events.ptr, cast(int)m_events.length, timeout == Duration.max ? null : &ts);
|
||||||
m_changes.length = 0;
|
m_changeCount = 0;
|
||||||
m_changes.assumeSafeAppend();
|
|
||||||
|
|
||||||
//print("kevent returned %s", ret);
|
//print("kevent returned %s", ret);
|
||||||
|
|
||||||
|
@ -97,11 +96,11 @@ final class KqueueEventLoop : PosixEventLoop {
|
||||||
if (edge_triggered) ev.flags |= EV_CLEAR;
|
if (edge_triggered) ev.flags |= EV_CLEAR;
|
||||||
if (mask & EventMask.read) {
|
if (mask & EventMask.read) {
|
||||||
ev.filter = EVFILT_READ;
|
ev.filter = EVFILT_READ;
|
||||||
m_changes ~= ev;
|
putChange(ev);
|
||||||
}
|
}
|
||||||
if (mask & EventMask.write) {
|
if (mask & EventMask.write) {
|
||||||
ev.filter = EVFILT_WRITE;
|
ev.filter = EVFILT_WRITE;
|
||||||
m_changes ~= ev;
|
putChange(ev);
|
||||||
}
|
}
|
||||||
//if (mask & EventMask.status) ev.events |= EPOLLERR|EPOLLRDHUP;
|
//if (mask & EventMask.status) ev.events |= EPOLLERR|EPOLLRDHUP;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +110,7 @@ final class KqueueEventLoop : PosixEventLoop {
|
||||||
kevent_t ev;
|
kevent_t ev;
|
||||||
ev.ident = fd;
|
ev.ident = fd;
|
||||||
ev.flags = EV_DELETE;
|
ev.flags = EV_DELETE;
|
||||||
m_changes ~= ev;
|
putChange(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void updateFD(FD fd, EventMask old_mask, EventMask new_mask, bool edge_triggered = true)
|
override void updateFD(FD fd, EventMask old_mask, EventMask new_mask, bool edge_triggered = true)
|
||||||
|
@ -124,16 +123,26 @@ final class KqueueEventLoop : PosixEventLoop {
|
||||||
ev.filter = EVFILT_READ;
|
ev.filter = EVFILT_READ;
|
||||||
ev.flags = new_mask & EventMask.read ? EV_ADD : EV_DELETE;
|
ev.flags = new_mask & EventMask.read ? EV_ADD : EV_DELETE;
|
||||||
if (edge_triggered) ev.flags |= EV_CLEAR;
|
if (edge_triggered) ev.flags |= EV_CLEAR;
|
||||||
m_changes ~= ev;
|
putChange(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changes & EventMask.write) {
|
if (changes & EventMask.write) {
|
||||||
ev.filter = EVFILT_WRITE;
|
ev.filter = EVFILT_WRITE;
|
||||||
ev.flags = new_mask & EventMask.write ? EV_ADD : EV_DELETE;
|
ev.flags = new_mask & EventMask.write ? EV_ADD : EV_DELETE;
|
||||||
if (edge_triggered) ev.flags |= EV_CLEAR;
|
if (edge_triggered) ev.flags |= EV_CLEAR;
|
||||||
m_changes ~= ev;
|
putChange(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (mask & EventMask.status) ev.events |= EPOLLERR|EPOLLRDHUP;
|
//if (mask & EventMask.status) ev.events |= EPOLLERR|EPOLLRDHUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void putChange(ref kevent_t ev)
|
||||||
|
@safe nothrow @nogc {
|
||||||
|
m_changes[m_changeCount++] = ev;
|
||||||
|
if (m_changeCount == m_changes.length) {
|
||||||
|
auto ret = (() @trusted => kevent(m_queue, &m_changes[0], cast(int)m_changes.length, null, 0, null)) ();
|
||||||
|
assert(ret == 0);
|
||||||
|
m_changeCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ final class SignalFDEventDriverSignals(Loop : PosixEventLoop) : EventDriverSigna
|
||||||
|
|
||||||
private Loop m_loop;
|
private Loop m_loop;
|
||||||
|
|
||||||
this(Loop loop) { m_loop = loop; }
|
this(Loop loop) @nogc { m_loop = loop; }
|
||||||
|
|
||||||
override SignalListenID listen(int sig, SignalCallback on_signal)
|
override SignalListenID listen(int sig, SignalCallback on_signal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -654,7 +654,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
}
|
}
|
||||||
|
|
||||||
package DatagramSocketFD adoptDatagramSocketInternal(int socket, bool is_internal = true, bool close_on_exec = false)
|
package DatagramSocketFD adoptDatagramSocketInternal(int socket, bool is_internal = true, bool close_on_exec = false)
|
||||||
{
|
@nogc {
|
||||||
auto fd = DatagramSocketFD(socket);
|
auto fd = DatagramSocketFD(socket);
|
||||||
if (m_loop.m_fds[fd].common.refCount) // FD already in use?
|
if (m_loop.m_fds[fd].common.refCount) // FD already in use?
|
||||||
return DatagramSocketFD.init;
|
return DatagramSocketFD.init;
|
||||||
|
@ -742,8 +742,16 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
on_receive_finish(socket, IOStatus.ok, ret, src_addrc);
|
on_receive_finish(socket, IOStatus.ok, ret, src_addrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
package void receiveNoGC(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, void delegate(DatagramSocketFD, IOStatus, size_t, scope RefAddress) @safe nothrow @nogc on_receive_finish)
|
||||||
|
@trusted @nogc {
|
||||||
|
scope void delegate() @safe nothrow do_it = {
|
||||||
|
receive(socket, buffer, mode, on_receive_finish);
|
||||||
|
};
|
||||||
|
(cast(void delegate() @safe nothrow @nogc)do_it)();
|
||||||
|
}
|
||||||
|
|
||||||
void cancelReceive(DatagramSocketFD socket)
|
void cancelReceive(DatagramSocketFD socket)
|
||||||
{
|
@nogc {
|
||||||
assert(m_loop.m_fds[socket].datagramSocket.readCallback !is null, "Cancelling read when there is no read in progress.");
|
assert(m_loop.m_fds[socket].datagramSocket.readCallback !is null, "Cancelling read when there is no read in progress.");
|
||||||
m_loop.setNotifyCallback!(EventType.read)(socket, null);
|
m_loop.setNotifyCallback!(EventType.read)(socket, null);
|
||||||
m_loop.m_fds[socket].datagramSocket.readBuffer = null;
|
m_loop.m_fds[socket].datagramSocket.readBuffer = null;
|
||||||
|
@ -855,7 +863,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
}
|
}
|
||||||
|
|
||||||
final override bool releaseRef(SocketFD fd)
|
final override bool releaseRef(SocketFD fd)
|
||||||
{
|
@nogc {
|
||||||
import taggedalgebraic : hasType;
|
import taggedalgebraic : hasType;
|
||||||
auto slot = () @trusted { return &m_loop.m_fds[fd]; } ();
|
auto slot = () @trusted { return &m_loop.m_fds[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.");
|
||||||
|
|
|
@ -245,7 +245,7 @@ final class PollEventDriverWatchers(Events : EventDriverEvents) : EventDriverWat
|
||||||
}
|
}
|
||||||
|
|
||||||
this(Events events)
|
this(Events events)
|
||||||
{
|
@nogc {
|
||||||
m_events = events;
|
m_events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue