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