OSDN Git Service

2010-11-18 Jonathan Wakely <jwakely.gcc@gmail.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / ext / concurrence.h
1 // Support for concurrent programing -*- C++ -*-
2
3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
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 3, 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 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 // <http://www.gnu.org/licenses/>.
25
26 /** @file concurrence.h
27  *  This is an internal header file, included by other library headers.
28  *  You should not attempt to use it directly.
29  */
30
31 #ifndef _CONCURRENCE_H
32 #define _CONCURRENCE_H 1
33
34 #pragma GCC system_header
35
36 #include <exception>
37 #include <bits/gthr.h> 
38 #include <bits/functexcept.h>
39 #include <bits/cpp_type_traits.h>
40 #include <ext/type_traits.h>
41
42 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
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   {
103 #if __EXCEPTIONS
104     throw __concurrence_lock_error();
105 #else
106     __builtin_abort();
107 #endif
108   }
109
110   inline void
111   __throw_concurrence_unlock_error()
112   {
113 #if __EXCEPTIONS
114     throw __concurrence_unlock_error();
115 #else
116     __builtin_abort();
117 #endif
118   }
119
120 #ifdef __GTHREAD_HAS_COND
121   inline void
122   __throw_concurrence_broadcast_error()
123   {
124 #if __EXCEPTIONS
125     throw __concurrence_broadcast_error();
126 #else
127     __builtin_abort();
128 #endif
129   }
130
131   inline void
132   __throw_concurrence_wait_error()
133   {
134 #if __EXCEPTIONS
135     throw __concurrence_wait_error();
136 #else
137     __builtin_abort();
138 #endif
139   }
140 #endif
141  
142   class __mutex 
143   {
144   private:
145     __gthread_mutex_t _M_mutex;
146
147     __mutex(const __mutex&);
148     __mutex& operator=(const __mutex&);
149
150   public:
151     __mutex() 
152     { 
153 #if __GTHREADS
154       if (__gthread_active_p())
155         {
156 #if defined __GTHREAD_MUTEX_INIT
157           __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
158           _M_mutex = __tmp;
159 #else
160           __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 
161 #endif
162         }
163 #endif 
164     }
165
166 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
167     ~__mutex() 
168     { 
169       if (__gthread_active_p())
170         __gthread_mutex_destroy(&_M_mutex); 
171     }
172 #endif 
173
174     void lock()
175     {
176 #if __GTHREADS
177       if (__gthread_active_p())
178         {
179           if (__gthread_mutex_lock(&_M_mutex) != 0)
180             __throw_concurrence_lock_error();
181         }
182 #endif
183     }
184     
185     void unlock()
186     {
187 #if __GTHREADS
188       if (__gthread_active_p())
189         {
190           if (__gthread_mutex_unlock(&_M_mutex) != 0)
191             __throw_concurrence_unlock_error();
192         }
193 #endif
194     }
195
196     __gthread_mutex_t* gthread_mutex(void)
197       { return &_M_mutex; }
198   };
199
200   class __recursive_mutex 
201   {
202   private:
203     __gthread_recursive_mutex_t _M_mutex;
204
205     __recursive_mutex(const __recursive_mutex&);
206     __recursive_mutex& operator=(const __recursive_mutex&);
207
208   public:
209     __recursive_mutex() 
210     { 
211 #if __GTHREADS
212       if (__gthread_active_p())
213         {
214 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
215           __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
216           _M_mutex = __tmp;
217 #else
218           __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 
219 #endif
220         }
221 #endif 
222     }
223
224 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
225     ~__recursive_mutex()
226     {
227       if (__gthread_active_p())
228         _S_destroy(&_M_mutex);
229     }
230 #endif
231
232     void lock()
233     { 
234 #if __GTHREADS
235       if (__gthread_active_p())
236         {
237           if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
238             __throw_concurrence_lock_error();
239         }
240 #endif
241     }
242     
243     void unlock()
244     { 
245 #if __GTHREADS
246       if (__gthread_active_p())
247         {
248           if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
249             __throw_concurrence_unlock_error();
250         }
251 #endif
252     }
253
254     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
255     { return &_M_mutex; }
256
257 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
258     // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy
259     // so we need to obtain a __gthread_mutex_t to destroy
260   private:
261     template<typename _Mx, typename _Rm>
262       static void
263       _S_destroy_win32(_Mx* __mx, _Rm const* __rmx)
264       {
265         __mx->counter = __rmx->counter;
266         __mx->sema = __rmx->sema;
267         __gthread_mutex_destroy(__mx);
268       }
269
270     // matches a gthr-win32.h recursive mutex
271     template<typename _Rm>
272       static typename __enable_if<sizeof(&_Rm::sema), void>::__type
273       _S_destroy(_Rm* __mx)
274       {
275         __gthread_mutex_t __tmp;
276         _S_destroy_win32(&__tmp, __mx);
277       }
278
279     // matches a recursive mutex with a member 'actual'
280     template<typename _Rm>
281       static typename __enable_if<sizeof(&_Rm::actual), void>::__type
282       _S_destroy(_Rm* __mx)
283       { __gthread_mutex_destroy(&__mx->actual); }
284
285     // matches when there's only one mutex type
286     template<typename _Rm>
287       static typename
288       __enable_if<std::__are_same<_Rm, __gthread_mutex_t>::__value,
289         void>::__type
290       _S_destroy(_Rm* __mx)
291       { __gthread_mutex_destroy(__mx); }
292 #endif
293   };
294
295   /// Scoped lock idiom.
296   // Acquire the mutex here with a constructor call, then release with
297   // the destructor call in accordance with RAII style.
298   class __scoped_lock
299   {
300   public:
301     typedef __mutex __mutex_type;
302
303   private:
304     __mutex_type& _M_device;
305
306     __scoped_lock(const __scoped_lock&);
307     __scoped_lock& operator=(const __scoped_lock&);
308
309   public:
310     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
311     { _M_device.lock(); }
312
313     ~__scoped_lock() throw()
314     { _M_device.unlock(); }
315   };
316
317 #ifdef __GTHREAD_HAS_COND
318   class __cond
319   {
320   private:
321     __gthread_cond_t _M_cond;
322
323     __cond(const __cond&);
324     __cond& operator=(const __cond&);
325
326   public:
327     __cond() 
328     { 
329 #if __GTHREADS
330       if (__gthread_active_p())
331         {
332 #if defined __GTHREAD_COND_INIT
333           __gthread_cond_t __tmp = __GTHREAD_COND_INIT;
334           _M_cond = __tmp;
335 #else
336           __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
337 #endif
338         }
339 #endif 
340     }
341
342 #if __GTHREADS && ! defined __GTHREAD_COND_INIT
343     ~__cond() 
344     { 
345       if (__gthread_active_p())
346         __gthread_cond_destroy(&_M_cond); 
347     }
348 #endif 
349
350     void broadcast()
351     {
352 #if __GTHREADS
353       if (__gthread_active_p())
354         {
355           if (__gthread_cond_broadcast(&_M_cond) != 0)
356             __throw_concurrence_broadcast_error();
357         }
358 #endif
359     }
360
361     void wait(__mutex *mutex)
362     {
363 #if __GTHREADS
364       {
365           if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
366             __throw_concurrence_wait_error();
367       }
368 #endif
369     }
370
371     void wait_recursive(__recursive_mutex *mutex)
372     {
373 #if __GTHREADS
374       {
375           if (__gthread_cond_wait_recursive(&_M_cond,
376                                             mutex->gthread_recursive_mutex())
377               != 0)
378             __throw_concurrence_wait_error();
379       }
380 #endif
381     }
382   };
383 #endif
384
385 _GLIBCXX_END_NAMESPACE
386
387 #endif