1 // Support for concurrent programing -*- C++ -*- 2 3 // Copyright (C) 2003-2018 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file ext/concurrence.h 26 * This file is a GNU extension to the Standard C++ Library. 27 */ 28 29 #ifndef _CONCURRENCE_H 30 #define _CONCURRENCE_H 1 31 32 #pragma GCC system_header 33 34 #include <exception> 35 #include <bits/gthr.h> 36 #include <bits/functexcept.h> 37 #include <bits/cpp_type_traits.h> 38 #include <ext/type_traits.h> 39 40 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 41 { 42 _GLIBCXX_BEGIN_NAMESPACE_VERSION 43 44 // Available locking policies: 45 // _S_single single-threaded code that doesn't need to be locked. 46 // _S_mutex multi-threaded code that requires additional support 47 // from gthr.h or abstraction layers in concurrence.h. 48 // _S_atomic multi-threaded code using atomic operations. 49 enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 50 51 // Compile time constant that indicates prefered locking policy in 52 // the current configuration. 53 static const _Lock_policy __default_lock_policy = 54 #ifdef __GTHREADS 55 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ 56 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) 57 _S_atomic; 58 #else 59 _S_mutex; 60 #endif 61 #else 62 _S_single; 63 #endif 64 65 // NB: As this is used in libsupc++, need to only depend on 66 // exception. No stdexception classes, no use of std::string. 67 class __concurrence_lock_error : public std::exception 68 { 69 public: 70 virtual char const* 71 what() const throw() 72 { return "__gnu_cxx::__concurrence_lock_error"; } 73 }; 74 75 class __concurrence_unlock_error : public std::exception 76 { 77 public: 78 virtual char const* 79 what() const throw() 80 { return "__gnu_cxx::__concurrence_unlock_error"; } 81 }; 82 83 class __concurrence_broadcast_error : public std::exception 84 { 85 public: 86 virtual char const* 87 what() const throw() 88 { return "__gnu_cxx::__concurrence_broadcast_error"; } 89 }; 90 91 class __concurrence_wait_error : public std::exception 92 { 93 public: 94 virtual char const* 95 what() const throw() 96 { return "__gnu_cxx::__concurrence_wait_error"; } 97 }; 98 99 // Substitute for concurrence_error object in the case of -fno-exceptions. 100 inline void 101 __throw_concurrence_lock_error() 102 { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); } 103 104 inline void 105 __throw_concurrence_unlock_error() 106 { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); } 107 108 #ifdef __GTHREAD_HAS_COND 109 inline void 110 __throw_concurrence_broadcast_error() 111 { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); } 112 113 inline void 114 __throw_concurrence_wait_error() 115 { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); } 116 #endif 117 118 class __mutex 119 { 120 private: 121 #if __GTHREADS && defined __GTHREAD_MUTEX_INIT 122 __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT; 123 #else 124 __gthread_mutex_t _M_mutex; 125 #endif 126 127 __mutex(const __mutex&); 128 __mutex& operator=(const __mutex&); 129 130 public: 131 __mutex() 132 { 133 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 134 if (__gthread_active_p()) 135 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 136 #endif 137 } 138 139 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT 140 ~__mutex() 141 { 142 if (__gthread_active_p()) 143 __gthread_mutex_destroy(&_M_mutex); 144 } 145 #endif 146 147 void lock() 148 { 149 #if __GTHREADS 150 if (__gthread_active_p()) 151 { 152 if (__gthread_mutex_lock(&_M_mutex) != 0) 153 __throw_concurrence_lock_error(); 154 } 155 #endif 156 } 157 158 void unlock() 159 { 160 #if __GTHREADS 161 if (__gthread_active_p()) 162 { 163 if (__gthread_mutex_unlock(&_M_mutex) != 0) 164 __throw_concurrence_unlock_error(); 165 } 166 #endif 167 } 168 169 __gthread_mutex_t* gthread_mutex(void) 170 { return &_M_mutex; } 171 }; 172 173 class __recursive_mutex 174 { 175 private: 176 #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT 177 __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 178 #else 179 __gthread_recursive_mutex_t _M_mutex; 180 #endif 181 182 __recursive_mutex(const __recursive_mutex&); 183 __recursive_mutex& operator=(const __recursive_mutex&); 184 185 public: 186 __recursive_mutex() 187 { 188 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 189 if (__gthread_active_p()) 190 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 191 #endif 192 } 193 194 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT 195 ~__recursive_mutex() 196 { 197 if (__gthread_active_p()) 198 __gthread_recursive_mutex_destroy(&_M_mutex); 199 } 200 #endif 201 202 void lock() 203 { 204 #if __GTHREADS 205 if (__gthread_active_p()) 206 { 207 if (__gthread_recursive_mutex_lock(&_M_mutex) != 0) 208 __throw_concurrence_lock_error(); 209 } 210 #endif 211 } 212 213 void unlock() 214 { 215 #if __GTHREADS 216 if (__gthread_active_p()) 217 { 218 if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0) 219 __throw_concurrence_unlock_error(); 220 } 221 #endif 222 } 223 224 __gthread_recursive_mutex_t* gthread_recursive_mutex(void) 225 { return &_M_mutex; } 226 }; 227 228 /// Scoped lock idiom. 229 // Acquire the mutex here with a constructor call, then release with 230 // the destructor call in accordance with RAII style. 231 class __scoped_lock 232 { 233 public: 234 typedef __mutex __mutex_type; 235 236 private: 237 __mutex_type& _M_device; 238 239 __scoped_lock(const __scoped_lock&); 240 __scoped_lock& operator=(const __scoped_lock&); 241 242 public: 243 explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) 244 { _M_device.lock(); } 245 246 ~__scoped_lock() throw() 247 { _M_device.unlock(); } 248 }; 249 250 #ifdef __GTHREAD_HAS_COND 251 class __cond 252 { 253 private: 254 #if __GTHREADS && defined __GTHREAD_COND_INIT 255 __gthread_cond_t _M_cond = __GTHREAD_COND_INIT; 256 #else 257 __gthread_cond_t _M_cond; 258 #endif 259 260 __cond(const __cond&); 261 __cond& operator=(const __cond&); 262 263 public: 264 __cond() 265 { 266 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 267 if (__gthread_active_p()) 268 __GTHREAD_COND_INIT_FUNCTION(&_M_cond); 269 #endif 270 } 271 272 #if __GTHREADS && ! defined __GTHREAD_COND_INIT 273 ~__cond() 274 { 275 if (__gthread_active_p()) 276 __gthread_cond_destroy(&_M_cond); 277 } 278 #endif 279 280 void broadcast() 281 { 282 #if __GTHREADS 283 if (__gthread_active_p()) 284 { 285 if (__gthread_cond_broadcast(&_M_cond) != 0) 286 __throw_concurrence_broadcast_error(); 287 } 288 #endif 289 } 290 291 void wait(__mutex *mutex) 292 { 293 #if __GTHREADS 294 { 295 if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0) 296 __throw_concurrence_wait_error(); 297 } 298 #endif 299 } 300 301 void wait_recursive(__recursive_mutex *mutex) 302 { 303 #if __GTHREADS 304 { 305 if (__gthread_cond_wait_recursive(&_M_cond, 306 mutex->gthread_recursive_mutex()) 307 != 0) 308 __throw_concurrence_wait_error(); 309 } 310 #endif 311 } 312 }; 313 #endif 314 315 _GLIBCXX_END_NAMESPACE_VERSION 316 } // namespace 317 318 #endif 319