blob: b858e8877ae5c959d53b96607b9e70586a759195 [file] [log] [blame]
Howard Hinnantc51e1022010-05-11 19:42:16 +00001//===------------------------- mutex.cpp ----------------------------------===//
2//
Howard Hinnantc566dc32010-05-11 21:36:01 +00003// The LLVM Compiler Infrastructure
Howard Hinnantc51e1022010-05-11 19:42:16 +00004//
Howard Hinnantee11c312010-11-16 22:09:02 +00005// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
Howard Hinnantc51e1022010-05-11 19:42:16 +00007//
8//===----------------------------------------------------------------------===//
9
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000010#define _LIBCPP_BUILDING_MUTEX
Howard Hinnantc51e1022010-05-11 19:42:16 +000011#include "mutex"
12#include "limits"
13#include "system_error"
Eric Fiselier1366d262015-08-18 21:08:54 +000014#include "include/atomic_support.h"
Howard Hinnantc51e1022010-05-11 19:42:16 +000015
16_LIBCPP_BEGIN_NAMESPACE_STD
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +000017#ifndef _LIBCPP_HAS_NO_THREADS
Howard Hinnantc51e1022010-05-11 19:42:16 +000018
19const defer_lock_t defer_lock = {};
20const try_to_lock_t try_to_lock = {};
21const adopt_lock_t adopt_lock = {};
22
23mutex::~mutex()
24{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000025 __libcpp_mutex_destroy(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000026}
27
28void
29mutex::lock()
30{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000031 int ec = __libcpp_mutex_lock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000032 if (ec)
33 __throw_system_error(ec, "mutex lock failed");
34}
35
36bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000037mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000038{
Eric Fiselier0ec14472017-01-14 10:27:12 +000039 return __libcpp_mutex_trylock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000040}
41
42void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000043mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000044{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000045 int ec = __libcpp_mutex_unlock(&__m_);
Howard Hinnant9ad56f32013-09-21 21:26:37 +000046 (void)ec;
Eric Fiseliercf6c9df2017-01-24 04:57:33 +000047 _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000048}
49
50// recursive_mutex
51
52recursive_mutex::recursive_mutex()
53{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000054 int ec = __libcpp_recursive_mutex_init(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000055 if (ec)
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000056 __throw_system_error(ec, "recursive_mutex constructor failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000057}
58
59recursive_mutex::~recursive_mutex()
60{
Saleem Abdulrasool0bc37ca2017-01-05 17:54:45 +000061 int e = __libcpp_recursive_mutex_destroy(&__m_);
Howard Hinnant9ad56f32013-09-21 21:26:37 +000062 (void)e;
Eric Fiseliercf6c9df2017-01-24 04:57:33 +000063 _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000064}
65
66void
67recursive_mutex::lock()
68{
Saleem Abdulrasool0bc37ca2017-01-05 17:54:45 +000069 int ec = __libcpp_recursive_mutex_lock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000070 if (ec)
71 __throw_system_error(ec, "recursive_mutex lock failed");
72}
73
74void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000075recursive_mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000076{
Saleem Abdulrasool0bc37ca2017-01-05 17:54:45 +000077 int e = __libcpp_recursive_mutex_unlock(&__m_);
Howard Hinnant9ad56f32013-09-21 21:26:37 +000078 (void)e;
Eric Fiseliercf6c9df2017-01-24 04:57:33 +000079 _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000080}
81
82bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000083recursive_mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000084{
Eric Fiselier0ec14472017-01-14 10:27:12 +000085 return __libcpp_recursive_mutex_trylock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000086}
87
88// timed_mutex
89
90timed_mutex::timed_mutex()
91 : __locked_(false)
92{
93}
94
95timed_mutex::~timed_mutex()
96{
97 lock_guard<mutex> _(__m_);
98}
99
100void
101timed_mutex::lock()
102{
103 unique_lock<mutex> lk(__m_);
104 while (__locked_)
105 __cv_.wait(lk);
106 __locked_ = true;
107}
108
109bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000110timed_mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000111{
112 unique_lock<mutex> lk(__m_, try_to_lock);
113 if (lk.owns_lock() && !__locked_)
114 {
115 __locked_ = true;
116 return true;
117 }
118 return false;
119}
120
121void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000122timed_mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000123{
124 lock_guard<mutex> _(__m_);
125 __locked_ = false;
126 __cv_.notify_one();
127}
128
129// recursive_timed_mutex
130
131recursive_timed_mutex::recursive_timed_mutex()
132 : __count_(0),
Howard Hinnant155c2af2010-05-24 17:49:41 +0000133 __id_(0)
Howard Hinnantc51e1022010-05-11 19:42:16 +0000134{
135}
136
137recursive_timed_mutex::~recursive_timed_mutex()
138{
139 lock_guard<mutex> _(__m_);
140}
141
142void
143recursive_timed_mutex::lock()
144{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000145 __libcpp_thread_id id = __libcpp_thread_get_current_id();
Howard Hinnantc51e1022010-05-11 19:42:16 +0000146 unique_lock<mutex> lk(__m_);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000147 if (__libcpp_thread_id_equal(id, __id_))
Howard Hinnantc51e1022010-05-11 19:42:16 +0000148 {
149 if (__count_ == numeric_limits<size_t>::max())
150 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
151 ++__count_;
152 return;
153 }
154 while (__count_ != 0)
155 __cv_.wait(lk);
156 __count_ = 1;
157 __id_ = id;
158}
159
160bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000161recursive_timed_mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000162{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000163 __libcpp_thread_id id = __libcpp_thread_get_current_id();
Howard Hinnantc51e1022010-05-11 19:42:16 +0000164 unique_lock<mutex> lk(__m_, try_to_lock);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000165 if (lk.owns_lock() && (__count_ == 0 || __libcpp_thread_id_equal(id, __id_)))
Howard Hinnantc51e1022010-05-11 19:42:16 +0000166 {
167 if (__count_ == numeric_limits<size_t>::max())
168 return false;
169 ++__count_;
170 __id_ = id;
171 return true;
172 }
173 return false;
174}
175
176void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000177recursive_timed_mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000178{
179 unique_lock<mutex> lk(__m_);
180 if (--__count_ == 0)
181 {
Howard Hinnant155c2af2010-05-24 17:49:41 +0000182 __id_ = 0;
Howard Hinnantc51e1022010-05-11 19:42:16 +0000183 lk.unlock();
184 __cv_.notify_one();
185 }
186}
187
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000188#endif // !_LIBCPP_HAS_NO_THREADS
189
Howard Hinnantc51e1022010-05-11 19:42:16 +0000190// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
191// without illegal macros (unexpected macros not beginning with _UpperCase or
192// __lowercase), and if it stops spinning waiting threads, then call_once should
193// call into dispatch_once_f instead of here. Relevant radar this code needs to
194// keep in sync with: 7741191.
195
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000196#ifndef _LIBCPP_HAS_NO_THREADS
Eric Fiselier637dd952016-09-28 22:08:13 +0000197_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
198_LIBCPP_SAFE_STATIC static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000199#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000200
201void
202__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
203{
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000204#if defined(_LIBCPP_HAS_NO_THREADS)
205 if (flag == 0)
206 {
207#ifndef _LIBCPP_NO_EXCEPTIONS
208 try
209 {
210#endif // _LIBCPP_NO_EXCEPTIONS
211 flag = 1;
212 func(arg);
213 flag = ~0ul;
214#ifndef _LIBCPP_NO_EXCEPTIONS
215 }
216 catch (...)
217 {
218 flag = 0ul;
219 throw;
220 }
221#endif // _LIBCPP_NO_EXCEPTIONS
222 }
223#else // !_LIBCPP_HAS_NO_THREADS
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000224 __libcpp_mutex_lock(&mut);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000225 while (flag == 1)
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000226 __libcpp_condvar_wait(&cv, &mut);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000227 if (flag == 0)
228 {
Howard Hinnant72f73582010-08-11 17:04:31 +0000229#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000230 try
231 {
Howard Hinnantffb308e2010-08-22 00:03:27 +0000232#endif // _LIBCPP_NO_EXCEPTIONS
Eric Fiselier89659d12015-07-07 00:27:16 +0000233 __libcpp_relaxed_store(&flag, 1ul);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000234 __libcpp_mutex_unlock(&mut);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000235 func(arg);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000236 __libcpp_mutex_lock(&mut);
Kuba Breckade9d6792016-09-04 09:55:12 +0000237 __libcpp_atomic_store(&flag, ~0ul, _AO_Release);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000238 __libcpp_mutex_unlock(&mut);
239 __libcpp_condvar_broadcast(&cv);
Howard Hinnant72f73582010-08-11 17:04:31 +0000240#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000241 }
242 catch (...)
243 {
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000244 __libcpp_mutex_lock(&mut);
Eric Fiselier89659d12015-07-07 00:27:16 +0000245 __libcpp_relaxed_store(&flag, 0ul);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000246 __libcpp_mutex_unlock(&mut);
247 __libcpp_condvar_broadcast(&cv);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000248 throw;
249 }
Howard Hinnantffb308e2010-08-22 00:03:27 +0000250#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000251 }
252 else
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000253 __libcpp_mutex_unlock(&mut);
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000254#endif // !_LIBCPP_HAS_NO_THREADS
255
Howard Hinnantc51e1022010-05-11 19:42:16 +0000256}
257
258_LIBCPP_END_NAMESPACE_STD