libstdc++
|
00001 // Support for concurrent programing -*- C++ -*- 00002 00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 00004 // Free Software Foundation, Inc. 00005 // 00006 // This file is part of the GNU ISO C++ Library. This library is free 00007 // software; you can redistribute it and/or modify it under the 00008 // terms of the GNU General Public License as published by the 00009 // Free Software Foundation; either version 3, or (at your option) 00010 // any later version. 00011 00012 // This library is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 00017 // Under Section 7 of GPL version 3, you are granted additional 00018 // permissions described in the GCC Runtime Library Exception, version 00019 // 3.1, as published by the Free Software Foundation. 00020 00021 // You should have received a copy of the GNU General Public License and 00022 // a copy of the GCC Runtime Library Exception along with this program; 00023 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00024 // <http://www.gnu.org/licenses/>. 00025 00026 /** @file ext/concurrence.h 00027 * This file is a GNU extension to the Standard C++ Library. 00028 */ 00029 00030 #ifndef _CONCURRENCE_H 00031 #define _CONCURRENCE_H 1 00032 00033 #pragma GCC system_header 00034 00035 #include <exception> 00036 #include <bits/gthr.h> 00037 #include <bits/functexcept.h> 00038 #include <bits/cpp_type_traits.h> 00039 #include <ext/type_traits.h> 00040 00041 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 00042 { 00043 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00044 00045 // Available locking policies: 00046 // _S_single single-threaded code that doesn't need to be locked. 00047 // _S_mutex multi-threaded code that requires additional support 00048 // from gthr.h or abstraction layers in concurrence.h. 00049 // _S_atomic multi-threaded code using atomic operations. 00050 enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 00051 00052 // Compile time constant that indicates prefered locking policy in 00053 // the current configuration. 00054 static const _Lock_policy __default_lock_policy = 00055 #ifdef __GTHREADS 00056 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ 00057 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) 00058 _S_atomic; 00059 #else 00060 _S_mutex; 00061 #endif 00062 #else 00063 _S_single; 00064 #endif 00065 00066 // NB: As this is used in libsupc++, need to only depend on 00067 // exception. No stdexception classes, no use of std::string. 00068 class __concurrence_lock_error : public std::exception 00069 { 00070 public: 00071 virtual char const* 00072 what() const throw() 00073 { return "__gnu_cxx::__concurrence_lock_error"; } 00074 }; 00075 00076 class __concurrence_unlock_error : public std::exception 00077 { 00078 public: 00079 virtual char const* 00080 what() const throw() 00081 { return "__gnu_cxx::__concurrence_unlock_error"; } 00082 }; 00083 00084 class __concurrence_broadcast_error : public std::exception 00085 { 00086 public: 00087 virtual char const* 00088 what() const throw() 00089 { return "__gnu_cxx::__concurrence_broadcast_error"; } 00090 }; 00091 00092 class __concurrence_wait_error : public std::exception 00093 { 00094 public: 00095 virtual char const* 00096 what() const throw() 00097 { return "__gnu_cxx::__concurrence_wait_error"; } 00098 }; 00099 00100 // Substitute for concurrence_error object in the case of -fno-exceptions. 00101 inline void 00102 __throw_concurrence_lock_error() 00103 { 00104 #if __EXCEPTIONS 00105 throw __concurrence_lock_error(); 00106 #else 00107 __builtin_abort(); 00108 #endif 00109 } 00110 00111 inline void 00112 __throw_concurrence_unlock_error() 00113 { 00114 #if __EXCEPTIONS 00115 throw __concurrence_unlock_error(); 00116 #else 00117 __builtin_abort(); 00118 #endif 00119 } 00120 00121 #ifdef __GTHREAD_HAS_COND 00122 inline void 00123 __throw_concurrence_broadcast_error() 00124 { 00125 #if __EXCEPTIONS 00126 throw __concurrence_broadcast_error(); 00127 #else 00128 __builtin_abort(); 00129 #endif 00130 } 00131 00132 inline void 00133 __throw_concurrence_wait_error() 00134 { 00135 #if __EXCEPTIONS 00136 throw __concurrence_wait_error(); 00137 #else 00138 __builtin_abort(); 00139 #endif 00140 } 00141 #endif 00142 00143 template<typename _Tp> 00144 static inline void 00145 __copy_gthr_type(_Tp& __to, const _Tp& __from) 00146 { 00147 #if defined __GXX_EXPERIMENTAL_CXX0X__ \ 00148 && defined _GLIBCXX_GTHREADS_NO_COPY_ASSIGN_IN_CXX11 00149 __builtin_memcpy(&__to, &__from, sizeof(__to)); 00150 #else 00151 __to = __from; 00152 #endif 00153 } 00154 00155 class __mutex 00156 { 00157 private: 00158 __gthread_mutex_t _M_mutex; 00159 00160 __mutex(const __mutex&); 00161 __mutex& operator=(const __mutex&); 00162 00163 public: 00164 __mutex() 00165 { 00166 #if __GTHREADS 00167 if (__gthread_active_p()) 00168 { 00169 #if defined __GTHREAD_MUTEX_INIT 00170 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; 00171 __copy_gthr_type(_M_mutex, __tmp); 00172 #else 00173 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00174 #endif 00175 } 00176 #endif 00177 } 00178 00179 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 00180 ~__mutex() 00181 { 00182 if (__gthread_active_p()) 00183 __gthread_mutex_destroy(&_M_mutex); 00184 } 00185 #endif 00186 00187 void lock() 00188 { 00189 #if __GTHREADS 00190 if (__gthread_active_p()) 00191 { 00192 if (__gthread_mutex_lock(&_M_mutex) != 0) 00193 __throw_concurrence_lock_error(); 00194 } 00195 #endif 00196 } 00197 00198 void unlock() 00199 { 00200 #if __GTHREADS 00201 if (__gthread_active_p()) 00202 { 00203 if (__gthread_mutex_unlock(&_M_mutex) != 0) 00204 __throw_concurrence_unlock_error(); 00205 } 00206 #endif 00207 } 00208 00209 __gthread_mutex_t* gthread_mutex(void) 00210 { return &_M_mutex; } 00211 }; 00212 00213 class __recursive_mutex 00214 { 00215 private: 00216 __gthread_recursive_mutex_t _M_mutex; 00217 00218 __recursive_mutex(const __recursive_mutex&); 00219 __recursive_mutex& operator=(const __recursive_mutex&); 00220 00221 public: 00222 __recursive_mutex() 00223 { 00224 #if __GTHREADS 00225 if (__gthread_active_p()) 00226 { 00227 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT 00228 __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT; 00229 __copy_gthr_type(_M_mutex, __tmp); 00230 #else 00231 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00232 #endif 00233 } 00234 #endif 00235 } 00236 00237 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00238 ~__recursive_mutex() 00239 { 00240 if (__gthread_active_p()) 00241 _S_destroy(&_M_mutex); 00242 } 00243 #endif 00244 00245 void lock() 00246 { 00247 #if __GTHREADS 00248 if (__gthread_active_p()) 00249 { 00250 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 00251 __throw_concurrence_lock_error(); 00252 } 00253 #endif 00254 } 00255 00256 void unlock() 00257 { 00258 #if __GTHREADS 00259 if (__gthread_active_p()) 00260 { 00261 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 00262 __throw_concurrence_unlock_error(); 00263 } 00264 #endif 00265 } 00266 00267 __gthread_recursive_mutex_t* gthread_recursive_mutex(void) 00268 { return &_M_mutex; } 00269 00270 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00271 // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy 00272 // so we need to obtain a __gthread_mutex_t to destroy 00273 private: 00274 template<typename _Mx, typename _Rm> 00275 static void 00276 _S_destroy_win32(_Mx* __mx, _Rm const* __rmx) 00277 { 00278 __mx->counter = __rmx->counter; 00279 __mx->sema = __rmx->sema; 00280 __gthread_mutex_destroy(__mx); 00281 } 00282 00283 // matches a gthr-win32.h recursive mutex 00284 template<typename _Rm> 00285 static typename __enable_if<(bool)sizeof(&_Rm::sema), void>::__type 00286 _S_destroy(_Rm* __mx) 00287 { 00288 __gthread_mutex_t __tmp; 00289 _S_destroy_win32(&__tmp, __mx); 00290 } 00291 00292 // matches a recursive mutex with a member 'actual' 00293 template<typename _Rm> 00294 static typename __enable_if<(bool)sizeof(&_Rm::actual), void>::__type 00295 _S_destroy(_Rm* __mx) 00296 { __gthread_mutex_destroy(&__mx->actual); } 00297 00298 // matches when there's only one mutex type 00299 template<typename _Rm> 00300 static typename 00301 __enable_if<std::__are_same<_Rm, __gthread_mutex_t>::__value, 00302 void>::__type 00303 _S_destroy(_Rm* __mx) 00304 { __gthread_mutex_destroy(__mx); } 00305 #endif 00306 }; 00307 00308 /// Scoped lock idiom. 00309 // Acquire the mutex here with a constructor call, then release with 00310 // the destructor call in accordance with RAII style. 00311 class __scoped_lock 00312 { 00313 public: 00314 typedef __mutex __mutex_type; 00315 00316 private: 00317 __mutex_type& _M_device; 00318 00319 __scoped_lock(const __scoped_lock&); 00320 __scoped_lock& operator=(const __scoped_lock&); 00321 00322 public: 00323 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 00324 { _M_device.lock(); } 00325 00326 ~__scoped_lock() throw() 00327 { _M_device.unlock(); } 00328 }; 00329 00330 #ifdef __GTHREAD_HAS_COND 00331 class __cond 00332 { 00333 private: 00334 __gthread_cond_t _M_cond; 00335 00336 __cond(const __cond&); 00337 __cond& operator=(const __cond&); 00338 00339 public: 00340 __cond() 00341 { 00342 #if __GTHREADS 00343 if (__gthread_active_p()) 00344 { 00345 #if defined __GTHREAD_COND_INIT 00346 __gthread_cond_t __tmp = __GTHREAD_COND_INIT; 00347 __copy_gthr_type(_M_cond, __tmp); 00348 #else 00349 __GTHREAD_COND_INIT_FUNCTION(&_M_cond); 00350 #endif 00351 } 00352 #endif 00353 } 00354 00355 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 00356 ~__cond() 00357 { 00358 if (__gthread_active_p()) 00359 __gthread_cond_destroy(&_M_cond); 00360 } 00361 #endif 00362 00363 void broadcast() 00364 { 00365 #if __GTHREADS 00366 if (__gthread_active_p()) 00367 { 00368 if (__gthread_cond_broadcast(&_M_cond) != 0) 00369 __throw_concurrence_broadcast_error(); 00370 } 00371 #endif 00372 } 00373 00374 void wait(__mutex *mutex) 00375 { 00376 #if __GTHREADS 00377 { 00378 if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) 00379 __throw_concurrence_wait_error(); 00380 } 00381 #endif 00382 } 00383 00384 void wait_recursive(__recursive_mutex *mutex) 00385 { 00386 #if __GTHREADS 00387 { 00388 if (__gthread_cond_wait_recursive(&_M_cond, 00389 mutex->gthread_recursive_mutex()) 00390 != 0) 00391 __throw_concurrence_wait_error(); 00392 } 00393 #endif 00394 } 00395 }; 00396 #endif 00397 00398 _GLIBCXX_END_NAMESPACE_VERSION 00399 } // namespace 00400 00401 #endif