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