From ffa5bd5c5899475becb51e8a1fa8985aa939bc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 14 Jan 2019 00:00:20 +0100 Subject: [PATCH] Add a trap to detect invalid uses of InterruptibleTaskMutex in conjunction with synchronized. --- source/vibe/core/sync.d | 51 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/source/vibe/core/sync.d b/source/vibe/core/sync.d index 20b50d6..2710ae0 100644 --- a/source/vibe/core/sync.d +++ b/source/vibe/core/sync.d @@ -274,7 +274,6 @@ final class LocalTaskSemaphore */ final class TaskMutex : core.sync.mutex.Mutex, Lockable { @safe: - private TaskMutexImpl!false m_impl; this(Object o) { m_impl.setup(); super(o); } @@ -376,7 +375,13 @@ final class InterruptibleTaskMutex : Lockable { private TaskMutexImpl!true m_impl; - this() { m_impl.setup(); } + this() + { + m_impl.setup(); + + // detects invalid usage within synchronized(...) + () @trusted { this.__monitor = cast(void*)&NoUseMonitor.instance(); } (); + } bool tryLock() nothrow { return m_impl.tryLock(); } void lock() { m_impl.lock(); } @@ -437,10 +442,15 @@ unittest { */ final class InterruptibleRecursiveTaskMutex : Lockable { @safe: - private RecursiveTaskMutexImpl!true m_impl; - this() { m_impl.setup(); } + this() + { + m_impl.setup(); + + // detects invalid usage within synchronized(...) + () @trusted { this.__monitor = cast(void*)&NoUseMonitor.instance(); } (); + } bool tryLock() { return m_impl.tryLock(); } void lock() { m_impl.lock(); } @@ -453,6 +463,39 @@ unittest { } +// Helper class to ensure that the non Object.Monitor compatible interruptible +// mutex classes are not accidentally used with the `synchronized` statement +private final class NoUseMonitor : Object.Monitor { + private static shared Proxy st_instance; + + static struct Proxy { + Object.Monitor monitor; + } + + static @property ref shared(Proxy) instance() + @safe nothrow { + static shared(Proxy)* inst = null; + if (inst) return *inst; + + () @trusted { // synchronized {} not @safe for DMD <= 2.078.3 + synchronized { + if (!st_instance.monitor) + st_instance.monitor = new shared NoUseMonitor; + inst = &st_instance; + } + } (); + + return *inst; + } + + override void lock() @safe @nogc nothrow { + assert(false, "Interruptible task mutexes cannot be used with synchronized(), use scopedMutexLock instead."); + } + + override void unlock() @safe @nogc nothrow {} +} + + private void runMutexUnitTests(M)() { import vibe.core.core;