]>
Commit | Line | Data |
---|---|---|
2e362c74 BK |
1 | // Support for concurrent programing -*- C++ -*- |
2 | ||
99dee823 | 3 | // Copyright (C) 2003-2021 Free Software Foundation, Inc. |
2e362c74 BK |
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 | |
748086b7 | 8 | // Free Software Foundation; either version 3, or (at your option) |
2e362c74 BK |
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 | ||
748086b7 JJ |
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/>. | |
2e362c74 | 24 | |
f910786b BK |
25 | /** @file ext/concurrence.h |
26 | * This file is a GNU extension to the Standard C++ Library. | |
2e362c74 BK |
27 | */ |
28 | ||
29 | #ifndef _CONCURRENCE_H | |
30 | #define _CONCURRENCE_H 1 | |
31 | ||
9c7f808d PC |
32 | #pragma GCC system_header |
33 | ||
f15e02d2 | 34 | #include <exception> |
2e362c74 BK |
35 | #include <bits/gthr.h> |
36 | #include <bits/functexcept.h> | |
9916a9e4 JW |
37 | #include <bits/cpp_type_traits.h> |
38 | #include <ext/type_traits.h> | |
2e362c74 | 39 | |
12ffa228 BK |
40 | namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) |
41 | { | |
42 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
2e362c74 BK |
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 | |
ee5ca789 | 47 | // from gthr.h or abstraction layers in concurrence.h. |
2e362c74 BK |
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 = | |
da29d2a3 JW |
54 | #ifndef __GTHREADS |
55 | _S_single; | |
56 | #elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY | |
2e362c74 BK |
57 | _S_atomic; |
58 | #else | |
59 | _S_mutex; | |
60 | #endif | |
8679a8ef | 61 | |
f15e02d2 BK |
62 | // NB: As this is used in libsupc++, need to only depend on |
63 | // exception. No stdexception classes, no use of std::string. | |
56acf88c | 64 | class __concurrence_lock_error : public std::exception |
f15e02d2 BK |
65 | { |
66 | public: | |
67 | virtual char const* | |
68 | what() const throw() | |
56acf88c | 69 | { return "__gnu_cxx::__concurrence_lock_error"; } |
f15e02d2 BK |
70 | }; |
71 | ||
56acf88c | 72 | class __concurrence_unlock_error : public std::exception |
f15e02d2 BK |
73 | { |
74 | public: | |
75 | virtual char const* | |
76 | what() const throw() | |
56acf88c | 77 | { return "__gnu_cxx::__concurrence_unlock_error"; } |
f15e02d2 BK |
78 | }; |
79 | ||
afd82ef5 DK |
80 | class __concurrence_broadcast_error : public std::exception |
81 | { | |
82 | public: | |
83 | virtual char const* | |
84 | what() const throw() | |
85 | { return "__gnu_cxx::__concurrence_broadcast_error"; } | |
86 | }; | |
87 | ||
88 | class __concurrence_wait_error : public std::exception | |
89 | { | |
90 | public: | |
91 | virtual char const* | |
92 | what() const throw() | |
93 | { return "__gnu_cxx::__concurrence_wait_error"; } | |
94 | }; | |
95 | ||
f15e02d2 BK |
96 | // Substitute for concurrence_error object in the case of -fno-exceptions. |
97 | inline void | |
98 | __throw_concurrence_lock_error() | |
54ba39f5 | 99 | { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); } |
f15e02d2 BK |
100 | |
101 | inline void | |
102 | __throw_concurrence_unlock_error() | |
54ba39f5 | 103 | { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); } |
2e362c74 | 104 | |
afd82ef5 DK |
105 | #ifdef __GTHREAD_HAS_COND |
106 | inline void | |
107 | __throw_concurrence_broadcast_error() | |
54ba39f5 | 108 | { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); } |
afd82ef5 DK |
109 | |
110 | inline void | |
111 | __throw_concurrence_wait_error() | |
54ba39f5 | 112 | { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); } |
afd82ef5 DK |
113 | #endif |
114 | ||
2e362c74 BK |
115 | class __mutex |
116 | { | |
117 | private: | |
eb407c34 | 118 | #if __GTHREADS && defined __GTHREAD_MUTEX_INIT |
01f83b7d JW |
119 | __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT; |
120 | #else | |
2e362c74 | 121 | __gthread_mutex_t _M_mutex; |
01f83b7d | 122 | #endif |
2e362c74 BK |
123 | |
124 | __mutex(const __mutex&); | |
125 | __mutex& operator=(const __mutex&); | |
126 | ||
127 | public: | |
128 | __mutex() | |
129 | { | |
eb407c34 | 130 | #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT |
2e362c74 | 131 | if (__gthread_active_p()) |
eb407c34 | 132 | __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); |
2e362c74 | 133 | #endif |
2e362c74 BK |
134 | } |
135 | ||
9916a9e4 JW |
136 | #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT |
137 | ~__mutex() | |
138 | { | |
139 | if (__gthread_active_p()) | |
140 | __gthread_mutex_destroy(&_M_mutex); | |
141 | } | |
142 | #endif | |
143 | ||
2e362c74 | 144 | void lock() |
56acf88c | 145 | { |
2e362c74 BK |
146 | #if __GTHREADS |
147 | if (__gthread_active_p()) | |
148 | { | |
149 | if (__gthread_mutex_lock(&_M_mutex) != 0) | |
f15e02d2 | 150 | __throw_concurrence_lock_error(); |
2e362c74 BK |
151 | } |
152 | #endif | |
153 | } | |
154 | ||
155 | void unlock() | |
56acf88c | 156 | { |
2e362c74 BK |
157 | #if __GTHREADS |
158 | if (__gthread_active_p()) | |
159 | { | |
160 | if (__gthread_mutex_unlock(&_M_mutex) != 0) | |
f15e02d2 | 161 | __throw_concurrence_unlock_error(); |
2e362c74 BK |
162 | } |
163 | #endif | |
164 | } | |
afd82ef5 DK |
165 | |
166 | __gthread_mutex_t* gthread_mutex(void) | |
167 | { return &_M_mutex; } | |
2e362c74 BK |
168 | }; |
169 | ||
170 | class __recursive_mutex | |
171 | { | |
172 | private: | |
eb407c34 | 173 | #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT |
01f83b7d JW |
174 | __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; |
175 | #else | |
2e362c74 | 176 | __gthread_recursive_mutex_t _M_mutex; |
01f83b7d | 177 | #endif |
2e362c74 BK |
178 | |
179 | __recursive_mutex(const __recursive_mutex&); | |
180 | __recursive_mutex& operator=(const __recursive_mutex&); | |
181 | ||
182 | public: | |
183 | __recursive_mutex() | |
184 | { | |
eb407c34 | 185 | #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT |
2e362c74 | 186 | if (__gthread_active_p()) |
eb407c34 | 187 | __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); |
2e362c74 | 188 | #endif |
2e362c74 BK |
189 | } |
190 | ||
9916a9e4 JW |
191 | #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT |
192 | ~__recursive_mutex() | |
193 | { | |
194 | if (__gthread_active_p()) | |
1504e3e1 | 195 | __gthread_recursive_mutex_destroy(&_M_mutex); |
9916a9e4 JW |
196 | } |
197 | #endif | |
198 | ||
2e362c74 BK |
199 | void lock() |
200 | { | |
201 | #if __GTHREADS | |
202 | if (__gthread_active_p()) | |
203 | { | |
204 | if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) | |
f15e02d2 | 205 | __throw_concurrence_lock_error(); |
2e362c74 BK |
206 | } |
207 | #endif | |
208 | } | |
209 | ||
210 | void unlock() | |
211 | { | |
212 | #if __GTHREADS | |
213 | if (__gthread_active_p()) | |
214 | { | |
215 | if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) | |
f15e02d2 | 216 | __throw_concurrence_unlock_error(); |
2e362c74 BK |
217 | } |
218 | #endif | |
219 | } | |
afd82ef5 DK |
220 | |
221 | __gthread_recursive_mutex_t* gthread_recursive_mutex(void) | |
9916a9e4 | 222 | { return &_M_mutex; } |
2e362c74 BK |
223 | }; |
224 | ||
939759fc | 225 | /// Scoped lock idiom. |
2e362c74 BK |
226 | // Acquire the mutex here with a constructor call, then release with |
227 | // the destructor call in accordance with RAII style. | |
228 | class __scoped_lock | |
229 | { | |
230 | public: | |
56acf88c | 231 | typedef __mutex __mutex_type; |
2e362c74 BK |
232 | |
233 | private: | |
56acf88c | 234 | __mutex_type& _M_device; |
2e362c74 BK |
235 | |
236 | __scoped_lock(const __scoped_lock&); | |
237 | __scoped_lock& operator=(const __scoped_lock&); | |
238 | ||
239 | public: | |
56acf88c | 240 | explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) |
2e362c74 BK |
241 | { _M_device.lock(); } |
242 | ||
243 | ~__scoped_lock() throw() | |
244 | { _M_device.unlock(); } | |
245 | }; | |
246 | ||
afd82ef5 DK |
247 | #ifdef __GTHREAD_HAS_COND |
248 | class __cond | |
249 | { | |
250 | private: | |
eb407c34 | 251 | #if __GTHREADS && defined __GTHREAD_COND_INIT |
01f83b7d JW |
252 | __gthread_cond_t _M_cond = __GTHREAD_COND_INIT; |
253 | #else | |
afd82ef5 | 254 | __gthread_cond_t _M_cond; |
01f83b7d | 255 | #endif |
afd82ef5 DK |
256 | |
257 | __cond(const __cond&); | |
258 | __cond& operator=(const __cond&); | |
259 | ||
260 | public: | |
261 | __cond() | |
262 | { | |
eb407c34 | 263 | #if __GTHREADS && ! defined __GTHREAD_COND_INIT |
afd82ef5 | 264 | if (__gthread_active_p()) |
eb407c34 | 265 | __GTHREAD_COND_INIT_FUNCTION(&_M_cond); |
afd82ef5 | 266 | #endif |
afd82ef5 DK |
267 | } |
268 | ||
9916a9e4 JW |
269 | #if __GTHREADS && ! defined __GTHREAD_COND_INIT |
270 | ~__cond() | |
271 | { | |
272 | if (__gthread_active_p()) | |
273 | __gthread_cond_destroy(&_M_cond); | |
274 | } | |
275 | #endif | |
276 | ||
afd82ef5 DK |
277 | void broadcast() |
278 | { | |
279 | #if __GTHREADS | |
280 | if (__gthread_active_p()) | |
281 | { | |
282 | if (__gthread_cond_broadcast(&_M_cond) != 0) | |
283 | __throw_concurrence_broadcast_error(); | |
284 | } | |
285 | #endif | |
286 | } | |
287 | ||
288 | void wait(__mutex *mutex) | |
289 | { | |
290 | #if __GTHREADS | |
291 | { | |
292 | if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) | |
293 | __throw_concurrence_wait_error(); | |
294 | } | |
295 | #endif | |
296 | } | |
297 | ||
298 | void wait_recursive(__recursive_mutex *mutex) | |
299 | { | |
300 | #if __GTHREADS | |
301 | { | |
302 | if (__gthread_cond_wait_recursive(&_M_cond, | |
303 | mutex->gthread_recursive_mutex()) | |
304 | != 0) | |
305 | __throw_concurrence_wait_error(); | |
306 | } | |
307 | #endif | |
308 | } | |
309 | }; | |
310 | #endif | |
311 | ||
12ffa228 BK |
312 | _GLIBCXX_END_NAMESPACE_VERSION |
313 | } // namespace | |
2e362c74 BK |
314 | |
315 | #endif |