]>
Commit | Line | Data |
---|---|---|
2e362c74 BK |
1 | // Support for concurrent programing -*- C++ -*- |
2 | ||
9c7f808d | 3 | // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
2e362c74 BK |
4 | // Free Software Foundation, Inc. |
5 | // | |
6 | // This file is part of the GNU ISO C++ Library. This library is free | |
7 | // software; you can redistribute it and/or modify it under the | |
8 | // terms of the GNU General Public License as published by the | |
748086b7 | 9 | // Free Software Foundation; either version 3, or (at your option) |
2e362c74 BK |
10 | // any later version. |
11 | ||
12 | // This library is distributed in the hope that it will be useful, | |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | // GNU General Public License for more details. | |
16 | ||
748086b7 JJ |
17 | // Under Section 7 of GPL version 3, you are granted additional |
18 | // permissions described in the GCC Runtime Library Exception, version | |
19 | // 3.1, as published by the Free Software Foundation. | |
20 | ||
21 | // You should have received a copy of the GNU General Public License and | |
22 | // a copy of the GCC Runtime Library Exception along with this program; | |
23 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
24 | // <http://www.gnu.org/licenses/>. | |
2e362c74 | 25 | |
f910786b BK |
26 | /** @file ext/concurrence.h |
27 | * This file is a GNU extension to the Standard C++ Library. | |
2e362c74 BK |
28 | */ |
29 | ||
30 | #ifndef _CONCURRENCE_H | |
31 | #define _CONCURRENCE_H 1 | |
32 | ||
9c7f808d PC |
33 | #pragma GCC system_header |
34 | ||
f15e02d2 | 35 | #include <exception> |
2e362c74 BK |
36 | #include <bits/gthr.h> |
37 | #include <bits/functexcept.h> | |
9916a9e4 JW |
38 | #include <bits/cpp_type_traits.h> |
39 | #include <ext/type_traits.h> | |
2e362c74 BK |
40 | |
41 | _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) | |
42 | ||
43 | // Available locking policies: | |
44 | // _S_single single-threaded code that doesn't need to be locked. | |
45 | // _S_mutex multi-threaded code that requires additional support | |
ee5ca789 | 46 | // from gthr.h or abstraction layers in concurrence.h. |
2e362c74 BK |
47 | // _S_atomic multi-threaded code using atomic operations. |
48 | enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; | |
49 | ||
50 | // Compile time constant that indicates prefered locking policy in | |
51 | // the current configuration. | |
52 | static const _Lock_policy __default_lock_policy = | |
53 | #ifdef __GTHREADS | |
8679a8ef PC |
54 | #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ |
55 | && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) | |
2e362c74 BK |
56 | _S_atomic; |
57 | #else | |
58 | _S_mutex; | |
59 | #endif | |
60 | #else | |
61 | _S_single; | |
62 | #endif | |
8679a8ef | 63 | |
f15e02d2 BK |
64 | // NB: As this is used in libsupc++, need to only depend on |
65 | // exception. No stdexception classes, no use of std::string. | |
56acf88c | 66 | class __concurrence_lock_error : public std::exception |
f15e02d2 BK |
67 | { |
68 | public: | |
69 | virtual char const* | |
70 | what() const throw() | |
56acf88c | 71 | { return "__gnu_cxx::__concurrence_lock_error"; } |
f15e02d2 BK |
72 | }; |
73 | ||
56acf88c | 74 | class __concurrence_unlock_error : public std::exception |
f15e02d2 BK |
75 | { |
76 | public: | |
77 | virtual char const* | |
78 | what() const throw() | |
56acf88c | 79 | { return "__gnu_cxx::__concurrence_unlock_error"; } |
f15e02d2 BK |
80 | }; |
81 | ||
afd82ef5 DK |
82 | class __concurrence_broadcast_error : public std::exception |
83 | { | |
84 | public: | |
85 | virtual char const* | |
86 | what() const throw() | |
87 | { return "__gnu_cxx::__concurrence_broadcast_error"; } | |
88 | }; | |
89 | ||
90 | class __concurrence_wait_error : public std::exception | |
91 | { | |
92 | public: | |
93 | virtual char const* | |
94 | what() const throw() | |
95 | { return "__gnu_cxx::__concurrence_wait_error"; } | |
96 | }; | |
97 | ||
f15e02d2 BK |
98 | // Substitute for concurrence_error object in the case of -fno-exceptions. |
99 | inline void | |
100 | __throw_concurrence_lock_error() | |
101 | { | |
102 | #if __EXCEPTIONS | |
56acf88c | 103 | throw __concurrence_lock_error(); |
f15e02d2 | 104 | #else |
87a20856 | 105 | __builtin_abort(); |
f15e02d2 BK |
106 | #endif |
107 | } | |
108 | ||
109 | inline void | |
110 | __throw_concurrence_unlock_error() | |
111 | { | |
112 | #if __EXCEPTIONS | |
56acf88c | 113 | throw __concurrence_unlock_error(); |
f15e02d2 | 114 | #else |
87a20856 | 115 | __builtin_abort(); |
f15e02d2 BK |
116 | #endif |
117 | } | |
2e362c74 | 118 | |
afd82ef5 DK |
119 | #ifdef __GTHREAD_HAS_COND |
120 | inline void | |
121 | __throw_concurrence_broadcast_error() | |
122 | { | |
123 | #if __EXCEPTIONS | |
124 | throw __concurrence_broadcast_error(); | |
125 | #else | |
126 | __builtin_abort(); | |
127 | #endif | |
128 | } | |
129 | ||
130 | inline void | |
131 | __throw_concurrence_wait_error() | |
132 | { | |
133 | #if __EXCEPTIONS | |
134 | throw __concurrence_wait_error(); | |
135 | #else | |
136 | __builtin_abort(); | |
137 | #endif | |
138 | } | |
139 | #endif | |
140 | ||
2e362c74 BK |
141 | class __mutex |
142 | { | |
143 | private: | |
144 | __gthread_mutex_t _M_mutex; | |
145 | ||
146 | __mutex(const __mutex&); | |
147 | __mutex& operator=(const __mutex&); | |
148 | ||
149 | public: | |
150 | __mutex() | |
151 | { | |
152 | #if __GTHREADS | |
153 | if (__gthread_active_p()) | |
154 | { | |
155 | #if defined __GTHREAD_MUTEX_INIT | |
156 | __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; | |
157 | _M_mutex = __tmp; | |
158 | #else | |
b128c5ef | 159 | __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); |
2e362c74 BK |
160 | #endif |
161 | } | |
162 | #endif | |
163 | } | |
164 | ||
9916a9e4 JW |
165 | #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT |
166 | ~__mutex() | |
167 | { | |
168 | if (__gthread_active_p()) | |
169 | __gthread_mutex_destroy(&_M_mutex); | |
170 | } | |
171 | #endif | |
172 | ||
2e362c74 | 173 | void lock() |
56acf88c | 174 | { |
2e362c74 BK |
175 | #if __GTHREADS |
176 | if (__gthread_active_p()) | |
177 | { | |
178 | if (__gthread_mutex_lock(&_M_mutex) != 0) | |
f15e02d2 | 179 | __throw_concurrence_lock_error(); |
2e362c74 BK |
180 | } |
181 | #endif | |
182 | } | |
183 | ||
184 | void unlock() | |
56acf88c | 185 | { |
2e362c74 BK |
186 | #if __GTHREADS |
187 | if (__gthread_active_p()) | |
188 | { | |
189 | if (__gthread_mutex_unlock(&_M_mutex) != 0) | |
f15e02d2 | 190 | __throw_concurrence_unlock_error(); |
2e362c74 BK |
191 | } |
192 | #endif | |
193 | } | |
afd82ef5 DK |
194 | |
195 | __gthread_mutex_t* gthread_mutex(void) | |
196 | { return &_M_mutex; } | |
2e362c74 BK |
197 | }; |
198 | ||
199 | class __recursive_mutex | |
200 | { | |
201 | private: | |
202 | __gthread_recursive_mutex_t _M_mutex; | |
203 | ||
204 | __recursive_mutex(const __recursive_mutex&); | |
205 | __recursive_mutex& operator=(const __recursive_mutex&); | |
206 | ||
207 | public: | |
208 | __recursive_mutex() | |
209 | { | |
210 | #if __GTHREADS | |
211 | if (__gthread_active_p()) | |
212 | { | |
213 | #if defined __GTHREAD_RECURSIVE_MUTEX_INIT | |
214 | __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT; | |
215 | _M_mutex = __tmp; | |
216 | #else | |
b128c5ef | 217 | __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); |
2e362c74 BK |
218 | #endif |
219 | } | |
220 | #endif | |
221 | } | |
222 | ||
9916a9e4 JW |
223 | #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT |
224 | ~__recursive_mutex() | |
225 | { | |
226 | if (__gthread_active_p()) | |
227 | _S_destroy(&_M_mutex); | |
228 | } | |
229 | #endif | |
230 | ||
2e362c74 BK |
231 | void lock() |
232 | { | |
233 | #if __GTHREADS | |
234 | if (__gthread_active_p()) | |
235 | { | |
236 | if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) | |
f15e02d2 | 237 | __throw_concurrence_lock_error(); |
2e362c74 BK |
238 | } |
239 | #endif | |
240 | } | |
241 | ||
242 | void unlock() | |
243 | { | |
244 | #if __GTHREADS | |
245 | if (__gthread_active_p()) | |
246 | { | |
247 | if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) | |
f15e02d2 | 248 | __throw_concurrence_unlock_error(); |
2e362c74 BK |
249 | } |
250 | #endif | |
251 | } | |
afd82ef5 DK |
252 | |
253 | __gthread_recursive_mutex_t* gthread_recursive_mutex(void) | |
9916a9e4 JW |
254 | { return &_M_mutex; } |
255 | ||
256 | #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT | |
257 | // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy | |
258 | // so we need to obtain a __gthread_mutex_t to destroy | |
259 | private: | |
260 | template<typename _Mx, typename _Rm> | |
261 | static void | |
262 | _S_destroy_win32(_Mx* __mx, _Rm const* __rmx) | |
263 | { | |
264 | __mx->counter = __rmx->counter; | |
265 | __mx->sema = __rmx->sema; | |
266 | __gthread_mutex_destroy(__mx); | |
267 | } | |
268 | ||
269 | // matches a gthr-win32.h recursive mutex | |
270 | template<typename _Rm> | |
271 | static typename __enable_if<sizeof(&_Rm::sema), void>::__type | |
272 | _S_destroy(_Rm* __mx) | |
273 | { | |
274 | __gthread_mutex_t __tmp; | |
275 | _S_destroy_win32(&__tmp, __mx); | |
276 | } | |
277 | ||
278 | // matches a recursive mutex with a member 'actual' | |
279 | template<typename _Rm> | |
280 | static typename __enable_if<sizeof(&_Rm::actual), void>::__type | |
281 | _S_destroy(_Rm* __mx) | |
282 | { __gthread_mutex_destroy(&__mx->actual); } | |
283 | ||
284 | // matches when there's only one mutex type | |
285 | template<typename _Rm> | |
286 | static typename | |
287 | __enable_if<std::__are_same<_Rm, __gthread_mutex_t>::__value, | |
288 | void>::__type | |
289 | _S_destroy(_Rm* __mx) | |
290 | { __gthread_mutex_destroy(__mx); } | |
291 | #endif | |
2e362c74 BK |
292 | }; |
293 | ||
939759fc | 294 | /// Scoped lock idiom. |
2e362c74 BK |
295 | // Acquire the mutex here with a constructor call, then release with |
296 | // the destructor call in accordance with RAII style. | |
297 | class __scoped_lock | |
298 | { | |
299 | public: | |
56acf88c | 300 | typedef __mutex __mutex_type; |
2e362c74 BK |
301 | |
302 | private: | |
56acf88c | 303 | __mutex_type& _M_device; |
2e362c74 BK |
304 | |
305 | __scoped_lock(const __scoped_lock&); | |
306 | __scoped_lock& operator=(const __scoped_lock&); | |
307 | ||
308 | public: | |
56acf88c | 309 | explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) |
2e362c74 BK |
310 | { _M_device.lock(); } |
311 | ||
312 | ~__scoped_lock() throw() | |
313 | { _M_device.unlock(); } | |
314 | }; | |
315 | ||
afd82ef5 DK |
316 | #ifdef __GTHREAD_HAS_COND |
317 | class __cond | |
318 | { | |
319 | private: | |
320 | __gthread_cond_t _M_cond; | |
321 | ||
322 | __cond(const __cond&); | |
323 | __cond& operator=(const __cond&); | |
324 | ||
325 | public: | |
326 | __cond() | |
327 | { | |
328 | #if __GTHREADS | |
329 | if (__gthread_active_p()) | |
330 | { | |
331 | #if defined __GTHREAD_COND_INIT | |
332 | __gthread_cond_t __tmp = __GTHREAD_COND_INIT; | |
333 | _M_cond = __tmp; | |
334 | #else | |
f05d0fc1 | 335 | __GTHREAD_COND_INIT_FUNCTION(&_M_cond); |
afd82ef5 DK |
336 | #endif |
337 | } | |
338 | #endif | |
339 | } | |
340 | ||
9916a9e4 JW |
341 | #if __GTHREADS && ! defined __GTHREAD_COND_INIT |
342 | ~__cond() | |
343 | { | |
344 | if (__gthread_active_p()) | |
345 | __gthread_cond_destroy(&_M_cond); | |
346 | } | |
347 | #endif | |
348 | ||
afd82ef5 DK |
349 | void broadcast() |
350 | { | |
351 | #if __GTHREADS | |
352 | if (__gthread_active_p()) | |
353 | { | |
354 | if (__gthread_cond_broadcast(&_M_cond) != 0) | |
355 | __throw_concurrence_broadcast_error(); | |
356 | } | |
357 | #endif | |
358 | } | |
359 | ||
360 | void wait(__mutex *mutex) | |
361 | { | |
362 | #if __GTHREADS | |
363 | { | |
364 | if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) | |
365 | __throw_concurrence_wait_error(); | |
366 | } | |
367 | #endif | |
368 | } | |
369 | ||
370 | void wait_recursive(__recursive_mutex *mutex) | |
371 | { | |
372 | #if __GTHREADS | |
373 | { | |
374 | if (__gthread_cond_wait_recursive(&_M_cond, | |
375 | mutex->gthread_recursive_mutex()) | |
376 | != 0) | |
377 | __throw_concurrence_wait_error(); | |
378 | } | |
379 | #endif | |
380 | } | |
381 | }; | |
382 | #endif | |
383 | ||
2e362c74 BK |
384 | _GLIBCXX_END_NAMESPACE |
385 | ||
386 | #endif |