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