1151937Sjkim/** 2151937Sjkim * SpinLock for runtime internal usage. 3151937Sjkim * 4167802Sjkim * Copyright: Copyright Digital Mars 2015 -. 5151937Sjkim * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 6151937Sjkim * Authors: Martin Nowak 7151937Sjkim * Source: $(DRUNTIMESRC core/internal/_spinlock.d) 8151937Sjkim */ 9151937Sjkimmodule core.internal.spinlock; 10151937Sjkim 11151937Sjkimimport core.atomic, core.thread; 12167802Sjkim 13151937Sjkimshared struct SpinLock 14151937Sjkim{ 15151937Sjkim /// for how long is the lock usually contended 16151937Sjkim enum Contention : ubyte 17151937Sjkim { 18151937Sjkim brief, 19151937Sjkim medium, 20151937Sjkim lengthy, 21151937Sjkim } 22151937Sjkim 23151937Sjkim@trusted @nogc nothrow: 24151937Sjkim this(Contention contention) 25151937Sjkim { 26151937Sjkim this.contention = contention; 27151937Sjkim } 28151937Sjkim 29151937Sjkim void lock() 30151937Sjkim { 31151937Sjkim if (cas(&val, size_t(0), size_t(1))) 32151937Sjkim return; 33151937Sjkim // Try to reduce the chance of another cas failure 34151937Sjkim // TTAS lock (https://en.wikipedia.org/wiki/Test_and_test-and-set) 35151937Sjkim immutable step = 1 << contention; 36151937Sjkim while (true) 37151937Sjkim { 38151937Sjkim for (size_t n; atomicLoad!(MemoryOrder.raw)(val); n += step) 39151937Sjkim yield(n); 40151937Sjkim if (cas(&val, size_t(0), size_t(1))) 41151937Sjkim return; 42151937Sjkim } 43151937Sjkim } 44151937Sjkim 45151937Sjkim void unlock() 46151937Sjkim { 47151937Sjkim atomicStore!(MemoryOrder.rel)(val, size_t(0)); 48151937Sjkim } 49151937Sjkim 50151937Sjkim /// yield with backoff 51151937Sjkim void yield(size_t k) 52151937Sjkim { 53151937Sjkim import core.time; 54151937Sjkim if (k < pauseThresh) 55151937Sjkim return core.atomic.pause(); 56151937Sjkim else if (k < 32) 57151937Sjkim return Thread.yield(); 58151937Sjkim Thread.sleep(1.msecs); 59151937Sjkim } 60151937Sjkim 61151937Sjkimprivate: 62151937Sjkim version (D_InlineAsm_X86) 63151937Sjkim enum X86 = true; 64151937Sjkim else version (D_InlineAsm_X86_64) 65151937Sjkim enum X86 = true; 66151937Sjkim else 67151937Sjkim enum X86 = false; 68151937Sjkim 69151937Sjkim static if (X86) 70151937Sjkim enum pauseThresh = 16; 71151937Sjkim else 72151937Sjkim enum pauseThresh = 4; 73151937Sjkim 74151937Sjkim size_t val; 75151937Sjkim Contention contention; 76151937Sjkim} 77151937Sjkim 78151937Sjkim// aligned to cacheline to avoid false sharing 79151937Sjkimshared align(64) struct AlignedSpinLock 80151937Sjkim{ 81151937Sjkim this(SpinLock.Contention contention) @trusted @nogc nothrow 82151937Sjkim { 83151937Sjkim impl = shared(SpinLock)(contention); 84151937Sjkim } 85151937Sjkim 86151937Sjkim SpinLock impl; 87151937Sjkim alias impl this; 88151937Sjkim} 89151937Sjkim