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 <mutex>
14 #  include <shared_mutex>
15 #  if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
16 #    pragma comment(lib, "pthread")
17 #  endif
18 
19 _LIBCPP_BEGIN_NAMESPACE_STD
20 
21 // Shared Mutex Base
22 __shared_mutex_base::__shared_mutex_base() : __state_(0) {}
23 
24 // Exclusive ownership
25 
26 void __shared_mutex_base::lock() {
27   unique_lock<mutex> lk(__mut_);
28   while (__state_ & __write_entered_)
29     __gate1_.wait(lk);
30   __state_ |= __write_entered_;
31   while (__state_ & __n_readers_)
32     __gate2_.wait(lk);
33 }
34 
35 bool __shared_mutex_base::try_lock() {
36   unique_lock<mutex> lk(__mut_);
37   if (__state_ == 0) {
38     __state_ = __write_entered_;
39     return true;
40   }
41   return false;
42 }
43 
44 void __shared_mutex_base::unlock() {
45   lock_guard<mutex> _(__mut_);
46   __state_ = 0;
47   __gate1_.notify_all();
48 }
49 
50 // Shared ownership
51 
52 void __shared_mutex_base::lock_shared() {
53   unique_lock<mutex> lk(__mut_);
54   while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
55     __gate1_.wait(lk);
56   unsigned num_readers = (__state_ & __n_readers_) + 1;
57   __state_ &= ~__n_readers_;
58   __state_ |= num_readers;
59 }
60 
61 bool __shared_mutex_base::try_lock_shared() {
62   unique_lock<mutex> lk(__mut_);
63   unsigned num_readers = __state_ & __n_readers_;
64   if (!(__state_ & __write_entered_) && num_readers != __n_readers_) {
65     ++num_readers;
66     __state_ &= ~__n_readers_;
67     __state_ |= num_readers;
68     return true;
69   }
70   return false;
71 }
72 
73 void __shared_mutex_base::unlock_shared() {
74   lock_guard<mutex> _(__mut_);
75   unsigned num_readers = (__state_ & __n_readers_) - 1;
76   __state_ &= ~__n_readers_;
77   __state_ |= num_readers;
78   if (__state_ & __write_entered_) {
79     if (num_readers == 0)
80       __gate2_.notify_one();
81   } else {
82     if (num_readers == __n_readers_ - 1)
83       __gate1_.notify_one();
84   }
85 }
86 
87 // Shared Timed Mutex
88 // These routines are here for ABI stability
89 shared_timed_mutex::shared_timed_mutex() : __base_() {}
90 void shared_timed_mutex::lock() { return __base_.lock(); }
91 bool shared_timed_mutex::try_lock() { return __base_.try_lock(); }
92 void shared_timed_mutex::unlock() { return __base_.unlock(); }
93 void shared_timed_mutex::lock_shared() { return __base_.lock_shared(); }
94 bool shared_timed_mutex::try_lock_shared() { return __base_.try_lock_shared(); }
95 void shared_timed_mutex::unlock_shared() { return __base_.unlock_shared(); }
96 
97 _LIBCPP_END_NAMESPACE_STD
98 
99 #endif // !_LIBCPP_HAS_NO_THREADS
100