1 // std::mutex implementation -*- 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 bits/std_mutex.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{mutex} 28 */ 29 30 #ifndef _GLIBCXX_MUTEX_H 31 #define _GLIBCXX_MUTEX_H 1 32 33 #pragma GCC system_header 34 35 #if __cplusplus < 201103L 36 # include <bits/c++0x_warning.h> 37 #else 38 39 #include <system_error> 40 #include <bits/functexcept.h> 41 #include <bits/gthr.h> 42 #include <bits/move.h> // for std::swap 43 44 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 45 46 namespace std _GLIBCXX_VISIBILITY(default) 47 { 48 _GLIBCXX_BEGIN_NAMESPACE_VERSION 49 50 /** 51 * @defgroup mutexes Mutexes 52 * @ingroup concurrency 53 * 54 * Classes for mutex support. 55 * @{ 56 */ 57 58 #ifdef _GLIBCXX_HAS_GTHREADS 59 // Common base class for std::mutex and std::timed_mutex 60 class __mutex_base 61 { 62 protected: 63 typedef __gthread_mutex_t __native_type; 64 65 #ifdef __GTHREAD_MUTEX_INIT 66 __native_type _M_mutex = __GTHREAD_MUTEX_INIT; 67 68 constexpr __mutex_base() noexcept = default; 69 #else 70 __native_type _M_mutex; 71 72 __mutex_base() noexcept 73 { 74 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 75 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 76 } 77 78 ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); } 79 #endif 80 81 __mutex_base(const __mutex_base&) = delete; 82 __mutex_base& operator=(const __mutex_base&) = delete; 83 }; 84 85 /// The standard mutex type. 86 class mutex : private __mutex_base 87 { 88 public: 89 typedef __native_type* native_handle_type; 90 91 #ifdef __GTHREAD_MUTEX_INIT 92 constexpr 93 #endif 94 mutex() noexcept = default; 95 ~mutex() = default; 96 97 mutex(const mutex&) = delete; 98 mutex& operator=(const mutex&) = delete; 99 100 void 101 lock() 102 { 103 int __e = __gthread_mutex_lock(&_M_mutex); 104 105 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 106 if (__e) 107 __throw_system_error(__e); 108 } 109 110 bool 111 try_lock() noexcept 112 { 113 // XXX EINVAL, EAGAIN, EBUSY 114 return !__gthread_mutex_trylock(&_M_mutex); 115 } 116 117 void 118 unlock() 119 { 120 // XXX EINVAL, EAGAIN, EPERM 121 __gthread_mutex_unlock(&_M_mutex); 122 } 123 124 native_handle_type 125 native_handle() noexcept 126 { return &_M_mutex; } 127 }; 128 129 #endif // _GLIBCXX_HAS_GTHREADS 130 131 /// Do not acquire ownership of the mutex. 132 struct defer_lock_t { explicit defer_lock_t() = default; }; 133 134 /// Try to acquire ownership of the mutex without blocking. 135 struct try_to_lock_t { explicit try_to_lock_t() = default; }; 136 137 /// Assume the calling thread has already obtained mutex ownership 138 /// and manage it. 139 struct adopt_lock_t { explicit adopt_lock_t() = default; }; 140 141 /// Tag used to prevent a scoped lock from acquiring ownership of a mutex. 142 _GLIBCXX17_INLINE constexpr defer_lock_t defer_lock { }; 143 144 /// Tag used to prevent a scoped lock from blocking if a mutex is locked. 145 _GLIBCXX17_INLINE constexpr try_to_lock_t try_to_lock { }; 146 147 /// Tag used to make a scoped lock take ownership of a locked mutex. 148 _GLIBCXX17_INLINE constexpr adopt_lock_t adopt_lock { }; 149 150 /** @brief A simple scoped lock type. 151 * 152 * A lock_guard controls mutex ownership within a scope, releasing 153 * ownership in the destructor. 154 */ 155 template<typename _Mutex> 156 class lock_guard 157 { 158 public: 159 typedef _Mutex mutex_type; 160 161 explicit lock_guard(mutex_type& __m) : _M_device(__m) 162 { _M_device.lock(); } 163 164 lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m) 165 { } // calling thread owns mutex 166 167 ~lock_guard() 168 { _M_device.unlock(); } 169 170 lock_guard(const lock_guard&) = delete; 171 lock_guard& operator=(const lock_guard&) = delete; 172 173 private: 174 mutex_type& _M_device; 175 }; 176 177 /** @brief A movable scoped lock type. 178 * 179 * A unique_lock controls mutex ownership within a scope. Ownership of the 180 * mutex can be delayed until after construction and can be transferred 181 * to another unique_lock by move construction or move assignment. If a 182 * mutex lock is owned when the destructor runs ownership will be released. 183 */ 184 template<typename _Mutex> 185 class unique_lock 186 { 187 public: 188 typedef _Mutex mutex_type; 189 190 unique_lock() noexcept 191 : _M_device(0), _M_owns(false) 192 { } 193 194 explicit unique_lock(mutex_type& __m) 195 : _M_device(std::__addressof(__m)), _M_owns(false) 196 { 197 lock(); 198 _M_owns = true; 199 } 200 201 unique_lock(mutex_type& __m, defer_lock_t) noexcept 202 : _M_device(std::__addressof(__m)), _M_owns(false) 203 { } 204 205 unique_lock(mutex_type& __m, try_to_lock_t) 206 : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) 207 { } 208 209 unique_lock(mutex_type& __m, adopt_lock_t) noexcept 210 : _M_device(std::__addressof(__m)), _M_owns(true) 211 { 212 // XXX calling thread owns mutex 213 } 214 215 template<typename _Clock, typename _Duration> 216 unique_lock(mutex_type& __m, 217 const chrono::time_point<_Clock, _Duration>& __atime) 218 : _M_device(std::__addressof(__m)), 219 _M_owns(_M_device->try_lock_until(__atime)) 220 { } 221 222 template<typename _Rep, typename _Period> 223 unique_lock(mutex_type& __m, 224 const chrono::duration<_Rep, _Period>& __rtime) 225 : _M_device(std::__addressof(__m)), 226 _M_owns(_M_device->try_lock_for(__rtime)) 227 { } 228 229 ~unique_lock() 230 { 231 if (_M_owns) 232 unlock(); 233 } 234 235 unique_lock(const unique_lock&) = delete; 236 unique_lock& operator=(const unique_lock&) = delete; 237 238 unique_lock(unique_lock&& __u) noexcept 239 : _M_device(__u._M_device), _M_owns(__u._M_owns) 240 { 241 __u._M_device = 0; 242 __u._M_owns = false; 243 } 244 245 unique_lock& operator=(unique_lock&& __u) noexcept 246 { 247 if(_M_owns) 248 unlock(); 249 250 unique_lock(std::move(__u)).swap(*this); 251 252 __u._M_device = 0; 253 __u._M_owns = false; 254 255 return *this; 256 } 257 258 void 259 lock() 260 { 261 if (!_M_device) 262 __throw_system_error(int(errc::operation_not_permitted)); 263 else if (_M_owns) 264 __throw_system_error(int(errc::resource_deadlock_would_occur)); 265 else 266 { 267 _M_device->lock(); 268 _M_owns = true; 269 } 270 } 271 272 bool 273 try_lock() 274 { 275 if (!_M_device) 276 __throw_system_error(int(errc::operation_not_permitted)); 277 else if (_M_owns) 278 __throw_system_error(int(errc::resource_deadlock_would_occur)); 279 else 280 { 281 _M_owns = _M_device->try_lock(); 282 return _M_owns; 283 } 284 } 285 286 template<typename _Clock, typename _Duration> 287 bool 288 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 289 { 290 if (!_M_device) 291 __throw_system_error(int(errc::operation_not_permitted)); 292 else if (_M_owns) 293 __throw_system_error(int(errc::resource_deadlock_would_occur)); 294 else 295 { 296 _M_owns = _M_device->try_lock_until(__atime); 297 return _M_owns; 298 } 299 } 300 301 template<typename _Rep, typename _Period> 302 bool 303 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 304 { 305 if (!_M_device) 306 __throw_system_error(int(errc::operation_not_permitted)); 307 else if (_M_owns) 308 __throw_system_error(int(errc::resource_deadlock_would_occur)); 309 else 310 { 311 _M_owns = _M_device->try_lock_for(__rtime); 312 return _M_owns; 313 } 314 } 315 316 void 317 unlock() 318 { 319 if (!_M_owns) 320 __throw_system_error(int(errc::operation_not_permitted)); 321 else if (_M_device) 322 { 323 _M_device->unlock(); 324 _M_owns = false; 325 } 326 } 327 328 void 329 swap(unique_lock& __u) noexcept 330 { 331 std::swap(_M_device, __u._M_device); 332 std::swap(_M_owns, __u._M_owns); 333 } 334 335 mutex_type* 336 release() noexcept 337 { 338 mutex_type* __ret = _M_device; 339 _M_device = 0; 340 _M_owns = false; 341 return __ret; 342 } 343 344 bool 345 owns_lock() const noexcept 346 { return _M_owns; } 347 348 explicit operator bool() const noexcept 349 { return owns_lock(); } 350 351 mutex_type* 352 mutex() const noexcept 353 { return _M_device; } 354 355 private: 356 mutex_type* _M_device; 357 bool _M_owns; // XXX use atomic_bool 358 }; 359 360 /// Swap overload for unique_lock objects. 361 template<typename _Mutex> 362 inline void 363 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 364 { __x.swap(__y); } 365 366 // @} group mutexes 367 _GLIBCXX_END_NAMESPACE_VERSION 368 } // namespace 369 #endif // _GLIBCXX_USE_C99_STDINT_TR1 370 371 #endif // C++11 372 373 #endif // _GLIBCXX_MUTEX_H 374