From 1b2c0f33d14498130a0d4a83b357d4b7fd995642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 19 Dec 2016 20:19:58 +0100 Subject: [PATCH] Fix timeout handling in ManualEvent. The timeout could was re-applied in every loop iteration of the wait routine, possibly causing an infinite loop. --- source/vibe/core/sync.d | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/source/vibe/core/sync.d b/source/vibe/core/sync.d index 57c5da9..974384e 100644 --- a/source/vibe/core/sync.d +++ b/source/vibe/core/sync.d @@ -838,6 +838,15 @@ struct ManualEvent { private int doWait(bool interruptible)(Duration timeout, int emit_count) { + import std.datetime : SysTime, Clock, UTC; + + SysTime target_timeout, now; + if (timeout != Duration.max) { + try now = Clock.currTime(UTC()); + catch (Exception e) { assert(false, e.msg); } + target_timeout = now + timeout; + } + int ec = this.emitCount; while (ec <= emit_count) { ThreadWaiter w; @@ -848,14 +857,29 @@ struct ManualEvent { cb => tw.wait(cb), cb => tw.cancel() ) waitable; - asyncAwaitAny!interruptible(timeout, waitable); + asyncAwaitAny!interruptible(timeout != Duration.max ? target_timeout - now : Duration.max, waitable); ec = this.emitCount; - } + + if (timeout != Duration.max) { + try now = Clock.currTime(UTC()); + catch (Exception e) { assert(false, e.msg); } + if (now >= target_timeout) break; + } +} return ec; } private int doWaitShared(bool interruptible)(Duration timeout, int emit_count) shared { + import std.datetime : SysTime, Clock, UTC; + + SysTime target_timeout, now; + if (timeout != Duration.max) { + try now = Clock.currTime(UTC()); + catch (Exception e) { assert(false, e.msg); } + target_timeout = now + timeout; + } + int ec = this.emitCount; while (ec <= emit_count) { shared(ThreadWaiter) w; @@ -870,7 +894,8 @@ struct ManualEvent { cb => tw.wait(cb), cb => tw.cancel() ) waitable; - asyncAwaitAny!interruptible(timeout, waitable); + asyncAwaitAny!interruptible(timeout != Duration.max ? target_timeout - now : Duration.max, waitable); + if (waitable.cancelled) break; // timeout } else { again: // if we are the first waiter for this thread, @@ -885,7 +910,7 @@ struct ManualEvent { cb => tw.cancel() ) localwaiter; logDebugV("Wait on event %s", ms_threadEvent); - asyncAwaitAny!interruptible(timeout, eventwaiter, localwaiter); + asyncAwaitAny!interruptible(timeout != Duration.max ? target_timeout - now : Duration.max, eventwaiter, localwaiter); if (!eventwaiter.cancelled) { if (() @trusted { return atomicLoad(w.next); } () is null) @@ -900,6 +925,12 @@ struct ManualEvent { }(); ec = this.emitCount; + + if (timeout != Duration.max) { + try now = Clock.currTime(UTC()); + catch (Exception e) { assert(false, e.msg); } + if (now >= target_timeout) break; + } } return ec; }