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"));