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 class __mutex 00144 { 00145 private: 00146 #if __GTHREADS && defined __GTHREAD_MUTEX_INIT 00147 __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT; 00148 #else 00149 __gthread_mutex_t _M_mutex; 00150 #endif 00151 00152 __mutex(const __mutex&); 00153 __mutex& operator=(const __mutex&); 00154 00155 public: 00156 __mutex() 00157 { 00158 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 00159 if (__gthread_active_p()) 00160 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00161 #endif 00162 } 00163 00164 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 00165 ~__mutex() 00166 { 00167 if (__gthread_active_p()) 00168 __gthread_mutex_destroy(&_M_mutex); 00169 } 00170 #endif 00171 00172 void lock() 00173 { 00174 #if __GTHREADS 00175 if (__gthread_active_p()) 00176 { 00177 if (__gthread_mutex_lock(&_M_mutex) != 0) 00178 __throw_concurrence_lock_error(); 00179 } 00180 #endif 00181 } 00182 00183 void unlock() 00184 { 00185 #if __GTHREADS 00186 if (__gthread_active_p()) 00187 { 00188 if (__gthread_mutex_unlock(&_M_mutex) != 0) 00189 __throw_concurrence_unlock_error(); 00190 } 00191 #endif 00192 } 00193 00194 __gthread_mutex_t* gthread_mutex(void) 00195 { return &_M_mutex; } 00196 }; 00197 00198 class __recursive_mutex 00199 { 00200 private: 00201 #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT 00202 __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 00203 #else 00204 __gthread_recursive_mutex_t _M_mutex; 00205 #endif 00206 00207 __recursive_mutex(const __recursive_mutex&); 00208 __recursive_mutex& operator=(const __recursive_mutex&); 00209 00210 public: 00211 __recursive_mutex() 00212 { 00213 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00214 if (__gthread_active_p()) 00215 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00216 #endif 00217 } 00218 00219 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00220 ~__recursive_mutex() 00221 { 00222 if (__gthread_active_p()) 00223 _S_destroy(&_M_mutex); 00224 } 00225 #endif 00226 00227 void lock() 00228 { 00229 #if __GTHREADS 00230 if (__gthread_active_p()) 00231 { 00232 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 00233 __throw_concurrence_lock_error(); 00234 } 00235 #endif 00236 } 00237 00238 void unlock() 00239 { 00240 #if __GTHREADS 00241 if (__gthread_active_p()) 00242 { 00243 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 00244 __throw_concurrence_unlock_error(); 00245 } 00246 #endif 00247 } 00248 00249 __gthread_recursive_mutex_t* gthread_recursive_mutex(void) 00250 { return &_M_mutex; } 00251 00252 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00253 // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy 00254 // so we need to obtain a __gthread_mutex_t to destroy 00255 private: 00256 template<typename _Mx, typename _Rm> 00257 static void 00258 _S_destroy_win32(_Mx* __mx, _Rm const* __rmx) 00259 { 00260 __mx->counter = __rmx->counter; 00261 __mx->sema = __rmx->sema; 00262 __gthread_mutex_destroy(__mx); 00263 } 00264 00265 // matches a gthr-win32.h recursive mutex 00266 template<typename _Rm> 00267 static typename __enable_if<(bool)sizeof(&_Rm::sema), void>::__type 00268 _S_destroy(_Rm* __mx) 00269 { 00270 __gthread_mutex_t __tmp; 00271 _S_destroy_win32(&__tmp, __mx); 00272 } 00273 00274 // matches a recursive mutex with a member 'actual' 00275 template<typename _Rm> 00276 static typename __enable_if<(bool)sizeof(&_Rm::actual), void>::__type 00277 _S_destroy(_Rm* __mx) 00278 { __gthread_mutex_destroy(&__mx->actual); } 00279 00280 // matches when there's only one mutex type 00281 template<typename _Rm> 00282 static typename 00283 __enable_if<std::__are_same<_Rm, __gthread_mutex_t>::__value, 00284 void>::__type 00285 _S_destroy(_Rm* __mx) 00286 { __gthread_mutex_destroy(__mx); } 00287 #endif 00288 }; 00289 00290 /// Scoped lock idiom. 00291 // Acquire the mutex here with a constructor call, then release with 00292 // the destructor call in accordance with RAII style. 00293 class __scoped_lock 00294 { 00295 public: 00296 typedef __mutex __mutex_type; 00297 00298 private: 00299 __mutex_type& _M_device; 00300 00301 __scoped_lock(const __scoped_lock&); 00302 __scoped_lock& operator=(const __scoped_lock&); 00303 00304 public: 00305 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 00306 { _M_device.lock(); } 00307 00308 ~__scoped_lock() throw() 00309 { _M_device.unlock(); } 00310 }; 00311 00312 #ifdef __GTHREAD_HAS_COND 00313 class __cond 00314 { 00315 private: 00316 #if __GTHREADS && defined __GTHREAD_COND_INIT 00317 __gthread_cond_t _M_cond = __GTHREAD_COND_INIT; 00318 #else 00319 __gthread_cond_t _M_cond; 00320 #endif 00321 00322 __cond(const __cond&); 00323 __cond& operator=(const __cond&); 00324 00325 public: 00326 __cond() 00327 { 00328 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 00329 if (__gthread_active_p()) 00330 __GTHREAD_COND_INIT_FUNCTION(&_M_cond); 00331 #endif 00332 } 00333 00334 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 00335 ~__cond() 00336 { 00337 if (__gthread_active_p()) 00338 __gthread_cond_destroy(&_M_cond); 00339 } 00340 #endif 00341 00342 void broadcast() 00343 { 00344 #if __GTHREADS 00345 if (__gthread_active_p()) 00346 { 00347 if (__gthread_cond_broadcast(&_M_cond) != 0) 00348 __throw_concurrence_broadcast_error(); 00349 } 00350 #endif 00351 } 00352 00353 void wait(__mutex *mutex) 00354 { 00355 #if __GTHREADS 00356 { 00357 if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) 00358 __throw_concurrence_wait_error(); 00359 } 00360 #endif 00361 } 00362 00363 void wait_recursive(__recursive_mutex *mutex) 00364 { 00365 #if __GTHREADS 00366 { 00367 if (__gthread_cond_wait_recursive(&_M_cond, 00368 mutex->gthread_recursive_mutex()) 00369 != 0) 00370 __throw_concurrence_wait_error(); 00371 } 00372 #endif 00373 } 00374 }; 00375 #endif 00376 00377 _GLIBCXX_END_NAMESPACE_VERSION 00378 } // namespace 00379 00380 #endif