Merge pull request #132 from vibe-d/connect_callback_fix
Ensure that only the connect or the connection error callback is ever triggered. merged-on-behalf-of: Leonid Kramer <l-kramer@users.noreply.github.com>
This commit is contained in:
commit
608f60237f
|
@ -153,3 +153,4 @@ test_script:
|
||||||
- echo %PATH%
|
- echo %PATH%
|
||||||
- '%DC% --version'
|
- '%DC% --version'
|
||||||
- dub test --arch=%Darch% --compiler=%DC% --config=%CONFIG%
|
- dub test --arch=%Darch% --compiler=%DC% --config=%CONFIG%
|
||||||
|
- for %%i in (tests\*.d) do echo %%i && dub --single %%i --arch=%Darch% --compiler=%DC% --override-config eventcore/%CONFIG% || exit /B 1
|
||||||
|
|
|
@ -19,6 +19,7 @@ import eventcore.drivers.threadedfile;
|
||||||
import eventcore.internal.consumablequeue : ConsumableQueue;
|
import eventcore.internal.consumablequeue : ConsumableQueue;
|
||||||
import eventcore.internal.utils;
|
import eventcore.internal.utils;
|
||||||
|
|
||||||
|
import core.time : MonoTime;
|
||||||
import std.algorithm.comparison : among, min, max;
|
import std.algorithm.comparison : among, min, max;
|
||||||
|
|
||||||
version (Posix) {
|
version (Posix) {
|
||||||
|
@ -221,17 +222,17 @@ final class PosixEventDriverCore(Loop : PosixEventLoop, Timers : EventDriverTime
|
||||||
|
|
||||||
if (timeout <= 0.seconds) {
|
if (timeout <= 0.seconds) {
|
||||||
got_events = m_loop.doProcessEvents(0.seconds);
|
got_events = m_loop.doProcessEvents(0.seconds);
|
||||||
m_timers.process(currStdTime);
|
m_timers.process(MonoTime.currTime);
|
||||||
} else {
|
} else {
|
||||||
long now = currStdTime;
|
auto now = MonoTime.currTime;
|
||||||
do {
|
do {
|
||||||
auto nextto = max(min(m_timers.getNextTimeout(now), timeout), 0.seconds);
|
auto nextto = max(min(m_timers.getNextTimeout(now), timeout), 0.seconds);
|
||||||
got_events = m_loop.doProcessEvents(nextto);
|
got_events = m_loop.doProcessEvents(nextto);
|
||||||
long prev_step = now;
|
auto prev_step = now;
|
||||||
now = currStdTime;
|
now = MonoTime.currTime;
|
||||||
got_events |= m_timers.process(now);
|
got_events |= m_timers.process(now);
|
||||||
if (timeout != Duration.max)
|
if (timeout != Duration.max)
|
||||||
timeout -= (now - prev_step).hnsecs;
|
timeout -= now - prev_step;
|
||||||
} while (timeout > 0.seconds && !m_exit && !got_events);
|
} while (timeout > 0.seconds && !m_exit && !got_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ version (Posix) {
|
||||||
import core.sys.posix.netinet.tcp;
|
import core.sys.posix.netinet.tcp;
|
||||||
import core.sys.posix.sys.un;
|
import core.sys.posix.sys.un;
|
||||||
import core.sys.posix.unistd : close, read, write;
|
import core.sys.posix.unistd : close, read, write;
|
||||||
import core.stdc.errno : errno, EAGAIN, EINPROGRESS;
|
import core.stdc.errno : errno, EAGAIN, EINPROGRESS, ECONNREFUSED;
|
||||||
import core.sys.posix.fcntl;
|
import core.sys.posix.fcntl;
|
||||||
import core.sys.posix.sys.socket;
|
import core.sys.posix.sys.socket;
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ version (Windows) {
|
||||||
import core.sys.windows.winsock2;
|
import core.sys.windows.winsock2;
|
||||||
alias sockaddr_storage = SOCKADDR_STORAGE;
|
alias sockaddr_storage = SOCKADDR_STORAGE;
|
||||||
alias EAGAIN = WSAEWOULDBLOCK;
|
alias EAGAIN = WSAEWOULDBLOCK;
|
||||||
|
alias ECONNREFUSED = WSAECONNREFUSED;
|
||||||
enum SHUT_RDWR = SD_BOTH;
|
enum SHUT_RDWR = SD_BOTH;
|
||||||
enum SHUT_RD = SD_RECEIVE;
|
enum SHUT_RD = SD_RECEIVE;
|
||||||
enum SHUT_WR = SD_SEND;
|
enum SHUT_WR = SD_SEND;
|
||||||
|
@ -138,9 +139,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loop.initFD(sock, FDFlags.none, StreamSocketSlot.init);
|
m_loop.initFD(sock, FDFlags.none, StreamSocketSlot.init);
|
||||||
m_loop.registerFD(sock, EventMask.read|EventMask.write|EventMask.status);
|
m_loop.registerFD(sock, EventMask.read|EventMask.write);
|
||||||
m_loop.setNotifyCallback!(EventType.status)(sock, &onConnectError);
|
|
||||||
releaseRef(sock); // onConnectError callback is weak reference
|
|
||||||
|
|
||||||
auto ret = () @trusted { return connect(cast(sock_t)sock, address.name, address.nameLen); } ();
|
auto ret = () @trusted { return connect(cast(sock_t)sock, address.name, address.nameLen); } ();
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
@ -155,10 +154,10 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
}
|
}
|
||||||
m_loop.setNotifyCallback!(EventType.write)(sock, &onConnect);
|
m_loop.setNotifyCallback!(EventType.write)(sock, &onConnect);
|
||||||
} else {
|
} else {
|
||||||
|
m_loop.unregisterFD(sock, EventMask.read|EventMask.write);
|
||||||
m_loop.clearFD!StreamSocketSlot(sock);
|
m_loop.clearFD!StreamSocketSlot(sock);
|
||||||
m_loop.unregisterFD(sock, EventMask.read|EventMask.write|EventMask.status);
|
|
||||||
invalidateSocket();
|
invalidateSocket();
|
||||||
on_connect(StreamSocketFD.invalid, ConnectStatus.unknownError);
|
on_connect(StreamSocketFD.invalid, determineConnectStatus(err));
|
||||||
return StreamSocketFD.invalid;
|
return StreamSocketFD.invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,11 +174,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
"Unable to cancel connect on the socket that is not in connecting state");
|
"Unable to cancel connect on the socket that is not in connecting state");
|
||||||
state = ConnectionState.closed;
|
state = ConnectionState.closed;
|
||||||
connectCallback = null;
|
connectCallback = null;
|
||||||
m_loop.setNotifyCallback!(EventType.status)(sock, null);
|
|
||||||
m_loop.setNotifyCallback!(EventType.write)(sock, null);
|
m_loop.setNotifyCallback!(EventType.write)(sock, null);
|
||||||
m_loop.clearFD!StreamSocketSlot(sock);
|
|
||||||
m_loop.unregisterFD(sock, EventMask.read|EventMask.write|EventMask.status);
|
|
||||||
closeSocket(cast(sock_t)sock.value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +185,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
return StreamSocketFD.invalid;
|
return StreamSocketFD.invalid;
|
||||||
setSocketNonBlocking(fd);
|
setSocketNonBlocking(fd);
|
||||||
m_loop.initFD(fd, FDFlags.none, StreamSocketSlot.init);
|
m_loop.initFD(fd, FDFlags.none, StreamSocketSlot.init);
|
||||||
m_loop.registerFD(fd, EventMask.read|EventMask.write|EventMask.status);
|
m_loop.registerFD(fd, EventMask.read|EventMask.write);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,22 +194,32 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
auto sock = cast(StreamSocketFD)fd;
|
auto sock = cast(StreamSocketFD)fd;
|
||||||
auto l = lockHandle(sock);
|
auto l = lockHandle(sock);
|
||||||
m_loop.setNotifyCallback!(EventType.write)(sock, null);
|
m_loop.setNotifyCallback!(EventType.write)(sock, null);
|
||||||
|
|
||||||
|
ConnectStatus status = ConnectStatus.unknownError;
|
||||||
|
int err;
|
||||||
|
socklen_t errlen = err.sizeof;
|
||||||
|
if (() @trusted { return getsockopt(cast(sock_t)fd, SOL_SOCKET, SO_ERROR, &err, &errlen); } () == 0)
|
||||||
|
status = determineConnectStatus(err);
|
||||||
|
|
||||||
with (m_loop.m_fds[sock].streamSocket) {
|
with (m_loop.m_fds[sock].streamSocket) {
|
||||||
state = ConnectionState.connected;
|
assert(state == ConnectionState.connecting);
|
||||||
|
|
||||||
|
state = status == ConnectStatus.connected
|
||||||
|
? ConnectionState.connected
|
||||||
|
: ConnectionState.closed;
|
||||||
|
|
||||||
auto cb = connectCallback;
|
auto cb = connectCallback;
|
||||||
connectCallback = null;
|
connectCallback = null;
|
||||||
if (cb) cb(sock, ConnectStatus.connected);
|
if (cb) cb(cast(StreamSocketFD)sock, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onConnectError(FD sock)
|
private ConnectStatus determineConnectStatus(int sock_err)
|
||||||
{
|
{
|
||||||
// FIXME: determine the correct kind of error!
|
switch (sock_err) {
|
||||||
with (m_loop.m_fds[sock].streamSocket) {
|
default: return ConnectStatus.unknownError;
|
||||||
state = ConnectionState.closed;
|
case 0: return ConnectStatus.connected;
|
||||||
auto cb = connectCallback;
|
case ECONNREFUSED: return ConnectStatus.refused;
|
||||||
connectCallback = null;
|
|
||||||
if (cb) cb(cast(StreamSocketFD)sock, ConnectStatus.refused);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,9 +292,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
auto fd = cast(StreamSocketFD)sockfd;
|
auto fd = cast(StreamSocketFD)sockfd;
|
||||||
m_loop.initFD(fd, FDFlags.none, StreamSocketSlot.init);
|
m_loop.initFD(fd, FDFlags.none, StreamSocketSlot.init);
|
||||||
m_loop.m_fds[fd].streamSocket.state = ConnectionState.connected;
|
m_loop.m_fds[fd].streamSocket.state = ConnectionState.connected;
|
||||||
m_loop.registerFD(fd, EventMask.read|EventMask.write|EventMask.status);
|
m_loop.registerFD(fd, EventMask.read|EventMask.write);
|
||||||
m_loop.setNotifyCallback!(EventType.status)(fd, &onConnectError);
|
|
||||||
releaseRef(fd); // onConnectError callback is weak reference
|
|
||||||
//print("accept %d", sockfd);
|
//print("accept %d", sockfd);
|
||||||
scope RefAddress addrc = new RefAddress(() @trusted { return cast(sockaddr*)&addr; } (), addr_len);
|
scope RefAddress addrc = new RefAddress(() @trusted { return cast(sockaddr*)&addr; } (), addr_len);
|
||||||
m_loop.m_fds[listenfd].streamListen.acceptCallback(cast(StreamListenSocketFD)listenfd, fd, addrc);
|
m_loop.m_fds[listenfd].streamListen.acceptCallback(cast(StreamListenSocketFD)listenfd, fd, addrc);
|
||||||
|
@ -656,7 +659,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loop.initFD(sock, is_internal ? FDFlags.internal : FDFlags.none, DgramSocketSlot.init);
|
m_loop.initFD(sock, is_internal ? FDFlags.internal : FDFlags.none, DgramSocketSlot.init);
|
||||||
m_loop.registerFD(sock, EventMask.read|EventMask.write|EventMask.status);
|
m_loop.registerFD(sock, EventMask.read|EventMask.write);
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
@ -673,7 +676,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
return DatagramSocketFD.init;
|
return DatagramSocketFD.init;
|
||||||
setSocketNonBlocking(fd, close_on_exec);
|
setSocketNonBlocking(fd, close_on_exec);
|
||||||
m_loop.initFD(fd, is_internal ? FDFlags.internal : FDFlags.none, DgramSocketSlot.init);
|
m_loop.initFD(fd, is_internal ? FDFlags.internal : FDFlags.none, DgramSocketSlot.init);
|
||||||
m_loop.registerFD(fd, EventMask.read|EventMask.write|EventMask.status);
|
m_loop.registerFD(fd, EventMask.read|EventMask.write);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,7 +884,7 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
|
||||||
// listening sockets have an incremented the reference count because of setNotifyCallback
|
// listening sockets have an incremented the reference count because of setNotifyCallback
|
||||||
int base_refcount = slot.specific.hasType!StreamListenSocketSlot ? 1 : 0;
|
int base_refcount = slot.specific.hasType!StreamListenSocketSlot ? 1 : 0;
|
||||||
if (--slot.common.refCount == base_refcount) {
|
if (--slot.common.refCount == base_refcount) {
|
||||||
m_loop.unregisterFD(fd, EventMask.read|EventMask.write|EventMask.status);
|
m_loop.unregisterFD(fd, EventMask.read|EventMask.write);
|
||||||
switch (slot.specific.kind) with (slot.specific.Kind) {
|
switch (slot.specific.kind) with (slot.specific.Kind) {
|
||||||
default: assert(false, "File descriptor slot is not a socket.");
|
default: assert(false, "File descriptor slot is not a socket.");
|
||||||
case streamSocket:
|
case streamSocket:
|
||||||
|
|
|
@ -7,7 +7,7 @@ import eventcore.driver;
|
||||||
import eventcore.internal.consumablequeue;
|
import eventcore.internal.consumablequeue;
|
||||||
import eventcore.internal.dlist;
|
import eventcore.internal.dlist;
|
||||||
import eventcore.internal.utils : mallocT, freeT, nogc_assert;
|
import eventcore.internal.utils : mallocT, freeT, nogc_assert;
|
||||||
|
import core.time : Duration, MonoTime, hnsecs;
|
||||||
|
|
||||||
final class LoopTimeoutTimerDriver : EventDriverTimers {
|
final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
import std.experimental.allocator.building_blocks.free_list;
|
import std.experimental.allocator.building_blocks.free_list;
|
||||||
|
@ -17,7 +17,6 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
import std.container.array;
|
import std.container.array;
|
||||||
import std.datetime : Clock;
|
import std.datetime : Clock;
|
||||||
import std.range : SortedRange, assumeSorted, take;
|
import std.range : SortedRange, assumeSorted, take;
|
||||||
import core.time : hnsecs, Duration;
|
|
||||||
import core.memory : GC;
|
import core.memory : GC;
|
||||||
|
|
||||||
private {
|
private {
|
||||||
|
@ -46,24 +45,22 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
|
|
||||||
package @property size_t pendingCount() const @safe nothrow { return m_timerQueue.length; }
|
package @property size_t pendingCount() const @safe nothrow { return m_timerQueue.length; }
|
||||||
|
|
||||||
final package Duration getNextTimeout(long stdtime)
|
final package Duration getNextTimeout(MonoTime time)
|
||||||
@safe nothrow {
|
@safe nothrow {
|
||||||
if (m_timerQueue.empty) return Duration.max;
|
if (m_timerQueue.empty) return Duration.max;
|
||||||
return (m_timerQueue.front.timeout - stdtime).hnsecs;
|
return m_timerQueue.front.timeout - time;
|
||||||
}
|
}
|
||||||
|
|
||||||
final package bool process(long stdtime)
|
final package bool process(MonoTime time)
|
||||||
@trusted nothrow {
|
@trusted nothrow {
|
||||||
assert(m_firedTimers.length == 0);
|
assert(m_firedTimers.length == 0);
|
||||||
if (m_timerQueue.empty) return false;
|
if (m_timerQueue.empty) return false;
|
||||||
|
|
||||||
TimerSlot ts = void;
|
|
||||||
ts.timeout = stdtime+1;
|
|
||||||
foreach (tm; m_timerQueue[]) {
|
foreach (tm; m_timerQueue[]) {
|
||||||
if (tm.timeout > stdtime) break;
|
if (tm.timeout > time) break;
|
||||||
if (tm.repeatDuration > 0) {
|
if (tm.repeatDuration > Duration.zero) {
|
||||||
do tm.timeout += tm.repeatDuration;
|
do tm.timeout += tm.repeatDuration;
|
||||||
while (tm.timeout <= stdtime);
|
while (tm.timeout <= time);
|
||||||
} else tm.pending = false;
|
} else tm.pending = false;
|
||||||
m_firedTimers.put(tm);
|
m_firedTimers.put(tm);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +69,7 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
|
|
||||||
foreach (tm; processed_timers) {
|
foreach (tm; processed_timers) {
|
||||||
m_timerQueue.remove(tm);
|
m_timerQueue.remove(tm);
|
||||||
if (tm.repeatDuration > 0)
|
if (tm.repeatDuration > Duration.zero)
|
||||||
enqueueTimer(tm);
|
enqueueTimer(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +95,7 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
GC.addRange(tm, TimerSlot.sizeof, typeid(TimerSlot));
|
GC.addRange(tm, TimerSlot.sizeof, typeid(TimerSlot));
|
||||||
tm.id = id;
|
tm.id = id;
|
||||||
tm.refCount = 1;
|
tm.refCount = 1;
|
||||||
tm.timeout = long.max;
|
tm.timeout = MonoTime.max;
|
||||||
m_timers[id] = tm;
|
m_timers[id] = tm;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -108,8 +105,8 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
scope (failure) assert(false);
|
scope (failure) assert(false);
|
||||||
auto tm = m_timers[timer];
|
auto tm = m_timers[timer];
|
||||||
if (tm.pending) stop(timer);
|
if (tm.pending) stop(timer);
|
||||||
tm.timeout = Clock.currStdTime + timeout.total!"hnsecs";
|
tm.timeout = MonoTime.currTime + timeout;
|
||||||
tm.repeatDuration = repeat.total!"hnsecs";
|
tm.repeatDuration = repeat;
|
||||||
tm.pending = true;
|
tm.pending = true;
|
||||||
enqueueTimer(tm);
|
enqueueTimer(tm);
|
||||||
}
|
}
|
||||||
|
@ -137,7 +134,7 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
|
||||||
|
|
||||||
final override bool isPeriodic(TimerID descriptor)
|
final override bool isPeriodic(TimerID descriptor)
|
||||||
{
|
{
|
||||||
return m_timers[descriptor].repeatDuration > 0;
|
return m_timers[descriptor].repeatDuration > Duration.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void wait(TimerID timer, TimerCallback2 callback)
|
final override void wait(TimerID timer, TimerCallback2 callback)
|
||||||
|
@ -239,8 +236,8 @@ struct TimerSlot {
|
||||||
TimerID id;
|
TimerID id;
|
||||||
uint refCount;
|
uint refCount;
|
||||||
bool pending;
|
bool pending;
|
||||||
long timeout; // stdtime
|
MonoTime timeout;
|
||||||
long repeatDuration;
|
Duration repeatDuration;
|
||||||
TimerCallback2 callback; // TODO: use a list with small-value optimization
|
TimerCallback2 callback; // TODO: use a list with small-value optimization
|
||||||
|
|
||||||
DataInitializer userDataDestructor;
|
DataInitializer userDataDestructor;
|
||||||
|
|
|
@ -96,7 +96,7 @@ final class WinAPIEventDriverCore : EventDriverCore {
|
||||||
override ExitReason processEvents(Duration timeout = Duration.max)
|
override ExitReason processEvents(Duration timeout = Duration.max)
|
||||||
{
|
{
|
||||||
import std.algorithm : min;
|
import std.algorithm : min;
|
||||||
import core.time : hnsecs, seconds;
|
import core.time : MonoTime, seconds;
|
||||||
|
|
||||||
if (m_exit) {
|
if (m_exit) {
|
||||||
m_exit = false;
|
m_exit = false;
|
||||||
|
@ -106,12 +106,12 @@ final class WinAPIEventDriverCore : EventDriverCore {
|
||||||
if (!waiterCount) return ExitReason.outOfWaiters;
|
if (!waiterCount) return ExitReason.outOfWaiters;
|
||||||
|
|
||||||
bool got_event;
|
bool got_event;
|
||||||
long now = currStdTime;
|
auto now = MonoTime.currTime;
|
||||||
do {
|
do {
|
||||||
auto nextto = min(m_timers.getNextTimeout(now), timeout);
|
auto nextto = min(m_timers.getNextTimeout(now), timeout);
|
||||||
got_event |= doProcessEvents(nextto);
|
got_event |= doProcessEvents(nextto);
|
||||||
long prev_step = now;
|
auto prev_step = now;
|
||||||
now = currStdTime;
|
now = MonoTime.currTime;
|
||||||
got_event |= m_timers.process(now);
|
got_event |= m_timers.process(now);
|
||||||
|
|
||||||
if (m_exit) {
|
if (m_exit) {
|
||||||
|
@ -119,7 +119,7 @@ final class WinAPIEventDriverCore : EventDriverCore {
|
||||||
return ExitReason.exited;
|
return ExitReason.exited;
|
||||||
} else if (got_event) break;
|
} else if (got_event) break;
|
||||||
if (timeout != Duration.max)
|
if (timeout != Duration.max)
|
||||||
timeout -= (now - prev_step).hnsecs;
|
timeout -= now - prev_step;
|
||||||
} while (timeout > 0.seconds);
|
} while (timeout > 0.seconds);
|
||||||
|
|
||||||
if (!waiterCount) return ExitReason.outOfWaiters;
|
if (!waiterCount) return ExitReason.outOfWaiters;
|
||||||
|
|
|
@ -85,7 +85,6 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_core.addWaiter();
|
m_core.addWaiter();
|
||||||
addRef(sock);
|
|
||||||
return sock;
|
return sock;
|
||||||
} else {
|
} else {
|
||||||
clearSocketSlot(sock);
|
clearSocketSlot(sock);
|
||||||
|
@ -103,8 +102,9 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
assert(state == ConnectionState.connecting,
|
assert(state == ConnectionState.connecting,
|
||||||
"Must be in 'connecting' state when calling cancelConnection.");
|
"Must be in 'connecting' state when calling cancelConnection.");
|
||||||
|
|
||||||
clearSocketSlot(sock);
|
state = ConnectionState.closed;
|
||||||
() @trusted { closesocket(sock); } ();
|
connectCallback = null;
|
||||||
|
m_core.removeWaiter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
{
|
{
|
||||||
auto slot = () @trusted { return &m_sockets[socket].streamSocket(); } ();
|
auto slot = () @trusted { return &m_sockets[socket].streamSocket(); } ();
|
||||||
slot.read.buffer = buffer;
|
slot.read.buffer = buffer;
|
||||||
|
slot.read.bytesTransferred = 0;
|
||||||
slot.read.mode = mode;
|
slot.read.mode = mode;
|
||||||
slot.read.wsabuf[0].len = buffer.length;
|
slot.read.wsabuf[0].len = buffer.length;
|
||||||
slot.read.wsabuf[0].buf = () @trusted { return buffer.ptr; } ();
|
slot.read.wsabuf[0].buf = () @trusted { return buffer.ptr; } ();
|
||||||
|
@ -306,7 +307,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot.streamSocket.read.mode == IOMode.once || !slot.streamSocket.read.buffer.length) {
|
if (slot.streamSocket.read.mode == IOMode.once || !slot.streamSocket.read.buffer.length) {
|
||||||
invokeCallback(IOStatus.ok, cbTransferred);
|
invokeCallback(IOStatus.ok, slot.streamSocket.read.bytesTransferred);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +333,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
{
|
{
|
||||||
auto slot = () @trusted { return &m_sockets[socket].streamSocket(); } ();
|
auto slot = () @trusted { return &m_sockets[socket].streamSocket(); } ();
|
||||||
slot.write.buffer = buffer;
|
slot.write.buffer = buffer;
|
||||||
|
slot.write.bytesTransferred = 0;
|
||||||
slot.write.mode = mode;
|
slot.write.mode = mode;
|
||||||
slot.write.wsabuf[0].len = buffer.length;
|
slot.write.wsabuf[0].len = buffer.length;
|
||||||
slot.write.wsabuf[0].buf = () @trusted { return cast(ubyte*)buffer.ptr; } ();
|
slot.write.wsabuf[0].buf = () @trusted { return cast(ubyte*)buffer.ptr; } ();
|
||||||
|
@ -381,7 +383,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot.streamSocket.write.mode == IOMode.once || !slot.streamSocket.write.buffer.length) {
|
if (slot.streamSocket.write.mode == IOMode.once || !slot.streamSocket.write.buffer.length) {
|
||||||
invokeCallback(IOStatus.ok, cbTransferred);
|
invokeCallback(IOStatus.ok, slot.streamSocket.write.bytesTransferred);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,8 +552,11 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == IOMode.immediate)
|
if (mode == IOMode.immediate) {
|
||||||
() @trusted { CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&slot.read.overlapped); } ();
|
() @trusted { CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&slot.read.overlapped); } ();
|
||||||
|
on_read_finish(socket, IOStatus.wouldBlock, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
slot.read.callback = on_read_finish;
|
slot.read.callback = on_read_finish;
|
||||||
addRef(socket);
|
addRef(socket);
|
||||||
|
@ -644,8 +649,11 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == IOMode.immediate)
|
if (mode == IOMode.immediate) {
|
||||||
() @trusted { CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&slot.write.overlapped); } ();
|
() @trusted { CancelIoEx(cast(HANDLE)cast(SOCKET)socket, cast(LPOVERLAPPED)&slot.write.overlapped); } ();
|
||||||
|
on_write_finish(socket, IOStatus.wouldBlock, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
slot.write.callback = on_write_finish;
|
slot.write.callback = on_write_finish;
|
||||||
addRef(socket);
|
addRef(socket);
|
||||||
|
@ -845,6 +853,8 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
default: break;
|
default: break;
|
||||||
case FD_CONNECT:
|
case FD_CONNECT:
|
||||||
auto cb = slot.streamSocket.connectCallback;
|
auto cb = slot.streamSocket.connectCallback;
|
||||||
|
if (!cb) break; // cancelled connect?
|
||||||
|
|
||||||
slot.streamSocket.connectCallback = null;
|
slot.streamSocket.connectCallback = null;
|
||||||
slot.common.driver.m_core.removeWaiter();
|
slot.common.driver.m_core.removeWaiter();
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -852,8 +862,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
|
||||||
cb(cast(StreamSocketFD)sock, ConnectStatus.refused);
|
cb(cast(StreamSocketFD)sock, ConnectStatus.refused);
|
||||||
} else {
|
} else {
|
||||||
slot.streamSocket.state = ConnectionState.connected;
|
slot.streamSocket.state = ConnectionState.connected;
|
||||||
if (slot.common.driver.releaseRef(cast(StreamSocketFD)sock))
|
cb(cast(StreamSocketFD)sock, ConnectStatus.connected);
|
||||||
cb(cast(StreamSocketFD)sock, ConnectStatus.connected);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FD_READ:
|
case FD_READ:
|
||||||
|
|
|
@ -4,39 +4,42 @@
|
||||||
+/
|
+/
|
||||||
module test;
|
module test;
|
||||||
|
|
||||||
import eventcore.core;
|
|
||||||
import std.stdio : writefln;
|
import std.stdio : writefln;
|
||||||
import core.stdc.signal;
|
|
||||||
import core.sys.posix.signal : SIGUSR1;
|
|
||||||
import core.time : Duration, msecs;
|
|
||||||
|
|
||||||
bool s_done;
|
version (Linux) {
|
||||||
|
import eventcore.core;
|
||||||
|
import core.stdc.signal;
|
||||||
|
import core.sys.posix.signal : SIGUSR1;
|
||||||
|
import core.time : Duration, msecs;
|
||||||
|
|
||||||
void main()
|
bool s_done;
|
||||||
{
|
|
||||||
version (OSX) writefln("Signals are not yet supported on macOS. Skipping test.");
|
|
||||||
else {
|
|
||||||
|
|
||||||
auto id = eventDriver.signals.listen(SIGUSR1, (id, status, sig) {
|
void main()
|
||||||
assert(!s_done);
|
{
|
||||||
assert(status == SignalStatus.ok);
|
auto id = eventDriver.signals.listen(SIGUSR1, (id, status, sig) {
|
||||||
assert(sig == () @trusted { return SIGUSR1; } ());
|
assert(!s_done);
|
||||||
eventDriver.signals.releaseRef(id);
|
assert(status == SignalStatus.ok);
|
||||||
s_done = true;
|
assert(sig == () @trusted { return SIGUSR1; } ());
|
||||||
});
|
eventDriver.signals.releaseRef(id);
|
||||||
|
s_done = true;
|
||||||
|
});
|
||||||
|
|
||||||
auto tm = eventDriver.timers.create();
|
auto tm = eventDriver.timers.create();
|
||||||
eventDriver.timers.set(tm, 500.msecs, 0.msecs);
|
eventDriver.timers.set(tm, 500.msecs, 0.msecs);
|
||||||
eventDriver.timers.wait(tm, (tm) {
|
eventDriver.timers.wait(tm, (tm) {
|
||||||
() @trusted { raise(SIGUSR1); } ();
|
() @trusted { raise(SIGUSR1); } ();
|
||||||
});
|
});
|
||||||
|
|
||||||
ExitReason er;
|
|
||||||
do er = eventDriver.core.processEvents(Duration.max);
|
|
||||||
while (er == ExitReason.idle);
|
|
||||||
assert(er == ExitReason.outOfWaiters);
|
|
||||||
assert(s_done);
|
|
||||||
s_done = false;
|
|
||||||
|
|
||||||
|
ExitReason er;
|
||||||
|
do er = eventDriver.core.processEvents(Duration.max);
|
||||||
|
while (er == ExitReason.idle);
|
||||||
|
assert(er == ExitReason.outOfWaiters);
|
||||||
|
assert(s_done);
|
||||||
|
s_done = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
writefln("Signals are not yet supported on macOS/Windows. Skipping test.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ void main()
|
||||||
eventDriver.timers.wait(tm, (tm) {
|
eventDriver.timers.wait(tm, (tm) {
|
||||||
assert(eventDriver.sockets.getConnectionState(sock) == ConnectionState.connecting);
|
assert(eventDriver.sockets.getConnectionState(sock) == ConnectionState.connecting);
|
||||||
eventDriver.sockets.cancelConnectStream(sock);
|
eventDriver.sockets.cancelConnectStream(sock);
|
||||||
|
eventDriver.sockets.releaseRef(sock);
|
||||||
s_done = true;
|
s_done = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,7 @@ bool s_done;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
version (OSX) {
|
version (Linux) {
|
||||||
import std.stdio;
|
|
||||||
writeln("This doesn't work on macOS. Skipping this test until it is determined that this special case should stay supported.");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
static ubyte[] pack1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
static ubyte[] pack1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
|
||||||
|
@ -68,5 +64,9 @@ void main()
|
||||||
assert(s_done);
|
assert(s_done);
|
||||||
s_done = false;
|
s_done = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
import std.stdio;
|
||||||
|
writeln("This doesn't work on macOS/Windows. Skipping this test until it is determined that this special case should stay supported.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,12 +38,16 @@ void main()
|
||||||
assert(bts == pack1.length);
|
assert(bts == pack1.length);
|
||||||
assert(s_rbuf[0 .. pack1.length] == pack1);
|
assert(s_rbuf[0 .. pack1.length] == pack1);
|
||||||
|
|
||||||
print("Second write");
|
auto tmw = eventDriver.timers.create();
|
||||||
client.write!((status, bytes) {
|
eventDriver.timers.set(tmw, 20.msecs, 0.msecs);
|
||||||
print("Second write done");
|
eventDriver.timers.wait(tmw, (tmw) {
|
||||||
assert(status == IOStatus.ok);
|
print("Second write");
|
||||||
assert(bytes == pack2.length);
|
client.write!((status, bytes) {
|
||||||
})(pack2, IOMode.once);
|
print("Second write done");
|
||||||
|
assert(status == IOStatus.ok);
|
||||||
|
assert(bytes == pack2.length);
|
||||||
|
})(pack2, IOMode.once);
|
||||||
|
});
|
||||||
|
|
||||||
print("Second read");
|
print("Second read");
|
||||||
incoming.read!((status, bts) {
|
incoming.read!((status, bts) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ void main()
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assert(dur > 1200.msecs, (dur - 1200.msecs).toString());
|
assert(dur > 1200.msecs - 2.msecs, (dur - 1200.msecs).toString());
|
||||||
assert(dur < 1300.msecs, (dur - 1200.msecs).toString());
|
assert(dur < 1300.msecs, (dur - 1200.msecs).toString());
|
||||||
} catch (Exception e) assert(false, e.msg);
|
} catch (Exception e) assert(false, e.msg);
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ void main()
|
||||||
try {
|
try {
|
||||||
auto dur = MonoTime.currTime() - s_startTime;
|
auto dur = MonoTime.currTime() - s_startTime;
|
||||||
s_cnt++;
|
s_cnt++;
|
||||||
assert(dur > 300.msecs * s_cnt, (dur - 300.msecs * s_cnt).toString());
|
assert(dur > 300.msecs * s_cnt - 2.msecs, (dur - 300.msecs * s_cnt).toString());
|
||||||
assert(dur < 300.msecs * s_cnt + 100.msecs, (dur - 300.msecs * s_cnt).toString());
|
assert(dur < 300.msecs * s_cnt + 100.msecs, (dur - 300.msecs * s_cnt).toString());
|
||||||
assert(s_cnt <= 3);
|
assert(s_cnt <= 3);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,11 @@ void main()
|
||||||
static ubyte[] pack1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
static ubyte[] pack1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
static ubyte[] pack2 = [4, 3, 2, 1, 0];
|
static ubyte[] pack2 = [4, 3, 2, 1, 0];
|
||||||
|
|
||||||
|
// Windows can not provide "immediate" semantics using the overlapped
|
||||||
|
// I/O API that is used
|
||||||
|
version (Windows) enum mode_immediate = IOMode.once;
|
||||||
|
else enum mode_immediate = IOMode.immediate;
|
||||||
|
|
||||||
auto baddr = new InternetAddress(0x7F000001, 40001);
|
auto baddr = new InternetAddress(0x7F000001, 40001);
|
||||||
auto anyaddr = new InternetAddress(0x7F000001, 0);
|
auto anyaddr = new InternetAddress(0x7F000001, 0);
|
||||||
s_baseSocket = createDatagramSocket(baddr);
|
s_baseSocket = createDatagramSocket(baddr);
|
||||||
|
@ -55,14 +60,14 @@ void main()
|
||||||
destroy(s_connectedSocket);
|
destroy(s_connectedSocket);
|
||||||
s_done = true;
|
s_done = true;
|
||||||
log("done.");
|
log("done.");
|
||||||
})(s_rbuf, IOMode.immediate);
|
})(s_rbuf, mode_immediate);
|
||||||
});
|
});
|
||||||
})(s_rbuf, IOMode.once);
|
})(s_rbuf, IOMode.once);
|
||||||
s_connectedSocket.send!((status, bytes) {
|
s_connectedSocket.send!((status, bytes) {
|
||||||
log("send1: %s %s", status, bytes);
|
log("send1: %s %s", status, bytes);
|
||||||
assert(status == IOStatus.ok);
|
assert(status == IOStatus.ok);
|
||||||
assert(bytes == 10);
|
assert(bytes == 10);
|
||||||
})(pack1, IOMode.immediate);
|
})(pack1, mode_immediate);
|
||||||
|
|
||||||
ExitReason er;
|
ExitReason er;
|
||||||
do er = eventDriver.core.processEvents(Duration.max);
|
do er = eventDriver.core.processEvents(Duration.max);
|
||||||
|
|
|
@ -44,7 +44,7 @@ void main()
|
||||||
|
|
||||||
auto dur = MonoTime.currTime() - s_startTime;
|
auto dur = MonoTime.currTime() - s_startTime;
|
||||||
s_cnt++;
|
s_cnt++;
|
||||||
assert(dur > 300.msecs * s_cnt, (dur - 300.msecs * s_cnt).toString());
|
assert(dur > 300.msecs * s_cnt - 2.msecs, (dur - 300.msecs * s_cnt).toString());
|
||||||
assert(dur < 300.msecs * s_cnt + 100.msecs, (dur - 300.msecs * s_cnt).toString());
|
assert(dur < 300.msecs * s_cnt + 100.msecs, (dur - 300.msecs * s_cnt).toString());
|
||||||
assert(s_cnt <= 5);
|
assert(s_cnt <= 5);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue