Line data Source code
1 : /*
2 : * (C) Copyright 2010 Marek Dopiera
3 : *
4 : * This file is part of CoherentDB.
5 : *
6 : * CoherentDB is free software: you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation, either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * CoherentDB is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public
17 : * License along with CoherentDB. If not, see
18 : * http://www.gnu.org/licenses/.
19 : */
20 :
21 : #ifndef THREAD_H_3295
22 : #define THREAD_H_3295
23 :
24 : #include <boost/thread/mutex.hpp>
25 : #include <boost/thread/condition_variable.hpp>
26 : #include <boost/noncopyable.hpp>
27 :
28 : #include <util/misc.h>
29 : #include <config/cmake_config.h>
30 : #include <debug/asserts.h>
31 :
32 : namespace coherent {
33 : namespace util {
34 :
35 :
36 : #ifdef HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT
37 : #define TAS_IMPL_GNU_BUILTIN
38 :
39 : #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
40 :
41 : #ifdef __i386__
42 : #define TAS_IMPL_ASM_i386
43 : #else
44 : #define TAS_IMPL_ASM_amd64
45 : #endif
46 : #else
47 : #error Your compiler is not gcc-4.1 or newer and your architecture is not\
48 : i386 neither amd64, so I dont know how to provide the test and set\
49 : operation.
50 : #endif
51 :
52 : namespace detail {
53 :
54 : template <class T>
55 : class scoped_lock_base : private boost::noncopyable {
56 :
57 : private:
58 : T &mutex;
59 : bool locked;
60 :
61 : protected:
62 : explicit scoped_lock_base(T & mutex); //doesn't try to lock the lock
63 :
64 : public:
65 : ~scoped_lock_base();
66 : void lock();
67 : void unlock();
68 : bool try_lock();
69 : bool owns_lock();
70 :
71 : };
72 :
73 : template <class T>
74 : class scoped_lock : public scoped_lock_base<T>
75 20000001 : {
76 : public:
77 : explicit scoped_lock(T & mutex);
78 : };
79 :
80 : template <class T>
81 : class scoped_try_lock : public scoped_lock_base<T>
82 : {
83 : public:
84 : explicit scoped_try_lock(T & mutex);
85 : };
86 :
87 : #ifdef TAS_IMPL_GNU_BUILTIN
88 :
89 : #define SPIN_IMPL int
90 : #define SPIN_IMPL_LOCKED 187
91 : #define SPIN_IMPL_UNLOCKED 245
92 : #define SPIN_IMPL_INITIALIZER SPIN_IMPL_UNLOCKED
93 :
94 20000001 : inline void SPIN_IMPL_LOCK(volatile SPIN_IMPL *lock)
95 : {
96 57151758 : while (unlikely(!__sync_bool_compare_and_swap(lock, SPIN_IMPL_UNLOCKED, SPIN_IMPL_LOCKED))) {}
97 20000001 : }
98 :
99 19999210 : inline void SPIN_IMPL_UNLOCK(volatile SPIN_IMPL *lock)
100 : {
101 19999210 : bool res = __sync_bool_compare_and_swap(lock, SPIN_IMPL_LOCKED, SPIN_IMPL_UNLOCKED);
102 : d_assert(res, "Spin lock implementation problem");
103 19999210 : }
104 :
105 1 : inline void SPIN_IMPL_INIT(volatile SPIN_IMPL *lock)
106 : {
107 1 : *lock = SPIN_IMPL_UNLOCKED;
108 1 : }
109 :
110 : inline bool SPIN_IMPL_TRYLOCK(volatile SPIN_IMPL *lock)
111 : {
112 : return __sync_bool_compare_and_swap(lock, SPIN_IMPL_UNLOCKED, SPIN_IMPL_LOCKED);
113 : }
114 :
115 : #elif defined(TAS_IMPL_ASM_i386) || defined(TAS_IMPL_ASM_amd64)
116 :
117 : #define SPIN_IMPL int
118 : #define SPIN_IMPL_LOCKED 187
119 : #define SPIN_IMPL_UNLOCKED 245
120 : #define SPIN_IMPL_INITIALIZER SPIN_IMPL_UNLOCKED
121 :
122 : #define EXCHANGE(lock, locker) {\
123 : asm volatile ("xchgl %1, (%0);" \
124 : :"=r"(lock), "=r"(locker) \
125 : :"0"(lock), "1"(locker) \
126 : );\
127 : }
128 :
129 : inline void SPIN_IMPL_LOCK(volatile SPIN_IMPL *lock)
130 : {
131 : volatile SPIN_IMPL locker = SPIN_IMPL_LOCKED;
132 : do {
133 : EXCHANGE(lock, locker);
134 : } while (unlikely(locker == SPIN_IMPL_LOCKED));
135 : d_assert(locker == SPIN_IMPL_UNLOCKED, "lock corruption: locker=" << locker);
136 : }
137 :
138 : inline void SPIN_IMPL_UNLOCK(volatile SPIN_IMPL *lock)
139 : {
140 : volatile SPIN_IMPL unlocker = SPIN_IMPL_UNLOCKED;
141 : EXCHANGE(lock, unlocker);
142 : }
143 :
144 : inline void SPIN_IMPL_INIT(volatile SPIN_IMPL *lock)
145 : {
146 : *lock = SPIN_IMPL_UNLOCKED;
147 : }
148 :
149 : inline bool SPIN_IMPL_TRYLOCK(volatile SPIN_IMPL *lock)
150 : {
151 : volatile SPIN_IMPL locker = SPIN_IMPL_LOCKED;
152 : EXCHANGE(lock, locker);
153 : return locker == SPIN_IMPL_UNLOCKED;
154 : }
155 :
156 : #endif /* spinlock type */
157 :
158 : template <class T>
159 19940827 : inline scoped_lock_base<T>::scoped_lock_base(T & mutex) : mutex(mutex), locked(false)
160 : {
161 19988130 : }
162 :
163 : template <class T>
164 : inline scoped_lock_base<T>::~scoped_lock_base()
165 20000001 : {
166 : if (this->locked)
167 20000001 : mutex.unlock();
168 20000001 : }
169 19981598 :
170 : template <class T>
171 : inline void scoped_lock_base<T>::lock()
172 19958272 : {
173 : d_assert(!this->locked, "Trying to acquire a locked lock");
174 19958272 : this->mutex.lock();
175 19958272 : this->locked = true;
176 20000001 : }
177 20000001 :
178 : template <class T>
179 : inline void scoped_lock_base<T>::unlock()
180 : {
181 : d_assert(this->locked, "Trying to unlock an already unlocked lock.");
182 : this->mutex.unlock();
183 : this->locked = false;
184 : }
185 :
186 : template <class T>
187 : inline bool scoped_lock_base<T>::try_lock()
188 : {
189 : d_assert(!this->locked, "Trying to acquire an already locked lock");
190 : this->locked = this->mutex.try_lock();
191 : return this->locked;
192 : }
193 :
194 : template <class T>
195 : inline bool scoped_lock_base<T>::owns_lock()
196 : {
197 : return this->locked;
198 : }
199 :
200 : template <class T>
201 : inline scoped_lock<T>::scoped_lock(T & mutex) : scoped_lock_base<T>(mutex)
202 : {
203 19994229 : this->lock();
204 : }
205 19960717 :
206 20000001 : template <class T>
207 : scoped_try_lock<T>::scoped_try_lock(T & mutex) : scoped_lock_base<T>(mutex)
208 : {
209 : this->try_lock();
210 : }
211 :
212 : } // namespace detail
213 :
214 : class spin_mutex : private boost::noncopyable {
215 : public:
216 1 : typedef detail::scoped_lock<spin_mutex> scoped_lock;
217 : typedef detail::scoped_try_lock<spin_mutex> scoped_try_lock;
218 :
219 : friend class detail::scoped_lock_base<spin_mutex>;
220 : friend class detail::scoped_try_lock<spin_mutex>;
221 : friend class detail::scoped_lock<spin_mutex>;
222 :
223 : inline spin_mutex()
224 : {
225 1 : detail::SPIN_IMPL_INIT(&lock_impl);
226 1 : }
227 1 :
228 1 : private:
229 : volatile SPIN_IMPL lock_impl;
230 :
231 : inline void lock()
232 : {
233 : detail::SPIN_IMPL_LOCK(&(this->lock_impl));
234 19985642 : }
235 :
236 19985642 : inline void unlock()
237 20000001 : {
238 : detail::SPIN_IMPL_UNLOCK(&(this->lock_impl));
239 20000001 : }
240 :
241 20000001 : inline bool try_lock()
242 19999684 : {
243 : return detail::SPIN_IMPL_TRYLOCK(&(this->lock_impl));
244 : }
245 :
246 : };
247 :
248 : class completion
249 : {
250 : public:
251 : completion();
252 36 : void wait();
253 : void complete();
254 : void reset();
255 : private:
256 : boost::mutex mutex;
257 : boost::condition_variable cond_var;
258 :
259 : bool completed;
260 : };
261 :
262 : } // namespace util
263 : } // namespace coherent
264 :
265 : #endif /* THREAD_H_3295 */
|