1 //===------------------------- mutex.cpp ----------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #define _LIBCPP_BUILDING_MUTEX
11 #include "mutex"
12 #include "limits"
13 #include "system_error"
14 #include "cassert"
15
16 _LIBCPP_BEGIN_NAMESPACE_STD
17 #ifndef _LIBCPP_HAS_NO_THREADS
18
19 const defer_lock_t defer_lock = {};
20 const try_to_lock_t try_to_lock = {};
21 const adopt_lock_t adopt_lock = {};
22
~mutex()23 mutex::~mutex()
24 {
25 pthread_mutex_destroy(&__m_);
26 }
27
28 void
lock()29 mutex::lock()
30 {
31 int ec = pthread_mutex_lock(&__m_);
32 if (ec)
33 __throw_system_error(ec, "mutex lock failed");
34 }
35
36 bool
try_lock()37 mutex::try_lock() _NOEXCEPT
38 {
39 return pthread_mutex_trylock(&__m_) == 0;
40 }
41
42 void
unlock()43 mutex::unlock() _NOEXCEPT
44 {
45 int ec = pthread_mutex_unlock(&__m_);
46 (void)ec;
47 assert(ec == 0);
48 }
49
50 // recursive_mutex
51
recursive_mutex()52 recursive_mutex::recursive_mutex()
53 {
54 pthread_mutexattr_t attr;
55 int ec = pthread_mutexattr_init(&attr);
56 if (ec)
57 goto fail;
58 ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
59 if (ec)
60 {
61 pthread_mutexattr_destroy(&attr);
62 goto fail;
63 }
64 ec = pthread_mutex_init(&__m_, &attr);
65 if (ec)
66 {
67 pthread_mutexattr_destroy(&attr);
68 goto fail;
69 }
70 ec = pthread_mutexattr_destroy(&attr);
71 if (ec)
72 {
73 pthread_mutex_destroy(&__m_);
74 goto fail;
75 }
76 return;
77 fail:
78 __throw_system_error(ec, "recursive_mutex constructor failed");
79 }
80
~recursive_mutex()81 recursive_mutex::~recursive_mutex()
82 {
83 int e = pthread_mutex_destroy(&__m_);
84 (void)e;
85 assert(e == 0);
86 }
87
88 void
lock()89 recursive_mutex::lock()
90 {
91 int ec = pthread_mutex_lock(&__m_);
92 if (ec)
93 __throw_system_error(ec, "recursive_mutex lock failed");
94 }
95
96 void
unlock()97 recursive_mutex::unlock() _NOEXCEPT
98 {
99 int e = pthread_mutex_unlock(&__m_);
100 (void)e;
101 assert(e == 0);
102 }
103
104 bool
try_lock()105 recursive_mutex::try_lock() _NOEXCEPT
106 {
107 return pthread_mutex_trylock(&__m_) == 0;
108 }
109
110 // timed_mutex
111
timed_mutex()112 timed_mutex::timed_mutex()
113 : __locked_(false)
114 {
115 }
116
~timed_mutex()117 timed_mutex::~timed_mutex()
118 {
119 lock_guard<mutex> _(__m_);
120 }
121
122 void
lock()123 timed_mutex::lock()
124 {
125 unique_lock<mutex> lk(__m_);
126 while (__locked_)
127 __cv_.wait(lk);
128 __locked_ = true;
129 }
130
131 bool
try_lock()132 timed_mutex::try_lock() _NOEXCEPT
133 {
134 unique_lock<mutex> lk(__m_, try_to_lock);
135 if (lk.owns_lock() && !__locked_)
136 {
137 __locked_ = true;
138 return true;
139 }
140 return false;
141 }
142
143 void
unlock()144 timed_mutex::unlock() _NOEXCEPT
145 {
146 lock_guard<mutex> _(__m_);
147 __locked_ = false;
148 __cv_.notify_one();
149 }
150
151 // recursive_timed_mutex
152
recursive_timed_mutex()153 recursive_timed_mutex::recursive_timed_mutex()
154 : __count_(0),
155 __id_(0)
156 {
157 }
158
~recursive_timed_mutex()159 recursive_timed_mutex::~recursive_timed_mutex()
160 {
161 lock_guard<mutex> _(__m_);
162 }
163
164 void
lock()165 recursive_timed_mutex::lock()
166 {
167 pthread_t id = pthread_self();
168 unique_lock<mutex> lk(__m_);
169 if (pthread_equal(id, __id_))
170 {
171 if (__count_ == numeric_limits<size_t>::max())
172 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
173 ++__count_;
174 return;
175 }
176 while (__count_ != 0)
177 __cv_.wait(lk);
178 __count_ = 1;
179 __id_ = id;
180 }
181
182 bool
try_lock()183 recursive_timed_mutex::try_lock() _NOEXCEPT
184 {
185 pthread_t id = pthread_self();
186 unique_lock<mutex> lk(__m_, try_to_lock);
187 if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_)))
188 {
189 if (__count_ == numeric_limits<size_t>::max())
190 return false;
191 ++__count_;
192 __id_ = id;
193 return true;
194 }
195 return false;
196 }
197
198 void
unlock()199 recursive_timed_mutex::unlock() _NOEXCEPT
200 {
201 unique_lock<mutex> lk(__m_);
202 if (--__count_ == 0)
203 {
204 __id_ = 0;
205 lk.unlock();
206 __cv_.notify_one();
207 }
208 }
209
210 #endif // !_LIBCPP_HAS_NO_THREADS
211
212 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
213 // without illegal macros (unexpected macros not beginning with _UpperCase or
214 // __lowercase), and if it stops spinning waiting threads, then call_once should
215 // call into dispatch_once_f instead of here. Relevant radar this code needs to
216 // keep in sync with: 7741191.
217
218 #ifndef _LIBCPP_HAS_NO_THREADS
219 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
220 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
221 #endif
222
223 void
__call_once(volatile unsigned long & flag,void * arg,void (* func)(void *))224 __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
225 {
226 #if defined(_LIBCPP_HAS_NO_THREADS)
227 if (flag == 0)
228 {
229 #ifndef _LIBCPP_NO_EXCEPTIONS
230 try
231 {
232 #endif // _LIBCPP_NO_EXCEPTIONS
233 flag = 1;
234 func(arg);
235 flag = ~0ul;
236 #ifndef _LIBCPP_NO_EXCEPTIONS
237 }
238 catch (...)
239 {
240 flag = 0ul;
241 throw;
242 }
243 #endif // _LIBCPP_NO_EXCEPTIONS
244 }
245 #else // !_LIBCPP_HAS_NO_THREADS
246 pthread_mutex_lock(&mut);
247 while (flag == 1)
248 pthread_cond_wait(&cv, &mut);
249 if (flag == 0)
250 {
251 #ifndef _LIBCPP_NO_EXCEPTIONS
252 try
253 {
254 #endif // _LIBCPP_NO_EXCEPTIONS
255 flag = 1;
256 pthread_mutex_unlock(&mut);
257 func(arg);
258 pthread_mutex_lock(&mut);
259 flag = ~0ul;
260 pthread_mutex_unlock(&mut);
261 pthread_cond_broadcast(&cv);
262 #ifndef _LIBCPP_NO_EXCEPTIONS
263 }
264 catch (...)
265 {
266 pthread_mutex_lock(&mut);
267 flag = 0ul;
268 pthread_mutex_unlock(&mut);
269 pthread_cond_broadcast(&cv);
270 throw;
271 }
272 #endif // _LIBCPP_NO_EXCEPTIONS
273 }
274 else
275 pthread_mutex_unlock(&mut);
276 #endif // !_LIBCPP_HAS_NO_THREADS
277
278 }
279
280 _LIBCPP_END_NAMESPACE_STD
281