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