libstdc++
|
00001 // std::mutex implementation -*- C++ -*- 00002 00003 // Copyright (C) 2003-2018 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 3, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** @file bits/std_mutex.h 00026 * This is an internal header file, included by other library headers. 00027 * Do not attempt to use it directly. @headername{mutex} 00028 */ 00029 00030 #ifndef _GLIBCXX_MUTEX_H 00031 #define _GLIBCXX_MUTEX_H 1 00032 00033 #pragma GCC system_header 00034 00035 #if __cplusplus < 201103L 00036 # include <bits/c++0x_warning.h> 00037 #else 00038 00039 #include <system_error> 00040 #include <bits/functexcept.h> 00041 #include <bits/gthr.h> 00042 #include <bits/move.h> // for std::swap 00043 00044 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 00045 00046 namespace std _GLIBCXX_VISIBILITY(default) 00047 { 00048 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00049 00050 /** 00051 * @defgroup mutexes Mutexes 00052 * @ingroup concurrency 00053 * 00054 * Classes for mutex support. 00055 * @{ 00056 */ 00057 00058 #ifdef _GLIBCXX_HAS_GTHREADS 00059 // Common base class for std::mutex and std::timed_mutex 00060 class __mutex_base 00061 { 00062 protected: 00063 typedef __gthread_mutex_t __native_type; 00064 00065 #ifdef __GTHREAD_MUTEX_INIT 00066 __native_type _M_mutex = __GTHREAD_MUTEX_INIT; 00067 00068 constexpr __mutex_base() noexcept = default; 00069 #else 00070 __native_type _M_mutex; 00071 00072 __mutex_base() noexcept 00073 { 00074 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 00075 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 00076 } 00077 00078 ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); } 00079 #endif 00080 00081 __mutex_base(const __mutex_base&) = delete; 00082 __mutex_base& operator=(const __mutex_base&) = delete; 00083 }; 00084 00085 /// The standard mutex type. 00086 class mutex : private __mutex_base 00087 { 00088 public: 00089 typedef __native_type* native_handle_type; 00090 00091 #ifdef __GTHREAD_MUTEX_INIT 00092 constexpr 00093 #endif 00094 mutex() noexcept = default; 00095 ~mutex() = default; 00096 00097 mutex(const mutex&) = delete; 00098 mutex& operator=(const mutex&) = delete; 00099 00100 void 00101 lock() 00102 { 00103 int __e = __gthread_mutex_lock(&_M_mutex); 00104 00105 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 00106 if (__e) 00107 __throw_system_error(__e); 00108 } 00109 00110 bool 00111 try_lock() noexcept 00112 { 00113 // XXX EINVAL, EAGAIN, EBUSY 00114 return !__gthread_mutex_trylock(&_M_mutex); 00115 } 00116 00117 void 00118 unlock() 00119 { 00120 // XXX EINVAL, EAGAIN, EPERM 00121 __gthread_mutex_unlock(&_M_mutex); 00122 } 00123 00124 native_handle_type 00125 native_handle() noexcept 00126 { return &_M_mutex; } 00127 }; 00128 00129 #endif // _GLIBCXX_HAS_GTHREADS 00130 00131 /// Do not acquire ownership of the mutex. 00132 struct defer_lock_t { explicit defer_lock_t() = default; }; 00133 00134 /// Try to acquire ownership of the mutex without blocking. 00135 struct try_to_lock_t { explicit try_to_lock_t() = default; }; 00136 00137 /// Assume the calling thread has already obtained mutex ownership 00138 /// and manage it. 00139 struct adopt_lock_t { explicit adopt_lock_t() = default; }; 00140 00141 /// Tag used to prevent a scoped lock from acquiring ownership of a mutex. 00142 _GLIBCXX17_INLINE constexpr defer_lock_t defer_lock { }; 00143 00144 /// Tag used to prevent a scoped lock from blocking if a mutex is locked. 00145 _GLIBCXX17_INLINE constexpr try_to_lock_t try_to_lock { }; 00146 00147 /// Tag used to make a scoped lock take ownership of a locked mutex. 00148 _GLIBCXX17_INLINE constexpr adopt_lock_t adopt_lock { }; 00149 00150 /** @brief A simple scoped lock type. 00151 * 00152 * A lock_guard controls mutex ownership within a scope, releasing 00153 * ownership in the destructor. 00154 */ 00155 template<typename _Mutex> 00156 class lock_guard 00157 { 00158 public: 00159 typedef _Mutex mutex_type; 00160 00161 explicit lock_guard(mutex_type& __m) : _M_device(__m) 00162 { _M_device.lock(); } 00163 00164 lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m) 00165 { } // calling thread owns mutex 00166 00167 ~lock_guard() 00168 { _M_device.unlock(); } 00169 00170 lock_guard(const lock_guard&) = delete; 00171 lock_guard& operator=(const lock_guard&) = delete; 00172 00173 private: 00174 mutex_type& _M_device; 00175 }; 00176 00177 /** @brief A movable scoped lock type. 00178 * 00179 * A unique_lock controls mutex ownership within a scope. Ownership of the 00180 * mutex can be delayed until after construction and can be transferred 00181 * to another unique_lock by move construction or move assignment. If a 00182 * mutex lock is owned when the destructor runs ownership will be released. 00183 */ 00184 template<typename _Mutex> 00185 class unique_lock 00186 { 00187 public: 00188 typedef _Mutex mutex_type; 00189 00190 unique_lock() noexcept 00191 : _M_device(0), _M_owns(false) 00192 { } 00193 00194 explicit unique_lock(mutex_type& __m) 00195 : _M_device(std::__addressof(__m)), _M_owns(false) 00196 { 00197 lock(); 00198 _M_owns = true; 00199 } 00200 00201 unique_lock(mutex_type& __m, defer_lock_t) noexcept 00202 : _M_device(std::__addressof(__m)), _M_owns(false) 00203 { } 00204 00205 unique_lock(mutex_type& __m, try_to_lock_t) 00206 : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) 00207 { } 00208 00209 unique_lock(mutex_type& __m, adopt_lock_t) noexcept 00210 : _M_device(std::__addressof(__m)), _M_owns(true) 00211 { 00212 // XXX calling thread owns mutex 00213 } 00214 00215 template<typename _Clock, typename _Duration> 00216 unique_lock(mutex_type& __m, 00217 const chrono::time_point<_Clock, _Duration>& __atime) 00218 : _M_device(std::__addressof(__m)), 00219 _M_owns(_M_device->try_lock_until(__atime)) 00220 { } 00221 00222 template<typename _Rep, typename _Period> 00223 unique_lock(mutex_type& __m, 00224 const chrono::duration<_Rep, _Period>& __rtime) 00225 : _M_device(std::__addressof(__m)), 00226 _M_owns(_M_device->try_lock_for(__rtime)) 00227 { } 00228 00229 ~unique_lock() 00230 { 00231 if (_M_owns) 00232 unlock(); 00233 } 00234 00235 unique_lock(const unique_lock&) = delete; 00236 unique_lock& operator=(const unique_lock&) = delete; 00237 00238 unique_lock(unique_lock&& __u) noexcept 00239 : _M_device(__u._M_device), _M_owns(__u._M_owns) 00240 { 00241 __u._M_device = 0; 00242 __u._M_owns = false; 00243 } 00244 00245 unique_lock& operator=(unique_lock&& __u) noexcept 00246 { 00247 if(_M_owns) 00248 unlock(); 00249 00250 unique_lock(std::move(__u)).swap(*this); 00251 00252 __u._M_device = 0; 00253 __u._M_owns = false; 00254 00255 return *this; 00256 } 00257 00258 void 00259 lock() 00260 { 00261 if (!_M_device) 00262 __throw_system_error(int(errc::operation_not_permitted)); 00263 else if (_M_owns) 00264 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00265 else 00266 { 00267 _M_device->lock(); 00268 _M_owns = true; 00269 } 00270 } 00271 00272 bool 00273 try_lock() 00274 { 00275 if (!_M_device) 00276 __throw_system_error(int(errc::operation_not_permitted)); 00277 else if (_M_owns) 00278 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00279 else 00280 { 00281 _M_owns = _M_device->try_lock(); 00282 return _M_owns; 00283 } 00284 } 00285 00286 template<typename _Clock, typename _Duration> 00287 bool 00288 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 00289 { 00290 if (!_M_device) 00291 __throw_system_error(int(errc::operation_not_permitted)); 00292 else if (_M_owns) 00293 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00294 else 00295 { 00296 _M_owns = _M_device->try_lock_until(__atime); 00297 return _M_owns; 00298 } 00299 } 00300 00301 template<typename _Rep, typename _Period> 00302 bool 00303 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 00304 { 00305 if (!_M_device) 00306 __throw_system_error(int(errc::operation_not_permitted)); 00307 else if (_M_owns) 00308 __throw_system_error(int(errc::resource_deadlock_would_occur)); 00309 else 00310 { 00311 _M_owns = _M_device->try_lock_for(__rtime); 00312 return _M_owns; 00313 } 00314 } 00315 00316 void 00317 unlock() 00318 { 00319 if (!_M_owns) 00320 __throw_system_error(int(errc::operation_not_permitted)); 00321 else if (_M_device) 00322 { 00323 _M_device->unlock(); 00324 _M_owns = false; 00325 } 00326 } 00327 00328 void 00329 swap(unique_lock& __u) noexcept 00330 { 00331 std::swap(_M_device, __u._M_device); 00332 std::swap(_M_owns, __u._M_owns); 00333 } 00334 00335 mutex_type* 00336 release() noexcept 00337 { 00338 mutex_type* __ret = _M_device; 00339 _M_device = 0; 00340 _M_owns = false; 00341 return __ret; 00342 } 00343 00344 bool 00345 owns_lock() const noexcept 00346 { return _M_owns; } 00347 00348 explicit operator bool() const noexcept 00349 { return owns_lock(); } 00350 00351 mutex_type* 00352 mutex() const noexcept 00353 { return _M_device; } 00354 00355 private: 00356 mutex_type* _M_device; 00357 bool _M_owns; // XXX use atomic_bool 00358 }; 00359 00360 /// Swap overload for unique_lock objects. 00361 template<typename _Mutex> 00362 inline void 00363 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 00364 { __x.swap(__y); } 00365 00366 // @} group mutexes 00367 _GLIBCXX_END_NAMESPACE_VERSION 00368 } // namespace 00369 #endif // _GLIBCXX_USE_C99_STDINT_TR1 00370 00371 #endif // C++11 00372 00373 #endif // _GLIBCXX_MUTEX_H