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