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