WPILibC++  2018.4.1-20180824021726-1174-g488ba79
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
spinlock.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #pragma once
9 
10 #include <atomic>
11 #include <cassert>
12 #include <thread>
13 
14 #include "Compiler.h"
15 
16 namespace wpi {
17 
21 class spinlock {
22  std::atomic_flag lock_flag;
23 
24  public:
25  spinlock() noexcept { lock_flag.clear(); }
26 
27  LLVM_ATTRIBUTE_ALWAYS_INLINE
28  bool try_lock() { return !lock_flag.test_and_set(std::memory_order_acquire); }
29 
30  LLVM_ATTRIBUTE_ALWAYS_INLINE
31  void lock() {
32  for (unsigned int i = 1; !try_lock(); ++i)
33  if ((i & 0xff) == 0) std::this_thread::yield();
34  }
35 
36  LLVM_ATTRIBUTE_ALWAYS_INLINE
37  void unlock() { lock_flag.clear(std::memory_order_release); }
38 };
39 
46  std::atomic<std::thread::id> owner_thread_id{std::thread::id{}};
47  int32_t recursive_counter{0};
48  std::atomic_flag lock_flag;
49 
50  public:
51  recursive_spinlock1() noexcept { lock_flag.clear(); }
52 
53  LLVM_ATTRIBUTE_ALWAYS_INLINE
54  bool try_lock() {
55  if (!lock_flag.test_and_set(std::memory_order_acquire)) {
56  owner_thread_id.store(std::this_thread::get_id(),
57  std::memory_order_release);
58  } else {
59  if (owner_thread_id.load(std::memory_order_acquire) !=
60  std::this_thread::get_id())
61  return false;
62  }
63  ++recursive_counter;
64  return true;
65  }
66 
67  LLVM_ATTRIBUTE_ALWAYS_INLINE
68  void lock() {
69  for (unsigned int i = 1; !try_lock(); ++i)
70  if ((i & 0xffff) == 0) std::this_thread::yield();
71  }
72 
73  LLVM_ATTRIBUTE_ALWAYS_INLINE
74  void unlock() {
75  assert(owner_thread_id.load(std::memory_order_acquire) ==
76  std::this_thread::get_id());
77  assert(recursive_counter > 0);
78 
79  if (--recursive_counter == 0) {
80  owner_thread_id.store(std::thread::id{}, std::memory_order_release);
81  lock_flag.clear(std::memory_order_release);
82  }
83  }
84 };
85 
92  std::atomic<std::thread::id> owner_thread_id{std::thread::id{}};
93  int32_t recursive_counter{0};
94 
95  public:
96  LLVM_ATTRIBUTE_ALWAYS_INLINE
97  bool try_lock() {
98  auto owner = std::thread::id{};
99  auto us = std::this_thread::get_id();
100  if (!owner_thread_id.compare_exchange_weak(owner, us,
101  std::memory_order_acquire)) {
102  if (owner != us) return false;
103  }
104  ++recursive_counter;
105  return true;
106  }
107 
108  LLVM_ATTRIBUTE_ALWAYS_INLINE
109  void lock() {
110  for (unsigned int i = 1; !try_lock(); ++i)
111  if ((i & 0xffff) == 0) std::this_thread::yield();
112  }
113 
114  LLVM_ATTRIBUTE_ALWAYS_INLINE
115  void unlock() {
116  assert(owner_thread_id.load(std::memory_order_acquire) ==
117  std::this_thread::get_id());
118  assert(recursive_counter > 0);
119 
120  if (--recursive_counter == 0)
121  owner_thread_id.store(std::thread::id{}, std::memory_order_release);
122  }
123 };
124 
125 #ifdef __arm__
126 // benchmarking has shown this version to be faster on ARM, but slower on
127 // windows, mac, and linux
129 #else
131 #endif
132 
133 } // namespace wpi
A spinlock mutex.
Definition: spinlock.h:21
A recursive spinlock mutex.
Definition: spinlock.h:45
WPILib C++ utilities (wpiutil) namespace.
Definition: SmallString.h:21
A recursive spinlock mutex.
Definition: spinlock.h:91