1 /************************************************************************************************************************ 2 It's internal code. Can be used for atomics if emscripten backend will be used. 3 4 This module contain atomic operations which include support for emscripten atomics functions. 5 Emscripten functions are contained in API similar to druntime. 6 7 Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz 8 License: BSD 3-clause, see LICENSE file in project root folder. 9 */ 10 module bubel.ecs.atomic; 11 12 version (Emscripten) version = ECSEmscripten; 13 14 version (ECSEmscripten) 15 { 16 import std.traits; 17 18 enum MemoryOrder 19 { 20 acq, 21 acq_rel, 22 raw, 23 rel, 24 seq 25 } 26 27 extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; 28 extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure; 29 extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure; 30 31 extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure; 32 extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure; 33 extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure; 34 35 extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure; 36 extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure; 37 extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure; 38 39 extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure; 40 extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure; 41 extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure; 42 43 extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure; 44 extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure; 45 extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure; 46 47 public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) 48 { 49 static if (op == "+=") 50 { 51 static if (is(T == byte) || is(T == ubyte)) 52 return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, 53 cast(Unqual!T) mod) + 1); 54 else static if (is(T == short) || is(T == ushort)) 55 return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, 56 cast(Unqual!T) mod) + 1); 57 else static if (is(T == int) || is(T == uint)) 58 return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, 59 cast(Unqual!T) mod) + 1); 60 else 61 static assert(0); 62 } 63 else static if (op == "-=") 64 { 65 static if (is(T == byte) || is(T == ubyte)) 66 return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, 67 cast(Unqual!T) mod) - 1); 68 else static if (is(T == short) || is(T == ushort)) 69 return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, 70 cast(Unqual!T) mod) - 1); 71 else static if (is(T == int) || is(T == uint)) 72 return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, 73 cast(Unqual!T) mod) - 1); 74 else 75 static assert(0); 76 } 77 } 78 79 public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, 80 V newval) 81 { 82 alias UT = Unqual!T; 83 static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte)) 84 emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval); 85 else static if (is(UT == short) || is(UT == ushort)) 86 emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval); 87 else static if (is(UT == int) || is(UT == uint)) 88 emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval); 89 else 90 static assert(0); 91 } 92 93 public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( 94 ref const T val) 95 { 96 alias UT = Unqual!T; 97 static if (is(UT == bool)) 98 return emscripten_atomic_load_u8(cast(const void*)&val) != 0; 99 else static if (is(UT == byte) || is(UT == ubyte)) 100 return emscripten_atomic_load_u8(cast(const void*)&val); 101 else static if (is(UT == short) || is(UT == ushort)) 102 return emscripten_atomic_load_u16(cast(const void*)&val); 103 else static if (is(UT == int) || is(UT == uint)) 104 return emscripten_atomic_load_u32(cast(const void*)&val); 105 else 106 static assert(0); 107 } 108 109 public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, 110 MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) 111 { 112 alias UT = Unqual!T; 113 static if (is(UT == bool)) 114 return emscripten_atomic_cas_u8(cast(void*) here, 115 cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; 116 else static if (is(UT == byte) || is(UT == ubyte)) 117 return emscripten_atomic_cas_u8(cast(void*) here, 118 cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; 119 else static if (is(UT == short) || is(UT == ushort)) 120 return emscripten_atomic_cas_u16(cast(void*) here, 121 cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; 122 else static if (is(UT == int) || is(UT == uint)) 123 return emscripten_atomic_cas_u32(cast(void*) here, 124 cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; 125 else 126 static assert(0); 127 } 128 } 129 else 130 { 131 public import core.atomic; 132 }