libstdc++
|
00001 // Support for concurrent programing -*- C++ -*- 00002 00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 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 concurrence.h 00027 * This is an internal header file, included by other library headers. 00028 * You should not attempt to use it directly. 00029 */ 00030 00031 #ifndef _CONCURRENCE_H 00032 #define _CONCURRENCE_H 1 00033 00034 #include <exception> 00035 #include <bits/gthr.h> 00036 #include <bits/functexcept.h> 00037 00038 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 00039 00040 // Available locking policies: 00041 // _S_single single-threaded code that doesn't need to be locked. 00042 // _S_mutex multi-threaded code that requires additional support 00043 // from gthr.h or abstraction layers in concurrence.h. 00044 // _S_atomic multi-threaded code using atomic operations. 00045 enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 00046 00047 // Compile time constant that indicates prefered locking policy in 00048 // the current configuration. 00049 static const _Lock_policy __default_lock_policy = 00050 #ifdef __GTHREADS 00051 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ 00052 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) 00053 _S_atomic; 00054 #else 00055 _S_mutex; 00056 #endif 00057 #else 00058 _S_single; 00059 #endif 00060 00061 // NB: As this is used in libsupc++, need to only depend on 00062 // exception. No stdexception classes, no use of std::string. 00063 class __concurrence_lock_error : public std::exception 00064 { 00065 public: 00066 virtual char const* 00067 what() const throw() 00068 { return "__gnu_cxx::__concurrence_lock_error"; } 00069 }; 00070 00071 class __concurrence_unlock_error : public std::exception 00072 { 00073 public: 00074 virtual char const* 00075 what() const throw() 00076 { return "__gnu_cxx::__concurrence_unlock_error"; } 00077 }; 00078 00079 class __concurrence_broadcast_error : public std::exception 00080 { 00081 public: 00082 virtual char const* 00083 what() const throw() 00084 { return "__gnu_cxx::__concurrence_broadcast_error"; } 00085 }; 00086 00087 class __concurrence_wait_error : public std::exception 00088 { 00089 public: 00090 virtual char const* 00091 what() const throw() 00092 { return "__gnu_cxx::__concurrence_wait_error"; } 00093 }; 00094 00095 // Substitute for concurrence_error object in the case of -fno-exceptions. 00096 inline void 00097 __throw_concurrence_lock_error() 00098 { 00099 #if __EXCEPTIONS 00100 throw __concurrence_lock_error(); 00101 #else 00102 __builtin_abort(); 00103 #endif 00104 } 00105 00106 inline void 00107 __throw_concurrence_unlock_error() 00108 { 00109 #if __EXCEPTIONS 00110 throw __concurrence_unlock_error(); 00111 #else 00112 __builtin_abort(); 00113 #endif 00114 } 00115 00116 #ifdef __GTHREAD_HAS_COND 00117 inline void 00118 __throw_concurrence_broadcast_error() 00119 { 00120 #if __EXCEPTIONS 00121 throw __concurrence_broadcast_error(); 00122 #else 00123 __builtin_abort(); 00124 #endif 00125 } 00126 00127 inline void 00128 __throw_concurrence_wait_error() 00129 { 00130 #if __EXCEPTIONS 00131 throw __concurrence_wait_error(); 00132 #else 00133 __builtin_abort(); 00134 #endif 00135 } 00136 #endif 00137 00138 class __mutex 00139 { 00140 private: 00141 __gthread_mutex_t _M_mutex; 00142 00143 __mutex(const __mutex&); 00144 __mutex& operator=(const __mutex&); 00145 00146 public: 00147 __mutex() 00148 { 00149 #if __GTHREADS 00150 if (__gthread_active_p()) 00151 { 00152 #if defined __GTHREAD_MUTEX_INIT 00153 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; 00154 _M_mutex = __tmp; 00155 #else 00156 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00157 #endif 00158 } 00159 #endif 00160 } 00161 00162 void lock() 00163 { 00164 #if __GTHREADS 00165 if (__gthread_active_p()) 00166 { 00167 if (__gthread_mutex_lock(&_M_mutex) != 0) 00168 __throw_concurrence_lock_error(); 00169 } 00170 #endif 00171 } 00172 00173 void unlock() 00174 { 00175 #if __GTHREADS 00176 if (__gthread_active_p()) 00177 { 00178 if (__gthread_mutex_unlock(&_M_mutex) != 0) 00179 __throw_concurrence_unlock_error(); 00180 } 00181 #endif 00182 } 00183 00184 __gthread_mutex_t* gthread_mutex(void) 00185 { return &_M_mutex; } 00186 }; 00187 00188 class __recursive_mutex 00189 { 00190 private: 00191 __gthread_recursive_mutex_t _M_mutex; 00192 00193 __recursive_mutex(const __recursive_mutex&); 00194 __recursive_mutex& operator=(const __recursive_mutex&); 00195 00196 public: 00197 __recursive_mutex() 00198 { 00199 #if __GTHREADS 00200 if (__gthread_active_p()) 00201 { 00202 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT 00203 __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT; 00204 _M_mutex = __tmp; 00205 #else 00206 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00207 #endif 00208 } 00209 #endif 00210 } 00211 00212 void lock() 00213 { 00214 #if __GTHREADS 00215 if (__gthread_active_p()) 00216 { 00217 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 00218 __throw_concurrence_lock_error(); 00219 } 00220 #endif 00221 } 00222 00223 void unlock() 00224 { 00225 #if __GTHREADS 00226 if (__gthread_active_p()) 00227 { 00228 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 00229 __throw_concurrence_unlock_error(); 00230 } 00231 #endif 00232 } 00233 00234 __gthread_recursive_mutex_t* gthread_recursive_mutex(void) 00235 { return &_M_mutex; } 00236 }; 00237 00238 /// Scoped lock idiom. 00239 // Acquire the mutex here with a constructor call, then release with 00240 // the destructor call in accordance with RAII style. 00241 class __scoped_lock 00242 { 00243 public: 00244 typedef __mutex __mutex_type; 00245 00246 private: 00247 __mutex_type& _M_device; 00248 00249 __scoped_lock(const __scoped_lock&); 00250 __scoped_lock& operator=(const __scoped_lock&); 00251 00252 public: 00253 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 00254 { _M_device.lock(); } 00255 00256 ~__scoped_lock() throw() 00257 { _M_device.unlock(); } 00258 }; 00259 00260 #ifdef __GTHREAD_HAS_COND 00261 class __cond 00262 { 00263 private: 00264 __gthread_cond_t _M_cond; 00265 00266 __cond(const __cond&); 00267 __cond& operator=(const __cond&); 00268 00269 public: 00270 __cond() 00271 { 00272 #if __GTHREADS 00273 if (__gthread_active_p()) 00274 { 00275 #if defined __GTHREAD_COND_INIT 00276 __gthread_cond_t __tmp = __GTHREAD_COND_INIT; 00277 _M_cond = __tmp; 00278 #else 00279 __GTHREAD_COND_INIT_FUNCTION(&_M_cond); 00280 #endif 00281 } 00282 #endif 00283 } 00284 00285 void broadcast() 00286 { 00287 #if __GTHREADS 00288 if (__gthread_active_p()) 00289 { 00290 if (__gthread_cond_broadcast(&_M_cond) != 0) 00291 __throw_concurrence_broadcast_error(); 00292 } 00293 #endif 00294 } 00295 00296 void wait(__mutex *mutex) 00297 { 00298 #if __GTHREADS 00299 { 00300 if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) 00301 __throw_concurrence_wait_error(); 00302 } 00303 #endif 00304 } 00305 00306 void wait_recursive(__recursive_mutex *mutex) 00307 { 00308 #if __GTHREADS 00309 { 00310 if (__gthread_cond_wait_recursive(&_M_cond, 00311 mutex->gthread_recursive_mutex()) 00312 != 0) 00313 __throw_concurrence_wait_error(); 00314 } 00315 #endif 00316 } 00317 }; 00318 #endif 00319 00320 _GLIBCXX_END_NAMESPACE 00321 00322 #endif