mutex.cpp revision 285830
1189251Ssam//===------------------------- mutex.cpp ----------------------------------===//
2189251Ssam//
3189251Ssam//                     The LLVM Compiler Infrastructure
4189251Ssam//
5189251Ssam// This file is dual licensed under the MIT and the University of Illinois Open
6189251Ssam// Source Licenses. See LICENSE.TXT for details.
7189251Ssam//
8189251Ssam//===----------------------------------------------------------------------===//
9189251Ssam
10189251Ssam#define _LIBCPP_BUILDING_MUTEX
11189251Ssam#include "mutex"
12189251Ssam#include "limits"
13189251Ssam#include "system_error"
14189251Ssam#include "cassert"
15189251Ssam
16189251Ssam_LIBCPP_BEGIN_NAMESPACE_STD
17189251Ssam#ifndef _LIBCPP_HAS_NO_THREADS
18189251Ssam
19189251Ssamconst defer_lock_t  defer_lock = {};
20189251Ssamconst try_to_lock_t try_to_lock = {};
21189251Ssamconst adopt_lock_t  adopt_lock = {};
22189251Ssam
23189251Ssammutex::~mutex()
24189251Ssam{
25189251Ssam    pthread_mutex_destroy(&__m_);
26189251Ssam}
27189251Ssam
28189251Ssamvoid
29189251Ssammutex::lock()
30189251Ssam{
31189251Ssam    int ec = pthread_mutex_lock(&__m_);
32189251Ssam    if (ec)
33189251Ssam        __throw_system_error(ec, "mutex lock failed");
34189251Ssam}
35189251Ssam
36189251Ssambool
37189251Ssammutex::try_lock() _NOEXCEPT
38189251Ssam{
39189251Ssam    return pthread_mutex_trylock(&__m_) == 0;
40189251Ssam}
41189251Ssam
42189251Ssamvoid
43189251Ssammutex::unlock() _NOEXCEPT
44189251Ssam{
45189251Ssam    int ec = pthread_mutex_unlock(&__m_);
46189251Ssam    (void)ec;
47189251Ssam    assert(ec == 0);
48189251Ssam}
49189251Ssam
50189251Ssam// recursive_mutex
51189251Ssam
52189251Ssamrecursive_mutex::recursive_mutex()
53189251Ssam{
54189251Ssam    pthread_mutexattr_t attr;
55189251Ssam    int ec = pthread_mutexattr_init(&attr);
56189251Ssam    if (ec)
57189251Ssam        goto fail;
58189251Ssam    ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
59189251Ssam    if (ec)
60189251Ssam    {
61189251Ssam        pthread_mutexattr_destroy(&attr);
62189251Ssam        goto fail;
63189251Ssam    }
64189251Ssam    ec = pthread_mutex_init(&__m_, &attr);
65189251Ssam    if (ec)
66189251Ssam    {
67189251Ssam        pthread_mutexattr_destroy(&attr);
68189251Ssam        goto fail;
69189251Ssam    }
70189251Ssam    ec = pthread_mutexattr_destroy(&attr);
71189251Ssam    if (ec)
72189251Ssam    {
73189251Ssam        pthread_mutex_destroy(&__m_);
74189251Ssam        goto fail;
75189251Ssam    }
76189251Ssam    return;
77189251Ssamfail:
78189251Ssam    __throw_system_error(ec, "recursive_mutex constructor failed");
79189251Ssam}
80189251Ssam
81189251Ssamrecursive_mutex::~recursive_mutex()
82189251Ssam{
83189251Ssam    int e = pthread_mutex_destroy(&__m_);
84189251Ssam    (void)e;
85189251Ssam    assert(e == 0);
86189251Ssam}
87189251Ssam
88189251Ssamvoid
89189251Ssamrecursive_mutex::lock()
90189251Ssam{
91189251Ssam    int ec = pthread_mutex_lock(&__m_);
92189251Ssam    if (ec)
93189251Ssam        __throw_system_error(ec, "recursive_mutex lock failed");
94189251Ssam}
95189251Ssam
96189251Ssamvoid
97189251Ssamrecursive_mutex::unlock() _NOEXCEPT
98189251Ssam{
99189251Ssam    int e = pthread_mutex_unlock(&__m_);
100189251Ssam    (void)e;
101189251Ssam    assert(e == 0);
102189251Ssam}
103189251Ssam
104189251Ssambool
105189251Ssamrecursive_mutex::try_lock() _NOEXCEPT
106189251Ssam{
107189251Ssam    return pthread_mutex_trylock(&__m_) == 0;
108189251Ssam}
109189251Ssam
110189251Ssam// timed_mutex
111189251Ssam
112189251Ssamtimed_mutex::timed_mutex()
113189251Ssam    : __locked_(false)
114189251Ssam{
115189251Ssam}
116189251Ssam
117189251Ssamtimed_mutex::~timed_mutex()
118189251Ssam{
119189251Ssam    lock_guard<mutex> _(__m_);
120189251Ssam}
121189251Ssam
122189251Ssamvoid
123189251Ssamtimed_mutex::lock()
124189251Ssam{
125189251Ssam    unique_lock<mutex> lk(__m_);
126189251Ssam    while (__locked_)
127189251Ssam        __cv_.wait(lk);
128189251Ssam    __locked_ = true;
129189251Ssam}
130189251Ssam
131189251Ssambool
132189251Ssamtimed_mutex::try_lock() _NOEXCEPT
133189251Ssam{
134189251Ssam    unique_lock<mutex> lk(__m_, try_to_lock);
135189251Ssam    if (lk.owns_lock() && !__locked_)
136189251Ssam    {
137189251Ssam        __locked_ = true;
138189251Ssam        return true;
139189251Ssam    }
140189251Ssam    return false;
141189251Ssam}
142189251Ssam
143189251Ssamvoid
144189251Ssamtimed_mutex::unlock() _NOEXCEPT
145189251Ssam{
146189251Ssam    lock_guard<mutex> _(__m_);
147189251Ssam    __locked_ = false;
148189251Ssam    __cv_.notify_one();
149189251Ssam}
150189251Ssam
151189251Ssam// recursive_timed_mutex
152189251Ssam
153189251Ssamrecursive_timed_mutex::recursive_timed_mutex()
154189251Ssam    : __count_(0),
155189251Ssam      __id_(0)
156189251Ssam{
157189251Ssam}
158189251Ssam
159189251Ssamrecursive_timed_mutex::~recursive_timed_mutex()
160189251Ssam{
161189251Ssam    lock_guard<mutex> _(__m_);
162189251Ssam}
163189251Ssam
164189251Ssamvoid
165189251Ssamrecursive_timed_mutex::lock()
166189251Ssam{
167189251Ssam    pthread_t id = pthread_self();
168189251Ssam    unique_lock<mutex> lk(__m_);
169189251Ssam    if (pthread_equal(id, __id_))
170189251Ssam    {
171189251Ssam        if (__count_ == numeric_limits<size_t>::max())
172189251Ssam            __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
173189251Ssam        ++__count_;
174189251Ssam        return;
175189251Ssam    }
176189251Ssam    while (__count_ != 0)
177189251Ssam        __cv_.wait(lk);
178189251Ssam    __count_ = 1;
179189251Ssam    __id_ = id;
180189251Ssam}
181189251Ssam
182189251Ssambool
183189251Ssamrecursive_timed_mutex::try_lock() _NOEXCEPT
184189251Ssam{
185189251Ssam    pthread_t id = pthread_self();
186189251Ssam    unique_lock<mutex> lk(__m_, try_to_lock);
187189251Ssam    if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_)))
188189251Ssam    {
189189251Ssam        if (__count_ == numeric_limits<size_t>::max())
190189251Ssam            return false;
191189251Ssam        ++__count_;
192189251Ssam        __id_ = id;
193189251Ssam        return true;
194189251Ssam    }
195189251Ssam    return false;
196189251Ssam}
197189251Ssam
198189251Ssamvoid
199189251Ssamrecursive_timed_mutex::unlock() _NOEXCEPT
200189251Ssam{
201189251Ssam    unique_lock<mutex> lk(__m_);
202189251Ssam    if (--__count_ == 0)
203189251Ssam    {
204189251Ssam        __id_ = 0;
205189251Ssam        lk.unlock();
206189251Ssam        __cv_.notify_one();
207189251Ssam    }
208189251Ssam}
209189251Ssam
210189251Ssam#endif // !_LIBCPP_HAS_NO_THREADS
211189251Ssam
212189251Ssam// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
213189251Ssam// without illegal macros (unexpected macros not beginning with _UpperCase or
214189251Ssam// __lowercase), and if it stops spinning waiting threads, then call_once should
215189251Ssam// call into dispatch_once_f instead of here. Relevant radar this code needs to
216189251Ssam// keep in sync with:  7741191.
217189251Ssam
218189251Ssam#ifndef _LIBCPP_HAS_NO_THREADS
219189251Ssamstatic pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
220189251Ssamstatic pthread_cond_t  cv  = PTHREAD_COND_INITIALIZER;
221189251Ssam#endif
222189251Ssam
223189251Ssamvoid
224189251Ssam__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
225189251Ssam{
226189251Ssam#if defined(_LIBCPP_HAS_NO_THREADS)
227189251Ssam    if (flag == 0)
228189251Ssam    {
229189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS
230189251Ssam        try
231189251Ssam        {
232189251Ssam#endif  // _LIBCPP_NO_EXCEPTIONS
233189251Ssam            flag = 1;
234189251Ssam            func(arg);
235189251Ssam            flag = ~0ul;
236189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS
237189251Ssam        }
238189251Ssam        catch (...)
239189251Ssam        {
240189251Ssam            flag = 0ul;
241189251Ssam            throw;
242189251Ssam        }
243189251Ssam#endif  // _LIBCPP_NO_EXCEPTIONS
244189251Ssam    }
245189251Ssam#else // !_LIBCPP_HAS_NO_THREADS
246189251Ssam    pthread_mutex_lock(&mut);
247189251Ssam    while (flag == 1)
248189251Ssam        pthread_cond_wait(&cv, &mut);
249189251Ssam    if (flag == 0)
250189251Ssam    {
251189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS
252189251Ssam        try
253189251Ssam        {
254189251Ssam#endif  // _LIBCPP_NO_EXCEPTIONS
255189251Ssam            flag = 1;
256189251Ssam            pthread_mutex_unlock(&mut);
257189251Ssam            func(arg);
258189251Ssam            pthread_mutex_lock(&mut);
259189251Ssam            flag = ~0ul;
260189251Ssam            pthread_mutex_unlock(&mut);
261189251Ssam            pthread_cond_broadcast(&cv);
262189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS
263189251Ssam        }
264189251Ssam        catch (...)
265189251Ssam        {
266189251Ssam            pthread_mutex_lock(&mut);
267189251Ssam            flag = 0ul;
268189251Ssam            pthread_mutex_unlock(&mut);
269189251Ssam            pthread_cond_broadcast(&cv);
270189251Ssam            throw;
271189251Ssam        }
272189251Ssam#endif  // _LIBCPP_NO_EXCEPTIONS
273189251Ssam    }
274189251Ssam    else
275189251Ssam        pthread_mutex_unlock(&mut);
276189251Ssam#endif // !_LIBCPP_HAS_NO_THREADS
277189251Ssam
278189251Ssam}
279189251Ssam
280189251Ssam_LIBCPP_END_NAMESPACE_STD
281189251Ssam