1// Support for concurrent programing -*- C++ -*- 
2 
3// Copyright (C) 2003-2019 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 
40namespace __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#ifndef __GTHREADS 
55 _S_single; 
56#elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY 
57 _S_atomic; 
58#else 
59 _S_mutex; 
60#endif 
61 
62 // NB: As this is used in libsupc++, need to only depend on 
63 // exception. No stdexception classes, no use of std::string. 
64 class __concurrence_lock_error : public std::exception 
65 { 
66 public: 
67 virtual char const* 
68 what() const throw() 
69 { return "__gnu_cxx::__concurrence_lock_error"; } 
70 }; 
71 
72 class __concurrence_unlock_error : public std::exception 
73 { 
74 public: 
75 virtual char const* 
76 what() const throw() 
77 { return "__gnu_cxx::__concurrence_unlock_error"; } 
78 }; 
79 
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 
96 // Substitute for concurrence_error object in the case of -fno-exceptions. 
97 inline void 
98 __throw_concurrence_lock_error() 
99 { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); } 
100 
101 inline void 
102 __throw_concurrence_unlock_error() 
103 { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); } 
104 
105#ifdef __GTHREAD_HAS_COND 
106 inline void 
107 __throw_concurrence_broadcast_error() 
108 { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); } 
109 
110 inline void 
111 __throw_concurrence_wait_error() 
112 { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); } 
113#endif 
114  
115 class __mutex  
116 { 
117 private: 
118#if __GTHREADS && defined __GTHREAD_MUTEX_INIT 
119 __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT; 
120#else 
121 __gthread_mutex_t _M_mutex; 
122#endif 
123 
124 __mutex(const __mutex&); 
125 __mutex& operator=(const __mutex&); 
126 
127 public: 
128 __mutex()  
129 {  
130#if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 
131 if (__gthread_active_p()) 
132 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 
133#endif 
134 } 
135 
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 
144 void lock() 
145 { 
146#if __GTHREADS 
147 if (__gthread_active_p()) 
148 { 
149 if (__gthread_mutex_lock(&_M_mutex) != 0) 
150 __throw_concurrence_lock_error(); 
151 } 
152#endif 
153 } 
154  
155 void unlock() 
156 { 
157#if __GTHREADS 
158 if (__gthread_active_p()) 
159 { 
160 if (__gthread_mutex_unlock(&_M_mutex) != 0) 
161 __throw_concurrence_unlock_error(); 
162 } 
163#endif 
164 } 
165 
166 __gthread_mutex_t* gthread_mutex(void) 
167 { return &_M_mutex; } 
168 }; 
169 
170 class __recursive_mutex  
171 { 
172 private: 
173#if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT 
174 __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 
175#else 
176 __gthread_recursive_mutex_t _M_mutex; 
177#endif 
178 
179 __recursive_mutex(const __recursive_mutex&); 
180 __recursive_mutex& operator=(const __recursive_mutex&); 
181 
182 public: 
183 __recursive_mutex()  
184 {  
185#if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 
186 if (__gthread_active_p()) 
187 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 
188#endif 
189 } 
190 
191#if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 
192 ~__recursive_mutex() 
193 { 
194 if (__gthread_active_p()) 
195 __gthread_recursive_mutex_destroy(&_M_mutex); 
196 } 
197#endif 
198 
199 void lock() 
200 {  
201#if __GTHREADS 
202 if (__gthread_active_p()) 
203 { 
204 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 
205 __throw_concurrence_lock_error(); 
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) 
216 __throw_concurrence_unlock_error(); 
217 } 
218#endif 
219 } 
220 
221 __gthread_recursive_mutex_t* gthread_recursive_mutex(void) 
222 { return &_M_mutex; } 
223 }; 
224 
225 /// Scoped lock idiom. 
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: 
231 typedef __mutex __mutex_type; 
232 
233 private: 
234 __mutex_type& _M_device; 
235 
236 __scoped_lock(const __scoped_lock&); 
237 __scoped_lock& operator=(const __scoped_lock&); 
238 
239 public: 
240 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 
241 { _M_device.lock(); } 
242 
243 ~__scoped_lock() throw() 
244 { _M_device.unlock(); } 
245 }; 
246 
247#ifdef __GTHREAD_HAS_COND 
248 class __cond 
249 { 
250 private: 
251#if __GTHREADS && defined __GTHREAD_COND_INIT 
252 __gthread_cond_t _M_cond = __GTHREAD_COND_INIT; 
253#else 
254 __gthread_cond_t _M_cond; 
255#endif 
256 
257 __cond(const __cond&); 
258 __cond& operator=(const __cond&); 
259 
260 public: 
261 __cond()  
262 {  
263#if __GTHREADS && ! defined __GTHREAD_COND_INIT 
264 if (__gthread_active_p()) 
265 __GTHREAD_COND_INIT_FUNCTION(&_M_cond); 
266#endif 
267 } 
268 
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 
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 
312_GLIBCXX_END_NAMESPACE_VERSION 
313} // namespace 
314 
315#endif 
316