00001 // Support for concurrent programing -*- C++ -*- 00002 00003 // Copyright (C) 2003, 2004, 2005, 2006 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 2, 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 // You should have received a copy of the GNU General Public License along 00018 // with this library; see the file COPYING. If not, write to the Free 00019 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 00020 // USA. 00021 00022 // As a special exception, you may use this file as part of a free software 00023 // library without restriction. Specifically, if other files instantiate 00024 // templates or use macros or inline functions from this file, or you compile 00025 // this file and link it with other files to produce an executable, this 00026 // file does not by itself cause the resulting executable to be covered by 00027 // the GNU General Public License. This exception does not however 00028 // invalidate any other reasons why the executable file might be covered by 00029 // the GNU General Public License. 00030 00031 /** @file concurrence.h 00032 * This is an internal header file, included by other library headers. 00033 * You should not attempt to use it directly. 00034 */ 00035 00036 #ifndef _CONCURRENCE_H 00037 #define _CONCURRENCE_H 1 00038 00039 #include <cstdlib> 00040 #include <exception> 00041 #include <bits/gthr.h> 00042 #include <bits/functexcept.h> 00043 00044 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 00045 00046 // Available locking policies: 00047 // _S_single single-threaded code that doesn't need to be locked. 00048 // _S_mutex multi-threaded code that requires additional support 00049 // from gthr.h or abstraction layers in concurrance.h. 00050 // _S_atomic multi-threaded code using atomic operations. 00051 enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 00052 00053 // Compile time constant that indicates prefered locking policy in 00054 // the current configuration. 00055 static const _Lock_policy __default_lock_policy = 00056 #ifdef __GTHREADS 00057 // NB: This macro doesn't actually exist yet in the compiler, but is 00058 // set somewhat haphazardly at configure time. 00059 #ifdef _GLIBCXX_ATOMIC_BUILTINS 00060 _S_atomic; 00061 #else 00062 _S_mutex; 00063 #endif 00064 #else 00065 _S_single; 00066 #endif 00067 00068 // NB: As this is used in libsupc++, need to only depend on 00069 // exception. No stdexception classes, no use of std::string. 00070 class __concurrence_lock_error : public std::exception 00071 { 00072 public: 00073 virtual char const* 00074 what() const throw() 00075 { return "__gnu_cxx::__concurrence_lock_error"; } 00076 }; 00077 00078 class __concurrence_unlock_error : public std::exception 00079 { 00080 public: 00081 virtual char const* 00082 what() const throw() 00083 { return "__gnu_cxx::__concurrence_unlock_error"; } 00084 }; 00085 00086 // Substitute for concurrence_error object in the case of -fno-exceptions. 00087 inline void 00088 __throw_concurrence_lock_error() 00089 { 00090 #if __EXCEPTIONS 00091 throw __concurrence_lock_error(); 00092 #else 00093 std::abort(); 00094 #endif 00095 } 00096 00097 inline void 00098 __throw_concurrence_unlock_error() 00099 { 00100 #if __EXCEPTIONS 00101 throw __concurrence_unlock_error(); 00102 #else 00103 std::abort(); 00104 #endif 00105 } 00106 00107 class __mutex 00108 { 00109 private: 00110 __gthread_mutex_t _M_mutex; 00111 00112 __mutex(const __mutex&); 00113 __mutex& operator=(const __mutex&); 00114 00115 public: 00116 __mutex() 00117 { 00118 #if __GTHREADS 00119 if (__gthread_active_p()) 00120 { 00121 #if defined __GTHREAD_MUTEX_INIT 00122 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; 00123 _M_mutex = __tmp; 00124 #else 00125 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00126 #endif 00127 } 00128 #endif 00129 } 00130 00131 void lock() 00132 { 00133 #if __GTHREADS 00134 if (__gthread_active_p()) 00135 { 00136 if (__gthread_mutex_lock(&_M_mutex) != 0) 00137 __throw_concurrence_lock_error(); 00138 } 00139 #endif 00140 } 00141 00142 void unlock() 00143 { 00144 #if __GTHREADS 00145 if (__gthread_active_p()) 00146 { 00147 if (__gthread_mutex_unlock(&_M_mutex) != 0) 00148 __throw_concurrence_unlock_error(); 00149 } 00150 #endif 00151 } 00152 }; 00153 00154 class __recursive_mutex 00155 { 00156 private: 00157 __gthread_recursive_mutex_t _M_mutex; 00158 00159 __recursive_mutex(const __recursive_mutex&); 00160 __recursive_mutex& operator=(const __recursive_mutex&); 00161 00162 public: 00163 __recursive_mutex() 00164 { 00165 #if __GTHREADS 00166 if (__gthread_active_p()) 00167 { 00168 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT 00169 __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT; 00170 _M_mutex = __tmp; 00171 #else 00172 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 00173 #endif 00174 } 00175 #endif 00176 } 00177 00178 void lock() 00179 { 00180 #if __GTHREADS 00181 if (__gthread_active_p()) 00182 { 00183 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 00184 __throw_concurrence_lock_error(); 00185 } 00186 #endif 00187 } 00188 00189 void unlock() 00190 { 00191 #if __GTHREADS 00192 if (__gthread_active_p()) 00193 { 00194 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 00195 __throw_concurrence_unlock_error(); 00196 } 00197 #endif 00198 } 00199 }; 00200 00201 /// @brief Scoped lock idiom. 00202 // Acquire the mutex here with a constructor call, then release with 00203 // the destructor call in accordance with RAII style. 00204 class __scoped_lock 00205 { 00206 public: 00207 typedef __mutex __mutex_type; 00208 00209 private: 00210 __mutex_type& _M_device; 00211 00212 __scoped_lock(const __scoped_lock&); 00213 __scoped_lock& operator=(const __scoped_lock&); 00214 00215 public: 00216 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 00217 { _M_device.lock(); } 00218 00219 ~__scoped_lock() throw() 00220 { _M_device.unlock(); } 00221 }; 00222 00223 _GLIBCXX_END_NAMESPACE 00224 00225 #endif