]>
Commit | Line | Data |
---|---|---|
2e362c74 BK |
1 | // Support for concurrent programing -*- C++ -*- |
2 | ||
87a20856 | 3 | // Copyright (C) 2003, 2004, 2005, 2006, 2007 |
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 | |
9 | // Free Software Foundation; either version 2, or (at your option) | |
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 | ||
17 | // You should have received a copy of the GNU General Public License along | |
18 | // with this library; see the file COPYING. If not, write to the Free | |
19 | // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | |
20 | // USA. | |
21 | ||
22 | // As a special exception, you may use this file as part of a free software | |
23 | // library without restriction. Specifically, if other files instantiate | |
24 | // templates or use macros or inline functions from this file, or you compile | |
25 | // this file and link it with other files to produce an executable, this | |
26 | // file does not by itself cause the resulting executable to be covered by | |
27 | // the GNU General Public License. This exception does not however | |
28 | // invalidate any other reasons why the executable file might be covered by | |
29 | // the GNU General Public License. | |
30 | ||
31 | /** @file concurrence.h | |
32 | * This is an internal header file, included by other library headers. | |
33 | * You should not attempt to use it directly. | |
34 | */ | |
35 | ||
36 | #ifndef _CONCURRENCE_H | |
37 | #define _CONCURRENCE_H 1 | |
38 | ||
f15e02d2 | 39 | #include <exception> |
2e362c74 BK |
40 | #include <bits/gthr.h> |
41 | #include <bits/functexcept.h> | |
42 | ||
43 | _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) | |
44 | ||
45 | // Available locking policies: | |
46 | // _S_single single-threaded code that doesn't need to be locked. | |
47 | // _S_mutex multi-threaded code that requires additional support | |
ee5ca789 | 48 | // from gthr.h or abstraction layers in concurrence.h. |
2e362c74 BK |
49 | // _S_atomic multi-threaded code using atomic operations. |
50 | enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; | |
51 | ||
52 | // Compile time constant that indicates prefered locking policy in | |
53 | // the current configuration. | |
54 | static const _Lock_policy __default_lock_policy = | |
55 | #ifdef __GTHREADS | |
8679a8ef PC |
56 | #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ |
57 | && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) | |
2e362c74 BK |
58 | _S_atomic; |
59 | #else | |
60 | _S_mutex; | |
61 | #endif | |
62 | #else | |
63 | _S_single; | |
64 | #endif | |
8679a8ef | 65 | |
f15e02d2 BK |
66 | // NB: As this is used in libsupc++, need to only depend on |
67 | // exception. No stdexception classes, no use of std::string. | |
56acf88c | 68 | class __concurrence_lock_error : public std::exception |
f15e02d2 BK |
69 | { |
70 | public: | |
71 | virtual char const* | |
72 | what() const throw() | |
56acf88c | 73 | { return "__gnu_cxx::__concurrence_lock_error"; } |
f15e02d2 BK |
74 | }; |
75 | ||
56acf88c | 76 | class __concurrence_unlock_error : public std::exception |
f15e02d2 BK |
77 | { |
78 | public: | |
79 | virtual char const* | |
80 | what() const throw() | |
56acf88c | 81 | { return "__gnu_cxx::__concurrence_unlock_error"; } |
f15e02d2 BK |
82 | }; |
83 | ||
afd82ef5 DK |
84 | class __concurrence_broadcast_error : public std::exception |
85 | { | |
86 | public: | |
87 | virtual char const* | |
88 | what() const throw() | |
89 | { return "__gnu_cxx::__concurrence_broadcast_error"; } | |
90 | }; | |
91 | ||
92 | class __concurrence_wait_error : public std::exception | |
93 | { | |
94 | public: | |
95 | virtual char const* | |
96 | what() const throw() | |
97 | { return "__gnu_cxx::__concurrence_wait_error"; } | |
98 | }; | |
99 | ||
f15e02d2 BK |
100 | // Substitute for concurrence_error object in the case of -fno-exceptions. |
101 | inline void | |
102 | __throw_concurrence_lock_error() | |
103 | { | |
104 | #if __EXCEPTIONS | |
56acf88c | 105 | throw __concurrence_lock_error(); |
f15e02d2 | 106 | #else |
87a20856 | 107 | __builtin_abort(); |
f15e02d2 BK |
108 | #endif |
109 | } | |
110 | ||
111 | inline void | |
112 | __throw_concurrence_unlock_error() | |
113 | { | |
114 | #if __EXCEPTIONS | |
56acf88c | 115 | throw __concurrence_unlock_error(); |
f15e02d2 | 116 | #else |
87a20856 | 117 | __builtin_abort(); |
f15e02d2 BK |
118 | #endif |
119 | } | |
2e362c74 | 120 | |
afd82ef5 DK |
121 | #ifdef __GTHREAD_HAS_COND |
122 | inline void | |
123 | __throw_concurrence_broadcast_error() | |
124 | { | |
125 | #if __EXCEPTIONS | |
126 | throw __concurrence_broadcast_error(); | |
127 | #else | |
128 | __builtin_abort(); | |
129 | #endif | |
130 | } | |
131 | ||
132 | inline void | |
133 | __throw_concurrence_wait_error() | |
134 | { | |
135 | #if __EXCEPTIONS | |
136 | throw __concurrence_wait_error(); | |
137 | #else | |
138 | __builtin_abort(); | |
139 | #endif | |
140 | } | |
141 | #endif | |
142 | ||
2e362c74 BK |
143 | class __mutex |
144 | { | |
145 | private: | |
146 | __gthread_mutex_t _M_mutex; | |
147 | ||
148 | __mutex(const __mutex&); | |
149 | __mutex& operator=(const __mutex&); | |
150 | ||
151 | public: | |
152 | __mutex() | |
153 | { | |
154 | #if __GTHREADS | |
155 | if (__gthread_active_p()) | |
156 | { | |
157 | #if defined __GTHREAD_MUTEX_INIT | |
158 | __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; | |
159 | _M_mutex = __tmp; | |
160 | #else | |
b128c5ef | 161 | __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); |
2e362c74 BK |
162 | #endif |
163 | } | |
164 | #endif | |
165 | } | |
166 | ||
167 | void lock() | |
56acf88c | 168 | { |
2e362c74 BK |
169 | #if __GTHREADS |
170 | if (__gthread_active_p()) | |
171 | { | |
172 | if (__gthread_mutex_lock(&_M_mutex) != 0) | |
f15e02d2 | 173 | __throw_concurrence_lock_error(); |
2e362c74 BK |
174 | } |
175 | #endif | |
176 | } | |
177 | ||
178 | void unlock() | |
56acf88c | 179 | { |
2e362c74 BK |
180 | #if __GTHREADS |
181 | if (__gthread_active_p()) | |
182 | { | |
183 | if (__gthread_mutex_unlock(&_M_mutex) != 0) | |
f15e02d2 | 184 | __throw_concurrence_unlock_error(); |
2e362c74 BK |
185 | } |
186 | #endif | |
187 | } | |
afd82ef5 DK |
188 | |
189 | __gthread_mutex_t* gthread_mutex(void) | |
190 | { return &_M_mutex; } | |
2e362c74 BK |
191 | }; |
192 | ||
193 | class __recursive_mutex | |
194 | { | |
195 | private: | |
196 | __gthread_recursive_mutex_t _M_mutex; | |
197 | ||
198 | __recursive_mutex(const __recursive_mutex&); | |
199 | __recursive_mutex& operator=(const __recursive_mutex&); | |
200 | ||
201 | public: | |
202 | __recursive_mutex() | |
203 | { | |
204 | #if __GTHREADS | |
205 | if (__gthread_active_p()) | |
206 | { | |
207 | #if defined __GTHREAD_RECURSIVE_MUTEX_INIT | |
208 | __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT; | |
209 | _M_mutex = __tmp; | |
210 | #else | |
b128c5ef | 211 | __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); |
2e362c74 BK |
212 | #endif |
213 | } | |
214 | #endif | |
215 | } | |
216 | ||
217 | void lock() | |
218 | { | |
219 | #if __GTHREADS | |
220 | if (__gthread_active_p()) | |
221 | { | |
222 | if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) | |
f15e02d2 | 223 | __throw_concurrence_lock_error(); |
2e362c74 BK |
224 | } |
225 | #endif | |
226 | } | |
227 | ||
228 | void unlock() | |
229 | { | |
230 | #if __GTHREADS | |
231 | if (__gthread_active_p()) | |
232 | { | |
233 | if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) | |
f15e02d2 | 234 | __throw_concurrence_unlock_error(); |
2e362c74 BK |
235 | } |
236 | #endif | |
237 | } | |
afd82ef5 DK |
238 | |
239 | __gthread_recursive_mutex_t* gthread_recursive_mutex(void) | |
240 | { return &_M_mutex; } | |
2e362c74 BK |
241 | }; |
242 | ||
939759fc | 243 | /// Scoped lock idiom. |
2e362c74 BK |
244 | // Acquire the mutex here with a constructor call, then release with |
245 | // the destructor call in accordance with RAII style. | |
246 | class __scoped_lock | |
247 | { | |
248 | public: | |
56acf88c | 249 | typedef __mutex __mutex_type; |
2e362c74 BK |
250 | |
251 | private: | |
56acf88c | 252 | __mutex_type& _M_device; |
2e362c74 BK |
253 | |
254 | __scoped_lock(const __scoped_lock&); | |
255 | __scoped_lock& operator=(const __scoped_lock&); | |
256 | ||
257 | public: | |
56acf88c | 258 | explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) |
2e362c74 BK |
259 | { _M_device.lock(); } |
260 | ||
261 | ~__scoped_lock() throw() | |
262 | { _M_device.unlock(); } | |
263 | }; | |
264 | ||
afd82ef5 DK |
265 | #ifdef __GTHREAD_HAS_COND |
266 | class __cond | |
267 | { | |
268 | private: | |
269 | __gthread_cond_t _M_cond; | |
270 | ||
271 | __cond(const __cond&); | |
272 | __cond& operator=(const __cond&); | |
273 | ||
274 | public: | |
275 | __cond() | |
276 | { | |
277 | #if __GTHREADS | |
278 | if (__gthread_active_p()) | |
279 | { | |
280 | #if defined __GTHREAD_COND_INIT | |
281 | __gthread_cond_t __tmp = __GTHREAD_COND_INIT; | |
282 | _M_cond = __tmp; | |
283 | #else | |
f05d0fc1 | 284 | __GTHREAD_COND_INIT_FUNCTION(&_M_cond); |
afd82ef5 DK |
285 | #endif |
286 | } | |
287 | #endif | |
288 | } | |
289 | ||
290 | void broadcast() | |
291 | { | |
292 | #if __GTHREADS | |
293 | if (__gthread_active_p()) | |
294 | { | |
295 | if (__gthread_cond_broadcast(&_M_cond) != 0) | |
296 | __throw_concurrence_broadcast_error(); | |
297 | } | |
298 | #endif | |
299 | } | |
300 | ||
301 | void wait(__mutex *mutex) | |
302 | { | |
303 | #if __GTHREADS | |
304 | { | |
305 | if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) | |
306 | __throw_concurrence_wait_error(); | |
307 | } | |
308 | #endif | |
309 | } | |
310 | ||
311 | void wait_recursive(__recursive_mutex *mutex) | |
312 | { | |
313 | #if __GTHREADS | |
314 | { | |
315 | if (__gthread_cond_wait_recursive(&_M_cond, | |
316 | mutex->gthread_recursive_mutex()) | |
317 | != 0) | |
318 | __throw_concurrence_wait_error(); | |
319 | } | |
320 | #endif | |
321 | } | |
322 | }; | |
323 | #endif | |
324 | ||
2e362c74 BK |
325 | _GLIBCXX_END_NAMESPACE |
326 | ||
327 | #endif |