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