brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.9 KiB · 3b424b3 Raw
66 lines · c
1//===-- TTAS Spin Lock ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H10#define LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H11 12#include "src/__support/CPP/atomic.h"13#include "src/__support/macros/attributes.h"14#include "src/__support/threads/sleep.h"15 16namespace LIBC_NAMESPACE_DECL {17 18class SpinLock {19  cpp::Atomic<unsigned char> flag;20 21public:22  LIBC_INLINE constexpr SpinLock() : flag{0} {}23  LIBC_INLINE bool try_lock() {24    return !flag.exchange(1u, cpp::MemoryOrder::ACQUIRE);25  }26  LIBC_INLINE void lock() {27    // clang-format off28    // For normal TTAS, this compiles to the following on armv9a and x86_64:29    //         mov     w8, #1            |          .LBB0_1:30    // .LBB0_1:                          |                  mov     al, 131    //         swpab   w8, w9, [x0]      |                  xchg    byte ptr [rdi], al32    //         tbnz    w9, #0, .LBB0_3   |                  test    al, 133    //         b       .LBB0_4           |                  jne     .LBB0_334    // .LBB0_2:                          |                  jmp     .LBB0_435    //         isb                       |         .LBB0_2:36    // .LBB0_3:                          |                  pause37    //         ldrb    w9, [x0]          |         .LBB0_3:38    //         tbnz    w9, #0, .LBB0_2   |                  movzx   eax, byte ptr [rdi]39    //         b       .LBB0_1           |                  test    al, 140    // .LBB0_4:                          |                  jne     .LBB0_241    //         ret                       |                  jmp     .LBB0_142    //                                   |          .LBB0_4:43    //                                   |                  ret44    // clang-format on45    // Notice that inside the busy loop .LBB0_2 and .LBB0_3, only instructions46    // with load semantics are used. swpab/xchg is only issued in outer loop47    // .LBB0_1. This is useful to avoid extra write traffic. The cache48    // coherence guarantees "write propagation", so even if the inner loop only49    // reads with relaxed ordering, the thread will evetually see the write.50    while (!try_lock())51      while (flag.load(cpp::MemoryOrder::RELAXED))52        sleep_briefly();53  }54  LIBC_INLINE void unlock() { flag.store(0u, cpp::MemoryOrder::RELEASE); }55  LIBC_INLINE bool is_locked() { return flag.load(cpp::MemoryOrder::ACQUIRE); }56  LIBC_INLINE bool is_invalid() {57    return flag.load(cpp::MemoryOrder::ACQUIRE) > 1;58  }59  // poison the lock60  LIBC_INLINE ~SpinLock() { flag.store(0xffu, cpp::MemoryOrder::RELEASE); }61};62 63} // namespace LIBC_NAMESPACE_DECL64 65#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H66