blob: 07678978a67880dbe8f944c77bcbcd65881217eb [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001//===------------------------- mutex.cpp ----------------------------------===//
2//
Howard Hinnantf5256e12010-05-11 21:36:01 +00003// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00004//
Howard Hinnantb64f8b02010-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 Hinnantbc8d3f92010-05-11 19:42:16 +00007//
8//===----------------------------------------------------------------------===//
9
Howard Hinnant499c61f2012-07-21 16:13:09 +000010#define _LIBCPP_BUILDING_MUTEX
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000011#include "mutex"
12#include "limits"
13#include "system_error"
14#include "cassert"
15
16_LIBCPP_BEGIN_NAMESPACE_STD
17
18const defer_lock_t defer_lock = {};
19const try_to_lock_t try_to_lock = {};
20const adopt_lock_t adopt_lock = {};
21
22mutex::~mutex()
23{
Howard Hinnantec3773c2011-12-01 20:21:04 +000024 pthread_mutex_destroy(&__m_);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000025}
26
27void
28mutex::lock()
29{
30 int ec = pthread_mutex_lock(&__m_);
31 if (ec)
32 __throw_system_error(ec, "mutex lock failed");
33}
34
35bool
Howard Hinnant499c61f2012-07-21 16:13:09 +000036mutex::try_lock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000037{
38 return pthread_mutex_trylock(&__m_) == 0;
39}
40
41void
Howard Hinnant499c61f2012-07-21 16:13:09 +000042mutex::unlock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000043{
44 int ec = pthread_mutex_unlock(&__m_);
Howard Hinnantfc910cb2013-09-21 21:26:37 +000045 (void)ec;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000046 assert(ec == 0);
47}
48
49// recursive_mutex
50
51recursive_mutex::recursive_mutex()
52{
53 pthread_mutexattr_t attr;
54 int ec = pthread_mutexattr_init(&attr);
55 if (ec)
56 goto fail;
57 ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
58 if (ec)
59 {
60 pthread_mutexattr_destroy(&attr);
61 goto fail;
62 }
63 ec = pthread_mutex_init(&__m_, &attr);
64 if (ec)
65 {
66 pthread_mutexattr_destroy(&attr);
67 goto fail;
68 }
69 ec = pthread_mutexattr_destroy(&attr);
70 if (ec)
71 {
72 pthread_mutex_destroy(&__m_);
73 goto fail;
74 }
75 return;
76fail:
77 __throw_system_error(ec, "recursive_mutex constructor failed");
78}
79
80recursive_mutex::~recursive_mutex()
81{
82 int e = pthread_mutex_destroy(&__m_);
Howard Hinnantfc910cb2013-09-21 21:26:37 +000083 (void)e;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000084 assert(e == 0);
85}
86
87void
88recursive_mutex::lock()
89{
90 int ec = pthread_mutex_lock(&__m_);
91 if (ec)
92 __throw_system_error(ec, "recursive_mutex lock failed");
93}
94
95void
Howard Hinnant499c61f2012-07-21 16:13:09 +000096recursive_mutex::unlock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000097{
98 int e = pthread_mutex_unlock(&__m_);
Howard Hinnantfc910cb2013-09-21 21:26:37 +000099 (void)e;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000100 assert(e == 0);
101}
102
103bool
Howard Hinnant499c61f2012-07-21 16:13:09 +0000104recursive_mutex::try_lock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000105{
106 return pthread_mutex_trylock(&__m_) == 0;
107}
108
109// timed_mutex
110
111timed_mutex::timed_mutex()
112 : __locked_(false)
113{
114}
115
116timed_mutex::~timed_mutex()
117{
118 lock_guard<mutex> _(__m_);
119}
120
121void
122timed_mutex::lock()
123{
124 unique_lock<mutex> lk(__m_);
125 while (__locked_)
126 __cv_.wait(lk);
127 __locked_ = true;
128}
129
130bool
Howard Hinnant499c61f2012-07-21 16:13:09 +0000131timed_mutex::try_lock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000132{
133 unique_lock<mutex> lk(__m_, try_to_lock);
134 if (lk.owns_lock() && !__locked_)
135 {
136 __locked_ = true;
137 return true;
138 }
139 return false;
140}
141
142void
Howard Hinnant499c61f2012-07-21 16:13:09 +0000143timed_mutex::unlock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000144{
145 lock_guard<mutex> _(__m_);
146 __locked_ = false;
147 __cv_.notify_one();
148}
149
150// recursive_timed_mutex
151
152recursive_timed_mutex::recursive_timed_mutex()
153 : __count_(0),
Howard Hinnantadff4892010-05-24 17:49:41 +0000154 __id_(0)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000155{
156}
157
158recursive_timed_mutex::~recursive_timed_mutex()
159{
160 lock_guard<mutex> _(__m_);
161}
162
163void
164recursive_timed_mutex::lock()
165{
166 pthread_t id = pthread_self();
167 unique_lock<mutex> lk(__m_);
168 if (pthread_equal(id, __id_))
169 {
170 if (__count_ == numeric_limits<size_t>::max())
171 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
172 ++__count_;
173 return;
174 }
175 while (__count_ != 0)
176 __cv_.wait(lk);
177 __count_ = 1;
178 __id_ = id;
179}
180
181bool
Howard Hinnant499c61f2012-07-21 16:13:09 +0000182recursive_timed_mutex::try_lock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000183{
184 pthread_t id = pthread_self();
185 unique_lock<mutex> lk(__m_, try_to_lock);
186 if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_)))
187 {
188 if (__count_ == numeric_limits<size_t>::max())
189 return false;
190 ++__count_;
191 __id_ = id;
192 return true;
193 }
194 return false;
195}
196
197void
Howard Hinnant499c61f2012-07-21 16:13:09 +0000198recursive_timed_mutex::unlock() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000199{
200 unique_lock<mutex> lk(__m_);
201 if (--__count_ == 0)
202 {
Howard Hinnantadff4892010-05-24 17:49:41 +0000203 __id_ = 0;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000204 lk.unlock();
205 __cv_.notify_one();
206 }
207}
208
209// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
210// without illegal macros (unexpected macros not beginning with _UpperCase or
211// __lowercase), and if it stops spinning waiting threads, then call_once should
212// call into dispatch_once_f instead of here. Relevant radar this code needs to
213// keep in sync with: 7741191.
214
215static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
216static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
217
218void
219__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
220{
221 pthread_mutex_lock(&mut);
222 while (flag == 1)
223 pthread_cond_wait(&cv, &mut);
224 if (flag == 0)
225 {
Howard Hinnantd4444702010-08-11 17:04:31 +0000226#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000227 try
228 {
Howard Hinnant16e6e1d2010-08-22 00:03:27 +0000229#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000230 flag = 1;
231 pthread_mutex_unlock(&mut);
232 func(arg);
233 pthread_mutex_lock(&mut);
234 flag = ~0ul;
235 pthread_mutex_unlock(&mut);
236 pthread_cond_broadcast(&cv);
Howard Hinnantd4444702010-08-11 17:04:31 +0000237#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000238 }
239 catch (...)
240 {
241 pthread_mutex_lock(&mut);
242 flag = 0ul;
243 pthread_mutex_unlock(&mut);
Howard Hinnant21aefc32010-06-03 16:42:57 +0000244 pthread_cond_broadcast(&cv);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000245 throw;
246 }
Howard Hinnant16e6e1d2010-08-22 00:03:27 +0000247#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000248 }
249 else
250 pthread_mutex_unlock(&mut);
251}
252
253_LIBCPP_END_NAMESPACE_STD