libcopp  2.2.0
spin_lock.h
Go to the documentation of this file.
1 
26 #pragma once
27 
28 #if defined(_MSC_VER)
29 
30 # ifndef WIN32_LEAN_AND_MEAN
31 # define WIN32_LEAN_AND_MEAN
32 # endif
33 
34 # include <Windows.h> // YieldProcessor
35 
36 # include <Processthreadsapi.h>
37 # include <Synchapi.h> // Windows server
38 # include <intrin.h>
39 #elif defined(__i386__) || defined(__x86_64__)
40 # if defined(__clang__)
41 # include <emmintrin.h>
42 # elif defined(__INTEL_COMPILER)
43 # include <immintrin.h>
44 # endif
45 #endif
46 
47 #include <libcopp/utils/config/libcopp_build_features.h>
48 
50 
56 #if defined(_MSC_VER)
57 
58 /*
59  * See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687419(v=vs.85).aspx
60  * Not for intel c++ compiler, so ignore http://software.intel.com/en-us/forums/topic/296168
61  */
62 
63 # ifdef YieldProcessor
64 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE() YieldProcessor()
65 # endif
66 
67 #elif defined(__GNUC__) || defined(__clang__)
68 # if defined(__i386__) || defined(__x86_64__)
74 // # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE() __asm__ __volatile__("pause")
75 # if defined(__clang__) || defined(__INTEL_COMPILER)
76 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE() _mm_pause()
77 # else
78 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE() __builtin_ia32_pause()
79 # endif
80 
81 # elif defined(__ia64__) || defined(__ia64)
87 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE() __asm__ __volatile__("hint @pause")
88 # elif defined(__arm__) && !defined(__ANDROID__)
93 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE() __asm__ __volatile__("yield")
94 # endif
95 
96 #endif /*compilers*/
97 
98 // set pause do nothing
99 #if !defined(__LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE)
100 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE()
101 #endif
108 #if 0 && defined(_MSC_VER)
109 
110 // SwitchToThread only can be used in desktop system
111 
112 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD() SwitchToThread()
113 
114 #elif defined(__linux__) || defined(__unix__)
115 # include <sched.h>
116 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD() sched_yield()
117 #endif
118 
119 #ifndef __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD
120 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD() __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE()
121 #endif
122 
128 #if defined(__LIBCOPP_UTIL_LOCK_ATOMIC_INT_TYPE_ATOMIC_STD)
129 // clang-format off
130 #include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
131 // clang-format on
132 # include <chrono>
133 # include <thread>
134 // clang-format off
135 #include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
136 // clang-format on
137 
138 # if defined(__GNUC__) && !defined(__clang__)
139 # if (__GNUC__ * 100 + __GNUC_MINOR__) <= 407
140 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD() __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD()
141 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD()
142 # endif
143 # endif
144 
145 # ifndef __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD
146 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD() ::std::this_thread::yield()
147 # endif
148 # ifndef __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP
149 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() ::std::this_thread::sleep_for(::std::chrono::milliseconds(1))
150 # endif
151 
152 #elif defined(_MSC_VER)
153 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD() Sleep(0)
154 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() Sleep(1)
155 #endif
156 
157 #ifndef __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD
158 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD()
159 # define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD()
160 #endif
161 
174 #define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_WAIT(x) \
175  { \
176  unsigned char try_lock_times = static_cast<unsigned char>(x); \
177  if (try_lock_times < 4) { \
178  } else if (try_lock_times < 16) { \
179  __LIBCOPP_UTIL_LOCK_SPIN_LOCK_PAUSE(); \
180  } else if (try_lock_times < 32) { \
181  __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_YIELD(); \
182  } else if (try_lock_times < 64) { \
183  __LIBCOPP_UTIL_LOCK_SPIN_LOCK_CPU_YIELD(); \
184  } else { \
185  __LIBCOPP_UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP(); \
186  } \
187  }
188 
189 LIBCOPP_COPP_NAMESPACE_BEGIN
190 namespace util {
191 namespace lock {
197 class LIBCOPP_COPP_API_HEAD_ONLY spin_lock {
198  private:
199  typedef enum { UNLOCKED = 0, LOCKED = 1 } lock_state_t;
200  LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<
201 #if defined(LIBCOPP_LOCK_DISABLE_MT) && LIBCOPP_LOCK_DISABLE_MT
202  LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<unsigned int>
203 #else
204  unsigned int
205 #endif
206  >
208 
209  public:
210  inline spin_lock() noexcept { lock_status_.store(UNLOCKED); }
211 
212  inline void lock() noexcept {
213  unsigned char try_times = 0;
214  while (lock_status_.exchange(static_cast<unsigned int>(LOCKED),
216  __LIBCOPP_UTIL_LOCK_SPIN_LOCK_WAIT(try_times++); /* busy-wait */
217  }
218 
219  inline void unlock() noexcept {
220  lock_status_.store(static_cast<unsigned int>(UNLOCKED),
222  }
223 
224  inline bool is_locked() noexcept {
225  return lock_status_.load(LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acquire) == LOCKED;
226  }
227 
228  inline bool try_lock() noexcept {
229  return lock_status_.exchange(static_cast<unsigned int>(LOCKED),
231  }
232 
233  inline bool try_unlock() noexcept {
234  return lock_status_.exchange(static_cast<unsigned int>(UNLOCKED),
236  }
237 };
238 } // namespace lock
239 } // namespace util
240 LIBCOPP_COPP_NAMESPACE_END
atomic wrapper fo integers Licensed under the MIT licenses.
spin_lock() noexcept
Definition: spin_lock.h:210
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< unsigned int > lock_status_
Definition: spin_lock.h:207
void lock() noexcept
Definition: spin_lock.h:212
void unlock() noexcept
Definition: spin_lock.h:219
bool try_lock() noexcept
Definition: spin_lock.h:228
bool try_unlock() noexcept
Definition: spin_lock.h:233
bool is_locked() noexcept
Definition: spin_lock.h:224
#define __LIBCOPP_UTIL_LOCK_SPIN_LOCK_WAIT(x)
Definition: spin_lock.h:174