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#if !_LIBCPP_SINGLE_THREADED
18
19const defer_lock_t  defer_lock = {};
20const try_to_lock_t try_to_lock = {};
21const adopt_lock_t  adopt_lock = {};
22
23mutex::~mutex()
24{
25    pthread_mutex_destroy(&__m_);
26}
27
28void
29mutex::lock()
30{
31    int ec = pthread_mutex_lock(&__m_);
32    if (ec)
33        __throw_system_error(ec, "mutex lock failed");
34}
35
36bool
37mutex::try_lock() _NOEXCEPT
38{
39    return pthread_mutex_trylock(&__m_) == 0;
40}
41
42void
43mutex::unlock() _NOEXCEPT
44{
45    int ec = pthread_mutex_unlock(&__m_);
46    (void)ec;
47    assert(ec == 0);
48}
49
50// recursive_mutex
51
52recursive_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;
77fail:
78    __throw_system_error(ec, "recursive_mutex constructor failed");
79}
80
81recursive_mutex::~recursive_mutex()
82{
83    int e = pthread_mutex_destroy(&__m_);
84    (void)e;
85    assert(e == 0);
86}
87
88void
89recursive_mutex::lock()
90{
91    int ec = pthread_mutex_lock(&__m_);
92    if (ec)
93        __throw_system_error(ec, "recursive_mutex lock failed");
94}
95
96void
97recursive_mutex::unlock() _NOEXCEPT
98{
99    int e = pthread_mutex_unlock(&__m_);
100    (void)e;
101    assert(e == 0);
102}
103
104bool
105recursive_mutex::try_lock() _NOEXCEPT
106{
107    return pthread_mutex_trylock(&__m_) == 0;
108}
109
110// timed_mutex
111
112timed_mutex::timed_mutex()
113    : __locked_(false)
114{
115}
116
117timed_mutex::~timed_mutex()
118{
119    lock_guard<mutex> _(__m_);
120}
121
122void
123timed_mutex::lock()
124{
125    unique_lock<mutex> lk(__m_);
126    while (__locked_)
127        __cv_.wait(lk);
128    __locked_ = true;
129}
130
131bool
132timed_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
143void
144timed_mutex::unlock() _NOEXCEPT
145{
146    lock_guard<mutex> _(__m_);
147    __locked_ = false;
148    __cv_.notify_one();
149}
150
151// recursive_timed_mutex
152
153recursive_timed_mutex::recursive_timed_mutex()
154    : __count_(0),
155      __id_(0)
156{
157}
158
159recursive_timed_mutex::~recursive_timed_mutex()
160{
161    lock_guard<mutex> _(__m_);
162}
163
164void
165recursive_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
182bool
183recursive_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
198void
199recursive_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_SINGLE_THREADED
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#if !_LIBCPP_SINGLE_THREADED
219static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
220static pthread_cond_t  cv  = PTHREAD_COND_INITIALIZER;
221#endif
222
223void
224__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
225{
226#if !_LIBCPP_SINGLE_THREADED
227    pthread_mutex_lock(&mut);
228    while (flag == 1)
229        pthread_cond_wait(&cv, &mut);
230#endif // !_LIBCPP_SINGLE_THREADED
231    if (flag == 0)
232    {
233#ifndef _LIBCPP_NO_EXCEPTIONS
234        try
235        {
236#endif  // _LIBCPP_NO_EXCEPTIONS
237            flag = 1;
238#if !_LIBCPP_SINGLE_THREADED
239            pthread_mutex_unlock(&mut);
240#endif // !_LIBCPP_SINGLE_THREADED
241            func(arg);
242#if !_LIBCPP_SINGLE_THREADED
243            pthread_mutex_lock(&mut);
244#endif // !_LIBCPP_SINGLE_THREADED
245            flag = ~0ul;
246#if !_LIBCPP_SINGLE_THREADED
247            pthread_mutex_unlock(&mut);
248            pthread_cond_broadcast(&cv);
249#endif // !_LIBCPP_SINGLE_THREADED
250#ifndef _LIBCPP_NO_EXCEPTIONS
251        }
252        catch (...)
253        {
254#if !_LIBCPP_SINGLE_THREADED
255            pthread_mutex_lock(&mut);
256#endif // !_LIBCPP_SINGLE_THREADED
257            flag = 0ul;
258#if !_LIBCPP_SINGLE_THREADED
259            pthread_mutex_unlock(&mut);
260            pthread_cond_broadcast(&cv);
261#endif // !_LIBCPP_SINGLE_THREADED
262            throw;
263        }
264#endif  // _LIBCPP_NO_EXCEPTIONS
265    }
266#if !_LIBCPP_SINGLE_THREADED
267    else
268        pthread_mutex_unlock(&mut);
269#endif // !_LIBCPP_SINGLE_THREADED
270}
271
272_LIBCPP_END_NAMESPACE_STD
273