libstdc++
|
00001 // Support for concurrent programing -*- C++ -*- 00002 00003 // Copyright (C) 2003-2019 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 #ifndef __GTHREADS 00055 _S_single; 00056 #elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY 00057 _S_atomic; 00058 #else 00059 _S_mutex; 00060 #endif 00061 00062 // NB: As this is used in libsupc++, need to only depend on 00063 // exception. No stdexception classes, no use of std::string. 00064 class __concurrence_lock_error : public std::exception 00065 { 00066 public: 00067 virtual char const* 00068 what() const throw() 00069 { return "__gnu_cxx::__concurrence_lock_error"; } 00070 }; 00071 00072 class __concurrence_unlock_error : public std::exception 00073 { 00074 public: 00075 virtual char const* 00076 what() const throw() 00077 { return "__gnu_cxx::__concurrence_unlock_error"; } 00078 }; 00079 00080 class __concurrence_broadcast_error : public std::exception 00081 { 00082 public: 00083 virtual char const* 00084 what() const throw() 00085 { return "__gnu_cxx::__concurrence_broadcast_error"; } 00086 }; 00087 00088 class __concurrence_wait_error : public std::exception 00089 { 00090 public: 00091 virtual char const* 00092 what() const throw() 00093 { return "__gnu_cxx::__concurrence_wait_error"; } 00094 }; 00095 00096 // Substitute for concurrence_error object in the case of -fno-exceptions. 00097 inline void 00098 __throw_concurrence_lock_error() 00099 { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); } 00100 00101 inline void 00102 __throw_concurrence_unlock_error() 00103 { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); } 00104 00105 #ifdef __GTHREAD_HAS_COND 00106 inline void 00107 __throw_concurrence_broadcast_error() 00108 { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); } 00109 00110 inline void 00111 __throw_concurrence_wait_error() 00112 { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); } 00113 #endif 00114 00115 class __mutex 00116 { 00117 private: 00118 #if __GTHREADS && defined __GTHREAD_MUTEX_INIT 00119 __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT; 00120 #else 00121 __gthread_mutex_t _M_mutex; 00122 #endif 00123 00124 __mutex(const __mutex&); 00125 __mutex& operator=(const __mutex&); 00126 00127 public: 00128 __mutex() 00129 { 00130 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 00131 if (__gthread_active_p()) 00132 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00133 #endif 00134 } 00135 00136 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 00137 ~__mutex() 00138 { 00139 if (__gthread_active_p()) 00140 __gthread_mutex_destroy(&_M_mutex); 00141 } 00142 #endif 00143 00144 void lock() 00145 { 00146 #if __GTHREADS 00147 if (__gthread_active_p()) 00148 { 00149 if (__gthread_mutex_lock(&_M_mutex) != 0) 00150 __throw_concurrence_lock_error(); 00151 } 00152 #endif 00153 } 00154 00155 void unlock() 00156 { 00157 #if __GTHREADS 00158 if (__gthread_active_p()) 00159 { 00160 if (__gthread_mutex_unlock(&_M_mutex) != 0) 00161 __throw_concurrence_unlock_error(); 00162 } 00163 #endif 00164 } 00165 00166 __gthread_mutex_t* gthread_mutex(void) 00167 { return &_M_mutex; } 00168 }; 00169 00170 class __recursive_mutex 00171 { 00172 private: 00173 #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT 00174 __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 00175 #else 00176 __gthread_recursive_mutex_t _M_mutex; 00177 #endif 00178 00179 __recursive_mutex(const __recursive_mutex&); 00180 __recursive_mutex& operator=(const __recursive_mutex&); 00181 00182 public: 00183 __recursive_mutex() 00184 { 00185 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00186 if (__gthread_active_p()) 00187 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00188 #endif 00189 } 00190 00191 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 00192 ~__recursive_mutex() 00193 { 00194 if (__gthread_active_p()) 00195 __gthread_recursive_mutex_destroy(&_M_mutex); 00196 } 00197 #endif 00198 00199 void lock() 00200 { 00201 #if __GTHREADS 00202 if (__gthread_active_p()) 00203 { 00204 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 00205 __throw_concurrence_lock_error(); 00206 } 00207 #endif 00208 } 00209 00210 void unlock() 00211 { 00212 #if __GTHREADS 00213 if (__gthread_active_p()) 00214 { 00215 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 00216 __throw_concurrence_unlock_error(); 00217 } 00218 #endif 00219 } 00220 00221 __gthread_recursive_mutex_t* gthread_recursive_mutex(void) 00222 { return &_M_mutex; } 00223 }; 00224 00225 /// Scoped lock idiom. 00226 // Acquire the mutex here with a constructor call, then release with 00227 // the destructor call in accordance with RAII style. 00228 class __scoped_lock 00229 { 00230 public: 00231 typedef __mutex __mutex_type; 00232 00233 private: 00234 __mutex_type& _M_device; 00235 00236 __scoped_lock(const __scoped_lock&); 00237 __scoped_lock& operator=(const __scoped_lock&); 00238 00239 public: 00240 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 00241 { _M_device.lock(); } 00242 00243 ~__scoped_lock() throw() 00244 { _M_device.unlock(); } 00245 }; 00246 00247 #ifdef __GTHREAD_HAS_COND 00248 class __cond 00249 { 00250 private: 00251 #if __GTHREADS && defined __GTHREAD_COND_INIT 00252 __gthread_cond_t _M_cond = __GTHREAD_COND_INIT; 00253 #else 00254 __gthread_cond_t _M_cond; 00255 #endif 00256 00257 __cond(const __cond&); 00258 __cond& operator=(const __cond&); 00259 00260 public: 00261 __cond() 00262 { 00263 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 00264 if (__gthread_active_p()) 00265 __GTHREAD_COND_INIT_FUNCTION(&_M_cond); 00266 #endif 00267 } 00268 00269 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 00270 ~__cond() 00271 { 00272 if (__gthread_active_p()) 00273 __gthread_cond_destroy(&_M_cond); 00274 } 00275 #endif 00276 00277 void broadcast() 00278 { 00279 #if __GTHREADS 00280 if (__gthread_active_p()) 00281 { 00282 if (__gthread_cond_broadcast(&_M_cond) != 0) 00283 __throw_concurrence_broadcast_error(); 00284 } 00285 #endif 00286 } 00287 00288 void wait(__mutex *mutex) 00289 { 00290 #if __GTHREADS 00291 { 00292 if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) 00293 __throw_concurrence_wait_error(); 00294 } 00295 #endif 00296 } 00297 00298 void wait_recursive(__recursive_mutex *mutex) 00299 { 00300 #if __GTHREADS 00301 { 00302 if (__gthread_cond_wait_recursive(&_M_cond, 00303 mutex->gthread_recursive_mutex()) 00304 != 0) 00305 __throw_concurrence_wait_error(); 00306 } 00307 #endif 00308 } 00309 }; 00310 #endif 00311 00312 _GLIBCXX_END_NAMESPACE_VERSION 00313 } // namespace 00314 00315 #endif