Line | % of fetches | Source | |
---|---|---|---|
1 | //////////////////////////////////////////////////////////////////////////////// | ||
2 | // Copyright (c) 2011 Bryce Lelbach | ||
3 | // Copyright (c) 2011-2016 Hartmut Kaiser | ||
4 | // Copyright (c) 2014 Thomas Heller | ||
5 | // | ||
6 | // Copyright (c) 2008 Peter Dimov | ||
7 | // | ||
8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
10 | //////////////////////////////////////////////////////////////////////////////// | ||
11 | |||
12 | #if !defined(HPX_B3A83B49_92E0_4150_A551_488F9F5E1113) | ||
13 | #define HPX_B3A83B49_92E0_4150_A551_488F9F5E1113 | ||
14 | |||
15 | #include <hpx/config.hpp> | ||
16 | #ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION | ||
17 | #include <hpx/throw_exception.hpp> | ||
18 | #endif | ||
19 | #include <hpx/runtime/threads/thread_helpers.hpp> | ||
20 | #include <hpx/util/itt_notify.hpp> | ||
21 | #include <hpx/util/register_locks.hpp> | ||
22 | |||
23 | #if defined(HPX_WINDOWS) | ||
24 | # include <boost/smart_ptr/detail/spinlock.hpp> | ||
25 | # if !defined( BOOST_SP_HAS_SYNC ) | ||
26 | # include <boost/detail/interlocked.hpp> | ||
27 | # endif | ||
28 | #else | ||
29 | # if !defined(__ANDROID__) && !defined(ANDROID) && !defined(__arm__) | ||
30 | # include <boost/smart_ptr/detail/spinlock.hpp> | ||
31 | # if defined( __ia64__ ) && defined( __INTEL_COMPILER ) | ||
32 | # include <ia64intrin.h> | ||
33 | # endif | ||
34 | # endif | ||
35 | #endif | ||
36 | |||
37 | #include <cstddef> | ||
38 | #include <cstdint> | ||
39 | |||
40 | /////////////////////////////////////////////////////////////////////////////// | ||
41 | namespace hpx { namespace lcos { namespace local | ||
42 | { | ||
43 | #ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION | ||
44 | HPX_API_EXPORT extern bool spinlock_break_on_deadlock; | ||
45 | HPX_API_EXPORT extern std::size_t spinlock_deadlock_detection_limit; | ||
46 | #endif | ||
47 | |||
48 | /// boost::mutex-compatible spinlock class | ||
49 | struct spinlock | ||
50 | { | ||
51 | private: | ||
52 | HPX_NON_COPYABLE(spinlock); | ||
53 | |||
54 | private: | ||
55 | #if defined(__ANDROID__) && defined(ANDROID) | ||
56 | int v_; | ||
57 | #else | ||
58 | std::uint64_t v_; | ||
59 | #endif | ||
60 | |||
61 | public: | ||
62 | /////////////////////////////////////////////////////////////////////// | ||
63 | static void yield(std::size_t k) | ||
64 | { | ||
65 | if (k < 4) //-V112 | ||
66 | { | ||
67 | } | ||
68 | #if defined(BOOST_SMT_PAUSE) | ||
69 | else if(k < 16) | ||
70 | { | ||
71 | BOOST_SMT_PAUSE | ||
72 | } | ||
73 | #endif | ||
74 | else if(k < 32 || k & 1) //-V112 | ||
75 | { | ||
76 | if (hpx::threads::get_self_ptr()) | ||
77 | { | ||
78 | hpx::this_thread::suspend(hpx::threads::pending, | ||
79 | "hpx::lcos::local::spinlock::yield"); | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | #if defined(HPX_WINDOWS) | ||
84 | Sleep(0); | ||
85 | #elif defined(BOOST_HAS_PTHREADS) | ||
86 | sched_yield(); | ||
87 | #else | ||
88 | #endif | ||
89 | } | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | #ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION | ||
94 | if (spinlock_break_on_deadlock && | ||
95 | k > spinlock_deadlock_detection_limit) | ||
96 | { | ||
97 | HPX_THROW_EXCEPTION(deadlock, | ||
98 | "hpx::lcos::local::spinlock::yield", | ||
99 | "possible deadlock detected"); | ||
100 | } | ||
101 | #endif | ||
102 | |||
103 | if (hpx::threads::get_self_ptr()) | ||
104 | { | ||
105 | hpx::this_thread::suspend(hpx::threads::pending, | ||
106 | "hpx::lcos::local::spinlock::yield"); | ||
107 | } | ||
108 | else | ||
109 | { | ||
110 | #if defined(HPX_WINDOWS) | ||
111 | Sleep(1); | ||
112 | #elif defined(BOOST_HAS_PTHREADS) | ||
113 | // g++ -Wextra warns on {} or {0} | ||
114 | struct timespec rqtp = { 0, 0 }; | ||
115 | |||
116 | // POSIX says that timespec has tv_sec and tv_nsec | ||
117 | // But it doesn't guarantee order or placement | ||
118 | |||
119 | rqtp.tv_sec = 0; | ||
120 | rqtp.tv_nsec = 1000; | ||
121 | |||
122 | nanosleep( &rqtp, nullptr ); | ||
123 | #else | ||
124 | #endif | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | public: | ||
130 | spinlock(char const* const desc = "hpx::lcos::local::spinlock") | ||
131 | : v_(0) | ||
132 | { | ||
133 | HPX_ITT_SYNC_CREATE(this, desc, ""); | ||
134 | } | ||
135 | |||
136 | ~spinlock() | ||
137 | { | ||
138 | HPX_ITT_SYNC_DESTROY(this); | ||
139 | } | ||
140 | |||
141 | void lock() | ||
142 | { | ||
143 | HPX_ITT_SYNC_PREPARE(this); | ||
144 | |||
145 | for (std::size_t k = 0; !acquire_lock(); ++k) | ||
146 | { | ||
147 | spinlock::yield(k); | ||
148 | } | ||
149 | |||
150 | HPX_ITT_SYNC_ACQUIRED(this); | ||
151 | util::register_lock(this); | ||
152 | } | ||
153 | |||
154 | bool try_lock() | ||
155 | { | ||
156 | HPX_ITT_SYNC_PREPARE(this); | ||
157 | |||
158 | bool r = acquire_lock(); //-V707 | ||
159 | |||
160 | if (r) { | ||
161 | HPX_ITT_SYNC_ACQUIRED(this); | ||
162 | util::register_lock(this); | ||
163 | return true; | ||
164 | } | ||
165 | |||
166 | HPX_ITT_SYNC_CANCEL(this); | ||
167 | return false; | ||
168 | } | ||
169 | |||
170 | void unlock() | ||
171 | { | ||
172 | HPX_ITT_SYNC_RELEASING(this); | ||
173 | |||
174 | relinquish_lock(); | ||
175 | |||
176 | HPX_ITT_SYNC_RELEASED(this); | ||
177 | util::unregister_lock(this); | ||
178 | } | ||
179 | |||
180 | private: | ||
181 | // returns whether the mutex has been acquired | ||
182 | bool acquire_lock() | ||
183 | { | ||
184 | #if !defined( BOOST_SP_HAS_SYNC ) | ||
185 | std::uint64_t r = BOOST_INTERLOCKED_EXCHANGE(&v_, 1); | ||
186 | BOOST_COMPILER_FENCE | ||
187 | #else | ||
188 ![]() | 0.5% | std::uint64_t r = __sync_lock_test_and_set(&v_, 1); | |
![]() | |||
189 | #endif | ||
190 | return r == 0; | ||
191 | } | ||
192 | |||
193 | void relinquish_lock() | ||
194 | { | ||
195 | #if !defined( BOOST_SP_HAS_SYNC ) | ||
196 | BOOST_COMPILER_FENCE | ||
197 | *const_cast<std::uint64_t volatile*>(&v_) = 0; | ||
198 | #else | ||
199 | __sync_lock_release(&v_); | ||
200 | #endif | ||
201 | } | ||
202 | }; | ||
203 | }}} | ||
204 | |||
205 | #endif // HPX_B3A83B49_92E0_4150_A551_488F9F5E1113 | ||
206 | |||
207 |
Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.