1 // 2 // Copyright 2021 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // Spinlock.h: 7 // Spinlock is a lock that loops actively until it gets the resource. 8 // Only use it when the lock will be granted in reasonably short time. 9 10 #ifndef COMMON_SPINLOCK_H_ 11 #define COMMON_SPINLOCK_H_ 12 13 #include "common/angleutils.h" 14 15 #ifdef _MSC_VER 16 # include <intrin.h> // for _mm_pause() and __yield() 17 #endif 18 19 #if defined(__ARM_ARCH_7__) || defined(__aarch64__) 20 # if defined(__GNUC__) || defined(__clang__) 21 # include <arm_acle.h> // for __yield() 22 # endif 23 #endif 24 25 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 26 # define ANGLE_SMT_PAUSE() _mm_pause() 27 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 28 # define ANGLE_SMT_PAUSE() __asm__ __volatile__("pause;") 29 #elif defined(_M_ARM) || defined(_M_ARM64) || defined(__ARM_ARCH_7__) || defined(__aarch64__) 30 # define ANGLE_SMT_PAUSE() __yield() 31 #else 32 # define ANGLE_SMT_PAUSE() static_cast<void>(0) 33 #endif 34 35 namespace angle 36 { 37 38 class Spinlock 39 { 40 public: 41 Spinlock() noexcept; 42 43 bool try_lock() noexcept; 44 void lock() noexcept; 45 void unlock() noexcept; 46 47 private: 48 std::atomic_int mLock; 49 }; 50 Spinlock()51ANGLE_INLINE Spinlock::Spinlock() noexcept : mLock(0) {} 52 try_lock()53ANGLE_INLINE bool Spinlock::try_lock() noexcept 54 { 55 // Relaxed check first to prevent unnecessary cache misses. 56 return mLock.load(std::memory_order_relaxed) == 0 && 57 mLock.exchange(1, std::memory_order_acquire) == 0; 58 } 59 lock()60ANGLE_INLINE void Spinlock::lock() noexcept 61 { 62 while (mLock.exchange(1, std::memory_order_acquire) != 0) 63 { 64 // Relaxed wait to prevent unnecessary cache misses. 65 while (mLock.load(std::memory_order_relaxed) != 0) 66 { 67 // Optimization for simultaneous multithreading. 68 ANGLE_SMT_PAUSE(); 69 } 70 } 71 } 72 unlock()73ANGLE_INLINE void Spinlock::unlock() noexcept 74 { 75 mLock.store(0, std::memory_order_release); 76 } 77 78 } // namespace angle 79 80 #endif // COMMON_SPINLOCK_H_ 81