Add a trap to detect invalid uses of InterruptibleTaskMutex in conjunction with synchronized.

This commit is contained in:
Sönke Ludwig 2019-01-14 00:00:20 +01:00
parent ea4917d4d0
commit ffa5bd5c58

View file

@ -274,7 +274,6 @@ final class LocalTaskSemaphore
*/ */
final class TaskMutex : core.sync.mutex.Mutex, Lockable { final class TaskMutex : core.sync.mutex.Mutex, Lockable {
@safe: @safe:
private TaskMutexImpl!false m_impl; private TaskMutexImpl!false m_impl;
this(Object o) { m_impl.setup(); super(o); } this(Object o) { m_impl.setup(); super(o); }
@ -376,7 +375,13 @@ final class InterruptibleTaskMutex : Lockable {
private TaskMutexImpl!true m_impl; 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(); } bool tryLock() nothrow { return m_impl.tryLock(); }
void lock() { m_impl.lock(); } void lock() { m_impl.lock(); }
@ -437,10 +442,15 @@ unittest {
*/ */
final class InterruptibleRecursiveTaskMutex : Lockable { final class InterruptibleRecursiveTaskMutex : Lockable {
@safe: @safe:
private RecursiveTaskMutexImpl!true m_impl; 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(); } bool tryLock() { return m_impl.tryLock(); }
void lock() { m_impl.lock(); } 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)() private void runMutexUnitTests(M)()
{ {
import vibe.core.core; import vibe.core.core;