1 module drm.atomic; 2 public import core.atomic : MemoryOrder; 3 4 pragma(inline, true): 5 6 /// Atomic data like std::atomic 7 struct Atomic(T) if (__traits(isIntegral, T) || isPointer!T) { 8 import core.atomic : atomicLoad, atomicStore, atomicExchange, atomicFetchAdd, 9 atomicFetchSub, atomicCas = cas, atomicCasWeak = casWeak, atomicOp; 10 11 private shared T val; 12 13 /// Constructor 14 this(T init) shared { 15 val.atomicStore(init); 16 } 17 18 private shared(T)* ptr() shared { 19 return &val; 20 } 21 22 /// Load the value from the atomic location with SC access 23 alias load this; 24 25 /// ditto 26 T load(MemoryOrder mo = MemoryOrder.seq)() shared { 27 return val.atomicLoad!mo; 28 } 29 30 /// Store the value to the atomic location 31 void store(MemoryOrder mo = MemoryOrder.seq)(T newVal) shared { 32 return val.atomicStore!mo(newVal); 33 } 34 35 /// Store using SC access 36 alias opAssign = store; 37 38 /// Atomically increment the value 39 T fadd(MemoryOrder mo = MemoryOrder.seq)(T mod) shared { 40 return atomicFetchAdd(val, mod); 41 } 42 43 /// Atomically decrement the value 44 T fsub(MemoryOrder mo = MemoryOrder.seq)(T mod) shared { 45 return atomicFetchSub(val, mod); 46 } 47 48 /// Atomically swap the value 49 T exchange(MemoryOrder mo = MemoryOrder.seq)(T desired) shared { 50 return atomicExchange(&val, desired); 51 } 52 53 /// Compare and swap 54 bool cas(MemoryOrder mo = MemoryOrder.seq, MemoryOrder fmo = MemoryOrder.seq)(T oldVal, T newVal) shared { 55 return atomicCas!(mo, fmo)(ptr, oldVal, newVal); 56 } 57 58 /// ditto 59 bool casWeak(MemoryOrder mo = MemoryOrder.seq, MemoryOrder fmo = MemoryOrder.seq)(T oldVal, 60 T newVal) shared { 61 return atomicCasWeak!(mo, fmo)(ptr, oldVal, newVal); 62 } 63 64 /// Op assign with SC semantics 65 T opOpAssign(string op)(T rhs) shared { 66 return val.atomicOp!(op ~ `=`)(rhs); 67 } 68 69 /// Implicit conversion to FADD and FSUB 70 T opUnary(string op)() shared if (op == `++`) { 71 return val.atomicOp!`+=`(1); 72 } 73 74 T opUnary(string op)() shared if (op == `--`) { 75 return val.atomicOp!`-=`(1); 76 } 77 78 auto ref opUnary(string op)() shared if (op == `*`) { 79 return *(load); 80 } 81 } 82 83 private alias TestAtomic = Atomic!(int); 84 85 @safe unittest { 86 shared Atomic!int a; 87 assert(a == 0); 88 assert(a.load == 0); 89 assert(a.fadd!(MemoryOrder.raw)(5) == 0); 90 assert(a.load!(MemoryOrder.acq) == 5); 91 assert(!a.casWeak(4, 5)); 92 assert(!a.cas(4, 5)); 93 assert(a.cas!(MemoryOrder.rel, MemoryOrder.acq)(5, 4)); 94 assert(a.fsub!(MemoryOrder.acq_rel)(2) == 4); 95 assert(a.exchange!(MemoryOrder.acq_rel)(3) == 2); 96 assert(a.load!(MemoryOrder.raw) == 3); 97 a.store!(MemoryOrder.rel)(7); 98 assert(a.load == 7); 99 a = 32; 100 assert(a == 32); 101 a += 5; 102 assert(a == 37); 103 assert(a++ == 37); 104 assert(a == 38); 105 } 106 107 // static array of shared atomics 108 @safe unittest { 109 static shared(Atomic!int)[5] arr; 110 arr[4] = 4; 111 assert(arr[4].load == 4); 112 } 113 114 unittest { 115 import core.thread : Thread; 116 117 shared(Atomic!int)[2] arr; 118 119 void reltest() @safe { 120 arr[0].store!(MemoryOrder.rel)(1); 121 arr[1].store!(MemoryOrder.rel)(1); 122 } 123 124 void acqtest() @safe { 125 while (arr[1].load!(MemoryOrder.acq) != 1) { 126 } 127 assert(arr[0].load!(MemoryOrder.acq) == 1); 128 } 129 130 auto t1 = new Thread(&acqtest); 131 auto t2 = new Thread(&reltest); 132 t2.start; 133 t1.start; 134 t2.join; 135 t1.join; 136 } 137 138 @safe unittest { 139 shared Atomic!(shared(int)) a = 5; 140 assert(a.load == shared(int)(5)); 141 a = 2; 142 assert(a == 2); 143 } 144 145 @safe unittest { 146 shared Atomic!(shared(int)*) ptr = new shared(int); 147 *ptr.load!(MemoryOrder.raw)() = 5; 148 assert(*ptr.load == 5); 149 *(ptr.load) = 42; 150 assert(*ptr.load == 42); 151 } 152 153 @safe unittest { 154 shared Atomic!(shared(int)*) ptr = new shared(int); 155 *ptr = 5; 156 assert(*ptr == 5); 157 *ptr = 42; 158 assert(*ptr == 42); 159 } 160 161 unittest { 162 //shared Atomic!(shared(Atomic!(int))*) ptr = new shared(Atomic!int); 163 } 164 165 private enum bool isAggregateType(T) = is(T == struct) || is(T == union) 166 || is(T == class) || is(T == interface); 167 private enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T;