From 0b638634c9dc01871b7f16d000bf1448fe021e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 3 Sep 2018 12:35:05 +0200 Subject: [PATCH 1/2] Fix waitForDataAsync compilation error for callbacks that have scoped destruction. --- source/vibe/core/net.d | 62 +++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/source/vibe/core/net.d b/source/vibe/core/net.d index d9d7979..a2cf17a 100644 --- a/source/vibe/core/net.d +++ b/source/vibe/core/net.d @@ -619,7 +619,7 @@ mixin(tracer); if (is(typeof(() @safe { read_ready_callback(true); } ()))) { mixin(tracer); - import vibe.core.core : setTimer; + import vibe.core.core : Timer, setTimer; if (!m_context) return WaitForDataAsyncStatus.noMoreData; @@ -632,17 +632,39 @@ mixin(tracer); return rs ? WaitForDataAsyncStatus.dataAvailable : WaitForDataAsyncStatus.noMoreData; } - auto tm = setTimer(timeout, { - eventDriver.sockets.cancelRead(m_socket); - read_ready_callback(false); - }); - eventDriver.sockets.read(m_socket, m_context.readBuffer.peekDst(), IOMode.once, - (sock, st, nb) { - tm.stop(); - assert(m_context.readBuffer.length == 0); - m_context.readBuffer.putN(nb); - read_ready_callback(m_context.readBuffer.length > 0); - }); + static final class WaitContext { + CALLABLE callback; + TCPConnection connection; + Timer timer; + + this(CALLABLE callback, TCPConnection connection, Duration timeout) + { + this.callback = callback; + this.connection = connection; + if (timeout < Duration.max) + this.timer = setTimer(timeout, &onTimeout); + } + + void onTimeout() + { + eventDriver.sockets.cancelRead(connection.m_socket); + callback(false); + } + + void onData(StreamSocketFD, IOStatus st, size_t nb) + { + if (timer) timer.stop(); + assert(connection.m_context.readBuffer.length == 0); + connection.m_context.readBuffer.putN(nb); + callback(connection.m_context.readBuffer.length > 0); + } + } + + // FIXME: make this work without a heap allocation! + auto context = new WaitContext(read_ready_callback, this, timeout); + + eventDriver.sockets.read(m_socket, m_context.readBuffer.peekDst(), + IOMode.once, &context.onData); return WaitForDataAsyncStatus.waiting; } @@ -758,6 +780,20 @@ enum WaitForDataAsyncStatus { waiting, } +unittest { // test compilation of callback with scoped destruction + static struct CB { + ~this() {} + this(this) {} + void opCall(bool) {} + } + + void test() { + TCPConnection c; + CB cb; + c.waitForDataAsync(cb); + } +} + mixin validateConnectionStream!TCPConnection; @@ -1066,4 +1102,4 @@ class ReadTimeoutException: Exception { super(message, file, line, next); } -} \ No newline at end of file +} From 897fee84ea1cfd18daad88130021b8f160e593f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 3 Sep 2018 13:45:53 +0200 Subject: [PATCH 2/2] Free resources associated with waitForDataAsync as early as possible. Instead of letting the GC clean up at an undefined point in time. --- source/vibe/core/net.d | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source/vibe/core/net.d b/source/vibe/core/net.d index a2cf17a..2c2a2a6 100644 --- a/source/vibe/core/net.d +++ b/source/vibe/core/net.d @@ -633,6 +633,8 @@ mixin(tracer); } static final class WaitContext { + import std.algorithm.mutation : move; + CALLABLE callback; TCPConnection connection; Timer timer; @@ -648,7 +650,7 @@ mixin(tracer); void onTimeout() { eventDriver.sockets.cancelRead(connection.m_socket); - callback(false); + invoke(false); } void onData(StreamSocketFD, IOStatus st, size_t nb) @@ -656,7 +658,15 @@ mixin(tracer); if (timer) timer.stop(); assert(connection.m_context.readBuffer.length == 0); connection.m_context.readBuffer.putN(nb); - callback(connection.m_context.readBuffer.length > 0); + invoke(connection.m_context.readBuffer.length > 0); + } + + void invoke(bool status) + { + auto cb = move(callback); + connection = TCPConnection.init; + timer = Timer.init; + cb(status); } }