1408a351dSSchrodinger ZHU Yifan //===-- TTAS Spin Lock ----------------------------------------------------===// 2408a351dSSchrodinger ZHU Yifan // 3408a351dSSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4408a351dSSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 5408a351dSSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6408a351dSSchrodinger ZHU Yifan // 7408a351dSSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 8408a351dSSchrodinger ZHU Yifan 9408a351dSSchrodinger ZHU Yifan #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H 10408a351dSSchrodinger ZHU Yifan #define LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H 11408a351dSSchrodinger ZHU Yifan 12408a351dSSchrodinger ZHU Yifan #include "src/__support/CPP/atomic.h" 13408a351dSSchrodinger ZHU Yifan #include "src/__support/macros/attributes.h" 14408a351dSSchrodinger ZHU Yifan #include "src/__support/threads/sleep.h" 15408a351dSSchrodinger ZHU Yifan 16408a351dSSchrodinger ZHU Yifan namespace LIBC_NAMESPACE_DECL { 17408a351dSSchrodinger ZHU Yifan 18*03841e7aSSchrodinger ZHU Yifan class SpinLock { 19*03841e7aSSchrodinger ZHU Yifan cpp::Atomic<unsigned char> flag; 20408a351dSSchrodinger ZHU Yifan 21408a351dSSchrodinger ZHU Yifan public: 22*03841e7aSSchrodinger ZHU Yifan LIBC_INLINE constexpr SpinLock() : flag{0} {} 23408a351dSSchrodinger ZHU Yifan LIBC_INLINE bool try_lock() { 24*03841e7aSSchrodinger ZHU Yifan return !flag.exchange(1u, cpp::MemoryOrder::ACQUIRE); 25408a351dSSchrodinger ZHU Yifan } 26408a351dSSchrodinger ZHU Yifan LIBC_INLINE void lock() { 27408a351dSSchrodinger ZHU Yifan // clang-format off 28408a351dSSchrodinger ZHU Yifan // For normal TTAS, this compiles to the following on armv9a and x86_64: 29408a351dSSchrodinger ZHU Yifan // mov w8, #1 | .LBB0_1: 30408a351dSSchrodinger ZHU Yifan // .LBB0_1: | mov al, 1 31408a351dSSchrodinger ZHU Yifan // swpab w8, w9, [x0] | xchg byte ptr [rdi], al 32408a351dSSchrodinger ZHU Yifan // tbnz w9, #0, .LBB0_3 | test al, 1 33408a351dSSchrodinger ZHU Yifan // b .LBB0_4 | jne .LBB0_3 34408a351dSSchrodinger ZHU Yifan // .LBB0_2: | jmp .LBB0_4 35408a351dSSchrodinger ZHU Yifan // isb | .LBB0_2: 36408a351dSSchrodinger ZHU Yifan // .LBB0_3: | pause 37408a351dSSchrodinger ZHU Yifan // ldrb w9, [x0] | .LBB0_3: 38408a351dSSchrodinger ZHU Yifan // tbnz w9, #0, .LBB0_2 | movzx eax, byte ptr [rdi] 39408a351dSSchrodinger ZHU Yifan // b .LBB0_1 | test al, 1 40408a351dSSchrodinger ZHU Yifan // .LBB0_4: | jne .LBB0_2 41408a351dSSchrodinger ZHU Yifan // ret | jmp .LBB0_1 42408a351dSSchrodinger ZHU Yifan // | .LBB0_4: 43408a351dSSchrodinger ZHU Yifan // | ret 44408a351dSSchrodinger ZHU Yifan // clang-format on 45408a351dSSchrodinger ZHU Yifan // Notice that inside the busy loop .LBB0_2 and .LBB0_3, only instructions 46408a351dSSchrodinger ZHU Yifan // with load semantics are used. swpab/xchg is only issued in outer loop 47408a351dSSchrodinger ZHU Yifan // .LBB0_1. This is useful to avoid extra write traffic. The cache 48408a351dSSchrodinger ZHU Yifan // coherence guarantees "write propagation", so even if the inner loop only 49408a351dSSchrodinger ZHU Yifan // reads with relaxed ordering, the thread will evetually see the write. 50408a351dSSchrodinger ZHU Yifan while (!try_lock()) 51408a351dSSchrodinger ZHU Yifan while (flag.load(cpp::MemoryOrder::RELAXED)) 52408a351dSSchrodinger ZHU Yifan sleep_briefly(); 53408a351dSSchrodinger ZHU Yifan } 54*03841e7aSSchrodinger ZHU Yifan LIBC_INLINE void unlock() { flag.store(0u, cpp::MemoryOrder::RELEASE); } 55*03841e7aSSchrodinger ZHU Yifan LIBC_INLINE bool is_locked() { return flag.load(cpp::MemoryOrder::ACQUIRE); } 56*03841e7aSSchrodinger ZHU Yifan LIBC_INLINE bool is_invalid() { 57*03841e7aSSchrodinger ZHU Yifan return flag.load(cpp::MemoryOrder::ACQUIRE) > 1; 58408a351dSSchrodinger ZHU Yifan } 59*03841e7aSSchrodinger ZHU Yifan // poison the lock 60*03841e7aSSchrodinger ZHU Yifan LIBC_INLINE ~SpinLock() { flag.store(0xffu, cpp::MemoryOrder::RELEASE); } 61408a351dSSchrodinger ZHU Yifan }; 62408a351dSSchrodinger ZHU Yifan 63408a351dSSchrodinger ZHU Yifan } // namespace LIBC_NAMESPACE_DECL 64408a351dSSchrodinger ZHU Yifan 65408a351dSSchrodinger ZHU Yifan #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H 66