• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()51 ANGLE_INLINE Spinlock::Spinlock() noexcept : mLock(0) {}
52 
try_lock()53 ANGLE_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()60 ANGLE_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()73 ANGLE_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