blob: c36bd5549da8ee222f87e8740e6cee62fcb39fd2 [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"
Eric Fiselierf4433a32017-05-31 22:07:49 +000015#include "__undef_macros"
Howard Hinnantc51e1022010-05-11 19:42:16 +000016
17_LIBCPP_BEGIN_NAMESPACE_STD
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +000018#ifndef _LIBCPP_HAS_NO_THREADS
Howard Hinnantc51e1022010-05-11 19:42:16 +000019
20const defer_lock_t defer_lock = {};
21const try_to_lock_t try_to_lock = {};
22const adopt_lock_t adopt_lock = {};
23
24mutex::~mutex()
25{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000026 __libcpp_mutex_destroy(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000027}
28
29void
30mutex::lock()
31{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000032 int ec = __libcpp_mutex_lock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000033 if (ec)
34 __throw_system_error(ec, "mutex lock failed");
35}
36
37bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000038mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000039{
Eric Fiselier0ec14472017-01-14 10:27:12 +000040 return __libcpp_mutex_trylock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000041}
42
43void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000044mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000045{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000046 int ec = __libcpp_mutex_unlock(&__m_);
Howard Hinnant9ad56f32013-09-21 21:26:37 +000047 (void)ec;
Eric Fiselier59cd98b2017-02-04 23:22:28 +000048 _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000049}
50
51// recursive_mutex
52
53recursive_mutex::recursive_mutex()
54{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000055 int ec = __libcpp_recursive_mutex_init(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000056 if (ec)
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +000057 __throw_system_error(ec, "recursive_mutex constructor failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000058}
59
60recursive_mutex::~recursive_mutex()
61{
Saleem Abdulrasool0bc37ca2017-01-05 17:54:45 +000062 int e = __libcpp_recursive_mutex_destroy(&__m_);
Howard Hinnant9ad56f32013-09-21 21:26:37 +000063 (void)e;
Eric Fiselier59cd98b2017-02-04 23:22:28 +000064 _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000065}
66
67void
68recursive_mutex::lock()
69{
Saleem Abdulrasool0bc37ca2017-01-05 17:54:45 +000070 int ec = __libcpp_recursive_mutex_lock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000071 if (ec)
72 __throw_system_error(ec, "recursive_mutex lock failed");
73}
74
75void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000076recursive_mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000077{
Saleem Abdulrasool0bc37ca2017-01-05 17:54:45 +000078 int e = __libcpp_recursive_mutex_unlock(&__m_);
Howard Hinnant9ad56f32013-09-21 21:26:37 +000079 (void)e;
Eric Fiselier59cd98b2017-02-04 23:22:28 +000080 _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
Howard Hinnantc51e1022010-05-11 19:42:16 +000081}
82
83bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +000084recursive_mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +000085{
Eric Fiselier0ec14472017-01-14 10:27:12 +000086 return __libcpp_recursive_mutex_trylock(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000087}
88
89// timed_mutex
90
91timed_mutex::timed_mutex()
92 : __locked_(false)
93{
94}
95
96timed_mutex::~timed_mutex()
97{
98 lock_guard<mutex> _(__m_);
99}
100
101void
102timed_mutex::lock()
103{
104 unique_lock<mutex> lk(__m_);
105 while (__locked_)
106 __cv_.wait(lk);
107 __locked_ = true;
108}
109
110bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000111timed_mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000112{
113 unique_lock<mutex> lk(__m_, try_to_lock);
114 if (lk.owns_lock() && !__locked_)
115 {
116 __locked_ = true;
117 return true;
118 }
119 return false;
120}
121
122void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000123timed_mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000124{
125 lock_guard<mutex> _(__m_);
126 __locked_ = false;
127 __cv_.notify_one();
128}
129
130// recursive_timed_mutex
131
132recursive_timed_mutex::recursive_timed_mutex()
133 : __count_(0),
Howard Hinnant155c2af2010-05-24 17:49:41 +0000134 __id_(0)
Howard Hinnantc51e1022010-05-11 19:42:16 +0000135{
136}
137
138recursive_timed_mutex::~recursive_timed_mutex()
139{
140 lock_guard<mutex> _(__m_);
141}
142
143void
144recursive_timed_mutex::lock()
145{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000146 __libcpp_thread_id id = __libcpp_thread_get_current_id();
Howard Hinnantc51e1022010-05-11 19:42:16 +0000147 unique_lock<mutex> lk(__m_);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000148 if (__libcpp_thread_id_equal(id, __id_))
Howard Hinnantc51e1022010-05-11 19:42:16 +0000149 {
150 if (__count_ == numeric_limits<size_t>::max())
151 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
152 ++__count_;
153 return;
154 }
155 while (__count_ != 0)
156 __cv_.wait(lk);
157 __count_ = 1;
158 __id_ = id;
159}
160
161bool
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000162recursive_timed_mutex::try_lock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000163{
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000164 __libcpp_thread_id id = __libcpp_thread_get_current_id();
Howard Hinnantc51e1022010-05-11 19:42:16 +0000165 unique_lock<mutex> lk(__m_, try_to_lock);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000166 if (lk.owns_lock() && (__count_ == 0 || __libcpp_thread_id_equal(id, __id_)))
Howard Hinnantc51e1022010-05-11 19:42:16 +0000167 {
168 if (__count_ == numeric_limits<size_t>::max())
169 return false;
170 ++__count_;
171 __id_ = id;
172 return true;
173 }
174 return false;
175}
176
177void
Howard Hinnantbd05d6a2012-07-21 16:13:09 +0000178recursive_timed_mutex::unlock() _NOEXCEPT
Howard Hinnantc51e1022010-05-11 19:42:16 +0000179{
180 unique_lock<mutex> lk(__m_);
181 if (--__count_ == 0)
182 {
Howard Hinnant155c2af2010-05-24 17:49:41 +0000183 __id_ = 0;
Howard Hinnantc51e1022010-05-11 19:42:16 +0000184 lk.unlock();
185 __cv_.notify_one();
186 }
187}
188
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000189#endif // !_LIBCPP_HAS_NO_THREADS
190
Howard Hinnantc51e1022010-05-11 19:42:16 +0000191// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
192// without illegal macros (unexpected macros not beginning with _UpperCase or
193// __lowercase), and if it stops spinning waiting threads, then call_once should
194// call into dispatch_once_f instead of here. Relevant radar this code needs to
195// keep in sync with: 7741191.
196
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000197#ifndef _LIBCPP_HAS_NO_THREADS
Eric Fiselier637dd952016-09-28 22:08:13 +0000198_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
199_LIBCPP_SAFE_STATIC static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000200#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000201
202void
203__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
204{
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000205#if defined(_LIBCPP_HAS_NO_THREADS)
206 if (flag == 0)
207 {
208#ifndef _LIBCPP_NO_EXCEPTIONS
209 try
210 {
211#endif // _LIBCPP_NO_EXCEPTIONS
212 flag = 1;
213 func(arg);
214 flag = ~0ul;
215#ifndef _LIBCPP_NO_EXCEPTIONS
216 }
217 catch (...)
218 {
219 flag = 0ul;
220 throw;
221 }
222#endif // _LIBCPP_NO_EXCEPTIONS
223 }
224#else // !_LIBCPP_HAS_NO_THREADS
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000225 __libcpp_mutex_lock(&mut);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000226 while (flag == 1)
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000227 __libcpp_condvar_wait(&cv, &mut);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000228 if (flag == 0)
229 {
Howard Hinnant72f73582010-08-11 17:04:31 +0000230#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000231 try
232 {
Howard Hinnantffb308e2010-08-22 00:03:27 +0000233#endif // _LIBCPP_NO_EXCEPTIONS
Eric Fiselier89659d12015-07-07 00:27:16 +0000234 __libcpp_relaxed_store(&flag, 1ul);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000235 __libcpp_mutex_unlock(&mut);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000236 func(arg);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000237 __libcpp_mutex_lock(&mut);
Kuba Breckade9d6792016-09-04 09:55:12 +0000238 __libcpp_atomic_store(&flag, ~0ul, _AO_Release);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000239 __libcpp_mutex_unlock(&mut);
240 __libcpp_condvar_broadcast(&cv);
Howard Hinnant72f73582010-08-11 17:04:31 +0000241#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000242 }
243 catch (...)
244 {
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000245 __libcpp_mutex_lock(&mut);
Eric Fiselier89659d12015-07-07 00:27:16 +0000246 __libcpp_relaxed_store(&flag, 0ul);
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000247 __libcpp_mutex_unlock(&mut);
248 __libcpp_condvar_broadcast(&cv);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000249 throw;
250 }
Howard Hinnantffb308e2010-08-22 00:03:27 +0000251#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000252 }
253 else
Asiri Rathnayakefa2e2032016-05-06 14:06:29 +0000254 __libcpp_mutex_unlock(&mut);
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000255#endif // !_LIBCPP_HAS_NO_THREADS
256
Howard Hinnantc51e1022010-05-11 19:42:16 +0000257}
258
259_LIBCPP_END_NAMESPACE_STD