1 module concurrency.utils; 2 3 import std.traits; 4 5 /// Helper used in with() to easily access `shared` methods of a class 6 struct SharedGuard(T) if (is(T == class)) { 7 import core.sync.mutex : Mutex; 8 private: 9 Mutex mutex; 10 public: 11 T reg; 12 alias reg this; 13 @disable this(); 14 @disable this(this); 15 static SharedGuard acquire(shared T reg, Mutex mutex) { 16 mutex.lock_nothrow(); 17 auto instance = SharedGuard.init; 18 instance.reg = (cast() reg); 19 instance.mutex = mutex; 20 return instance; 21 } 22 ~this() { 23 mutex.unlock_nothrow(); 24 } 25 } 26 27 /// A manually constructed closure, aimed at shared 28 struct Closure(Fun, Args...) { 29 Fun fun; 30 Args args; 31 auto apply() shared { 32 return fun((cast()this).args); 33 } 34 } 35 36 /// This is a terrible workaround for closure bugs in D. When a local is used in a delegate D is supposed to move it to the heap. I haven't seen that happen in all cases so we have this manual workaround. 37 auto closure(Fun, Args...)(Fun fun, Args args) @trusted if (isFunctionPointer!Fun) { 38 static assert(!hasFunctionAttributes!(Fun, "@system"), "no @system functions please"); 39 auto cl = cast(shared)new Closure!(Fun, Args)(fun, args); 40 /// need to cast to @safe because a @trusted delegate doesn't fit a @safe one... 41 static if (hasFunctionAttributes!(Fun, "nothrow")) 42 alias ResultType = void delegate() nothrow shared @safe; 43 else 44 alias ResultType = void delegate() shared @safe; 45 return cast(ResultType)&cl.apply; 46 } 47 48 /// don't want vibe-d to overwrite the scheduler 49 void resetScheduler() @trusted { 50 import std.concurrency : scheduler; 51 if (scheduler !is null) 52 scheduler = null; 53 } 54 55 enum NoVoid(T) = !is(T == void); 56 57 void spin_yield() nothrow @trusted @nogc { 58 // TODO: could use the pause asm instruction 59 // it is available in LDC as intrinsic... but not in DMD 60 import core.thread : Thread; 61 62 Thread.yield(); 63 } 64 65 /// ugly ugly 66 static if (__traits(compiles, () { import core.atomic : casWeak; }) && __traits(compiles, () { 67 import core.internal.atomic : atomicCompareExchangeWeakNoResult; 68 })) 69 public import core.atomic : casWeak; 70 else { 71 import core.atomic : MemoryOrder; 72 auto casWeak(MemoryOrder M1 = MemoryOrder.seq, MemoryOrder M2 = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) pure nothrow @nogc @safe { 73 import core.atomic : cas; 74 75 static if (__traits(compiles, cas!(M1, M2)(here, ifThis, writeThis))) 76 return cas!(M1, M2)(here, ifThis, writeThis); 77 else 78 return cas(here, ifThis, writeThis); 79 } 80 } 81 82 enum isThreadSafeFunction(alias Fun) = !hasFunctionAttributes!(Fun, "@system") && (isFunction!Fun || isFunctionPointer!Fun || hasFunctionAttributes!(Fun, "shared"));