libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
189LIBCOPP_COPP_NAMESPACE_BEGIN
190namespace util {
191namespace lock {
197class 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 LIBCOPP_MACRO_ENABLE_MULTI_THREAD
202 unsigned int
203#else
204 LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<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),
215 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acq_rel) == 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),
221 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_release);
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),
230 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acq_rel) == UNLOCKED;
231 }
232
233 inline bool try_unlock() noexcept {
234 return lock_status_.exchange(static_cast<unsigned int>(UNLOCKED),
235 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acq_rel) == LOCKED;
236 }
237};
238} // namespace lock
239} // namespace util
240LIBCOPP_COPP_NAMESPACE_END
atomic wrapper fo integers Licensed under the MIT licenses.
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
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type< unsigned int > > lock_status_
Definition spin_lock.h:207
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