1*0b57cec5SDimitry Andric //===---------------------- shared_mutex.cpp ------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "__config"
10*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
11*0b57cec5SDimitry Andric 
12*0b57cec5SDimitry Andric #include "shared_mutex"
13*0b57cec5SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
14*0b57cec5SDimitry Andric #pragma comment(lib, "pthread")
15*0b57cec5SDimitry Andric #endif
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric // Shared Mutex Base
__shared_mutex_base()20*0b57cec5SDimitry Andric __shared_mutex_base::__shared_mutex_base()
21*0b57cec5SDimitry Andric     : __state_(0)
22*0b57cec5SDimitry Andric {
23*0b57cec5SDimitry Andric }
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric // Exclusive ownership
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric void
lock()28*0b57cec5SDimitry Andric __shared_mutex_base::lock()
29*0b57cec5SDimitry Andric {
30*0b57cec5SDimitry Andric     unique_lock<mutex> lk(__mut_);
31*0b57cec5SDimitry Andric     while (__state_ & __write_entered_)
32*0b57cec5SDimitry Andric         __gate1_.wait(lk);
33*0b57cec5SDimitry Andric     __state_ |= __write_entered_;
34*0b57cec5SDimitry Andric     while (__state_ & __n_readers_)
35*0b57cec5SDimitry Andric         __gate2_.wait(lk);
36*0b57cec5SDimitry Andric }
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric bool
try_lock()39*0b57cec5SDimitry Andric __shared_mutex_base::try_lock()
40*0b57cec5SDimitry Andric {
41*0b57cec5SDimitry Andric     unique_lock<mutex> lk(__mut_);
42*0b57cec5SDimitry Andric     if (__state_ == 0)
43*0b57cec5SDimitry Andric     {
44*0b57cec5SDimitry Andric         __state_ = __write_entered_;
45*0b57cec5SDimitry Andric         return true;
46*0b57cec5SDimitry Andric     }
47*0b57cec5SDimitry Andric     return false;
48*0b57cec5SDimitry Andric }
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric void
unlock()51*0b57cec5SDimitry Andric __shared_mutex_base::unlock()
52*0b57cec5SDimitry Andric {
53*0b57cec5SDimitry Andric     lock_guard<mutex> _(__mut_);
54*0b57cec5SDimitry Andric     __state_ = 0;
55*0b57cec5SDimitry Andric     __gate1_.notify_all();
56*0b57cec5SDimitry Andric }
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric // Shared ownership
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric void
lock_shared()61*0b57cec5SDimitry Andric __shared_mutex_base::lock_shared()
62*0b57cec5SDimitry Andric {
63*0b57cec5SDimitry Andric     unique_lock<mutex> lk(__mut_);
64*0b57cec5SDimitry Andric     while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
65*0b57cec5SDimitry Andric         __gate1_.wait(lk);
66*0b57cec5SDimitry Andric     unsigned num_readers = (__state_ & __n_readers_) + 1;
67*0b57cec5SDimitry Andric     __state_ &= ~__n_readers_;
68*0b57cec5SDimitry Andric     __state_ |= num_readers;
69*0b57cec5SDimitry Andric }
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric bool
try_lock_shared()72*0b57cec5SDimitry Andric __shared_mutex_base::try_lock_shared()
73*0b57cec5SDimitry Andric {
74*0b57cec5SDimitry Andric     unique_lock<mutex> lk(__mut_);
75*0b57cec5SDimitry Andric     unsigned num_readers = __state_ & __n_readers_;
76*0b57cec5SDimitry Andric     if (!(__state_ & __write_entered_) && num_readers != __n_readers_)
77*0b57cec5SDimitry Andric     {
78*0b57cec5SDimitry Andric         ++num_readers;
79*0b57cec5SDimitry Andric         __state_ &= ~__n_readers_;
80*0b57cec5SDimitry Andric         __state_ |= num_readers;
81*0b57cec5SDimitry Andric         return true;
82*0b57cec5SDimitry Andric     }
83*0b57cec5SDimitry Andric     return false;
84*0b57cec5SDimitry Andric }
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric void
unlock_shared()87*0b57cec5SDimitry Andric __shared_mutex_base::unlock_shared()
88*0b57cec5SDimitry Andric {
89*0b57cec5SDimitry Andric     lock_guard<mutex> _(__mut_);
90*0b57cec5SDimitry Andric     unsigned num_readers = (__state_ & __n_readers_) - 1;
91*0b57cec5SDimitry Andric     __state_ &= ~__n_readers_;
92*0b57cec5SDimitry Andric     __state_ |= num_readers;
93*0b57cec5SDimitry Andric     if (__state_ & __write_entered_)
94*0b57cec5SDimitry Andric     {
95*0b57cec5SDimitry Andric         if (num_readers == 0)
96*0b57cec5SDimitry Andric             __gate2_.notify_one();
97*0b57cec5SDimitry Andric     }
98*0b57cec5SDimitry Andric     else
99*0b57cec5SDimitry Andric     {
100*0b57cec5SDimitry Andric         if (num_readers == __n_readers_ - 1)
101*0b57cec5SDimitry Andric             __gate1_.notify_one();
102*0b57cec5SDimitry Andric     }
103*0b57cec5SDimitry Andric }
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric 
106*0b57cec5SDimitry Andric // Shared Timed Mutex
107*0b57cec5SDimitry Andric // These routines are here for ABI stability
shared_timed_mutex()108*0b57cec5SDimitry Andric shared_timed_mutex::shared_timed_mutex() : __base() {}
lock()109*0b57cec5SDimitry Andric void shared_timed_mutex::lock()     { return __base.lock(); }
try_lock()110*0b57cec5SDimitry Andric bool shared_timed_mutex::try_lock() { return __base.try_lock(); }
unlock()111*0b57cec5SDimitry Andric void shared_timed_mutex::unlock()   { return __base.unlock(); }
lock_shared()112*0b57cec5SDimitry Andric void shared_timed_mutex::lock_shared() { return __base.lock_shared(); }
try_lock_shared()113*0b57cec5SDimitry Andric bool shared_timed_mutex::try_lock_shared() { return __base.try_lock_shared(); }
unlock_shared()114*0b57cec5SDimitry Andric void shared_timed_mutex::unlock_shared() { return __base.unlock_shared(); }
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS
119