blob: 9aa051be37f2c55c0d422a91f0274fe439ac259f [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
10#include "mutex"
11#include "limits"
12#include "system_error"
13#include "cassert"
14
15_LIBCPP_BEGIN_NAMESPACE_STD
16
17const defer_lock_t defer_lock = {};
18const try_to_lock_t try_to_lock = {};
19const adopt_lock_t adopt_lock = {};
20
21mutex::~mutex()
22{
Howard Hinnant28b24882011-12-01 20:21:04 +000023 pthread_mutex_destroy(&__m_);
Howard Hinnantc51e1022010-05-11 19:42:16 +000024}
25
26void
27mutex::lock()
28{
29 int ec = pthread_mutex_lock(&__m_);
30 if (ec)
31 __throw_system_error(ec, "mutex lock failed");
32}
33
34bool
35mutex::try_lock()
36{
37 return pthread_mutex_trylock(&__m_) == 0;
38}
39
40void
41mutex::unlock()
42{
43 int ec = pthread_mutex_unlock(&__m_);
44 assert(ec == 0);
45}
46
47// recursive_mutex
48
49recursive_mutex::recursive_mutex()
50{
51 pthread_mutexattr_t attr;
52 int ec = pthread_mutexattr_init(&attr);
53 if (ec)
54 goto fail;
55 ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
56 if (ec)
57 {
58 pthread_mutexattr_destroy(&attr);
59 goto fail;
60 }
61 ec = pthread_mutex_init(&__m_, &attr);
62 if (ec)
63 {
64 pthread_mutexattr_destroy(&attr);
65 goto fail;
66 }
67 ec = pthread_mutexattr_destroy(&attr);
68 if (ec)
69 {
70 pthread_mutex_destroy(&__m_);
71 goto fail;
72 }
73 return;
74fail:
75 __throw_system_error(ec, "recursive_mutex constructor failed");
76}
77
78recursive_mutex::~recursive_mutex()
79{
80 int e = pthread_mutex_destroy(&__m_);
81 assert(e == 0);
82}
83
84void
85recursive_mutex::lock()
86{
87 int ec = pthread_mutex_lock(&__m_);
88 if (ec)
89 __throw_system_error(ec, "recursive_mutex lock failed");
90}
91
92void
93recursive_mutex::unlock()
94{
95 int e = pthread_mutex_unlock(&__m_);
96 assert(e == 0);
97}
98
99bool
100recursive_mutex::try_lock()
101{
102 return pthread_mutex_trylock(&__m_) == 0;
103}
104
105// timed_mutex
106
107timed_mutex::timed_mutex()
108 : __locked_(false)
109{
110}
111
112timed_mutex::~timed_mutex()
113{
114 lock_guard<mutex> _(__m_);
115}
116
117void
118timed_mutex::lock()
119{
120 unique_lock<mutex> lk(__m_);
121 while (__locked_)
122 __cv_.wait(lk);
123 __locked_ = true;
124}
125
126bool
127timed_mutex::try_lock()
128{
129 unique_lock<mutex> lk(__m_, try_to_lock);
130 if (lk.owns_lock() && !__locked_)
131 {
132 __locked_ = true;
133 return true;
134 }
135 return false;
136}
137
138void
139timed_mutex::unlock()
140{
141 lock_guard<mutex> _(__m_);
142 __locked_ = false;
143 __cv_.notify_one();
144}
145
146// recursive_timed_mutex
147
148recursive_timed_mutex::recursive_timed_mutex()
149 : __count_(0),
Howard Hinnant155c2af2010-05-24 17:49:41 +0000150 __id_(0)
Howard Hinnantc51e1022010-05-11 19:42:16 +0000151{
152}
153
154recursive_timed_mutex::~recursive_timed_mutex()
155{
156 lock_guard<mutex> _(__m_);
157}
158
159void
160recursive_timed_mutex::lock()
161{
162 pthread_t id = pthread_self();
163 unique_lock<mutex> lk(__m_);
164 if (pthread_equal(id, __id_))
165 {
166 if (__count_ == numeric_limits<size_t>::max())
167 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
168 ++__count_;
169 return;
170 }
171 while (__count_ != 0)
172 __cv_.wait(lk);
173 __count_ = 1;
174 __id_ = id;
175}
176
177bool
178recursive_timed_mutex::try_lock()
179{
180 pthread_t id = pthread_self();
181 unique_lock<mutex> lk(__m_, try_to_lock);
182 if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_)))
183 {
184 if (__count_ == numeric_limits<size_t>::max())
185 return false;
186 ++__count_;
187 __id_ = id;
188 return true;
189 }
190 return false;
191}
192
193void
194recursive_timed_mutex::unlock()
195{
196 unique_lock<mutex> lk(__m_);
197 if (--__count_ == 0)
198 {
Howard Hinnant155c2af2010-05-24 17:49:41 +0000199 __id_ = 0;
Howard Hinnantc51e1022010-05-11 19:42:16 +0000200 lk.unlock();
201 __cv_.notify_one();
202 }
203}
204
205// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
206// without illegal macros (unexpected macros not beginning with _UpperCase or
207// __lowercase), and if it stops spinning waiting threads, then call_once should
208// call into dispatch_once_f instead of here. Relevant radar this code needs to
209// keep in sync with: 7741191.
210
211static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
212static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
213
214void
215__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
216{
217 pthread_mutex_lock(&mut);
218 while (flag == 1)
219 pthread_cond_wait(&cv, &mut);
220 if (flag == 0)
221 {
Howard Hinnant72f73582010-08-11 17:04:31 +0000222#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000223 try
224 {
Howard Hinnantffb308e2010-08-22 00:03:27 +0000225#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000226 flag = 1;
227 pthread_mutex_unlock(&mut);
228 func(arg);
229 pthread_mutex_lock(&mut);
230 flag = ~0ul;
231 pthread_mutex_unlock(&mut);
232 pthread_cond_broadcast(&cv);
Howard Hinnant72f73582010-08-11 17:04:31 +0000233#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000234 }
235 catch (...)
236 {
237 pthread_mutex_lock(&mut);
238 flag = 0ul;
239 pthread_mutex_unlock(&mut);
Howard Hinnant36b31ae2010-06-03 16:42:57 +0000240 pthread_cond_broadcast(&cv);
Howard Hinnantc51e1022010-05-11 19:42:16 +0000241 throw;
242 }
Howard Hinnantffb308e2010-08-22 00:03:27 +0000243#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantc51e1022010-05-11 19:42:16 +0000244 }
245 else
246 pthread_mutex_unlock(&mut);
247}
248
249_LIBCPP_END_NAMESPACE_STD