1 // Support for concurrent programing -*- C++ -*- 2 3 // Copyright (C) 2003, 2004, 2005, 2006 4 // Free Software Foundation, Inc. 5 // 6 // This file is part of the GNU ISO C++ Library. This library is free 7 // software; you can redistribute it and/or modify it under the 8 // terms of the GNU General Public License as published by the 9 // Free Software Foundation; either version 2, or (at your option) 10 // any later version. 11 12 // This library is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 // GNU General Public License for more details. 16 17 // You should have received a copy of the GNU General Public License along 18 // with this library; see the file COPYING. If not, write to the Free 19 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 20 // USA. 21 22 // As a special exception, you may use this file as part of a free software 23 // library without restriction. Specifically, if other files instantiate 24 // templates or use macros or inline functions from this file, or you compile 25 // this file and link it with other files to produce an executable, this 26 // file does not by itself cause the resulting executable to be covered by 27 // the GNU General Public License. This exception does not however 28 // invalidate any other reasons why the executable file might be covered by 29 // the GNU General Public License. 30 31 /** @file concurrence.h 32 * This is an internal header file, included by other library headers. 33 * You should not attempt to use it directly. 34 */ 35 36 #ifndef _CONCURRENCE_H 37 #define _CONCURRENCE_H 1 38 39 #include <cstdlib> 40 #include <exception> 41 #include <bits/gthr.h> 42 #include <bits/functexcept.h> 43 44 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 45 46 // Available locking policies: 47 // _S_single single-threaded code that doesn't need to be locked. 48 // _S_mutex multi-threaded code that requires additional support 49 // from gthr.h or abstraction layers in concurrance.h. 50 // _S_atomic multi-threaded code using atomic operations. 51 enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 52 53 // Compile time constant that indicates prefered locking policy in 54 // the current configuration. 55 static const _Lock_policy __default_lock_policy = 56 #ifdef __GTHREADS 57 // NB: This macro doesn't actually exist yet in the compiler, but is 58 // set somewhat haphazardly at configure time. 59 #ifdef _GLIBCXX_ATOMIC_BUILTINS 60 _S_atomic; 61 #else 62 _S_mutex; 63 #endif 64 #else 65 _S_single; 66 #endif 67 68 // NB: As this is used in libsupc++, need to only depend on 69 // exception. No stdexception classes, no use of std::string. 70 class __concurrence_lock_error : public std::exception 71 { 72 public: 73 virtual char const* what()74 what() const throw() 75 { return "__gnu_cxx::__concurrence_lock_error"; } 76 }; 77 78 class __concurrence_unlock_error : public std::exception 79 { 80 public: 81 virtual char const* what()82 what() const throw() 83 { return "__gnu_cxx::__concurrence_unlock_error"; } 84 }; 85 86 // Substitute for concurrence_error object in the case of -fno-exceptions. 87 inline void __throw_concurrence_lock_error()88 __throw_concurrence_lock_error() 89 { 90 #if __EXCEPTIONS 91 throw __concurrence_lock_error(); 92 #else 93 std::abort(); 94 #endif 95 } 96 97 inline void __throw_concurrence_unlock_error()98 __throw_concurrence_unlock_error() 99 { 100 #if __EXCEPTIONS 101 throw __concurrence_unlock_error(); 102 #else 103 std::abort(); 104 #endif 105 } 106 107 class __mutex 108 { 109 private: 110 __gthread_mutex_t _M_mutex; 111 112 __mutex(const __mutex&); 113 __mutex& operator=(const __mutex&); 114 115 public: __mutex()116 __mutex() 117 { 118 #if __GTHREADS 119 if (__gthread_active_p()) 120 { 121 #if defined __GTHREAD_MUTEX_INIT 122 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; 123 _M_mutex = __tmp; 124 #else 125 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 126 #endif 127 } 128 #endif 129 } 130 lock()131 void lock() 132 { 133 #if __GTHREADS 134 if (__gthread_active_p()) 135 { 136 if (__gthread_mutex_lock(&_M_mutex) != 0) 137 __throw_concurrence_lock_error(); 138 } 139 #endif 140 } 141 unlock()142 void unlock() 143 { 144 #if __GTHREADS 145 if (__gthread_active_p()) 146 { 147 if (__gthread_mutex_unlock(&_M_mutex) != 0) 148 __throw_concurrence_unlock_error(); 149 } 150 #endif 151 } 152 }; 153 154 class __recursive_mutex 155 { 156 private: 157 __gthread_recursive_mutex_t _M_mutex; 158 159 __recursive_mutex(const __recursive_mutex&); 160 __recursive_mutex& operator=(const __recursive_mutex&); 161 162 public: __recursive_mutex()163 __recursive_mutex() 164 { 165 #if __GTHREADS 166 if (__gthread_active_p()) 167 { 168 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT 169 __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT; 170 _M_mutex = __tmp; 171 #else 172 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 173 #endif 174 } 175 #endif 176 } 177 lock()178 void lock() 179 { 180 #if __GTHREADS 181 if (__gthread_active_p()) 182 { 183 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 184 __throw_concurrence_lock_error(); 185 } 186 #endif 187 } 188 unlock()189 void unlock() 190 { 191 #if __GTHREADS 192 if (__gthread_active_p()) 193 { 194 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 195 __throw_concurrence_unlock_error(); 196 } 197 #endif 198 } 199 }; 200 201 /// @brief Scoped lock idiom. 202 // Acquire the mutex here with a constructor call, then release with 203 // the destructor call in accordance with RAII style. 204 class __scoped_lock 205 { 206 public: 207 typedef __mutex __mutex_type; 208 209 private: 210 __mutex_type& _M_device; 211 212 __scoped_lock(const __scoped_lock&); 213 __scoped_lock& operator=(const __scoped_lock&); 214 215 public: __scoped_lock(__mutex_type & __name)216 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 217 { _M_device.lock(); } 218 throw()219 ~__scoped_lock() throw() 220 { _M_device.unlock(); } 221 }; 222 223 _GLIBCXX_END_NAMESPACE 224 225 #endif 226