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