/Users/deen/code/yugabyte-db/src/yb/util/rw_mutex.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #include "yb/util/rw_mutex.h" |
34 | | |
35 | | #include <mutex> |
36 | | |
37 | | #include <glog/logging.h> |
38 | | |
39 | | #include "yb/gutil/map-util.h" |
40 | | #include "yb/util/env.h" |
41 | | |
42 | | using std::lock_guard; |
43 | | |
44 | | namespace { |
45 | | |
46 | 26.5M | void unlock_rwlock(pthread_rwlock_t* rwlock) { |
47 | 26.5M | int rv = pthread_rwlock_unlock(rwlock); |
48 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
49 | 26.5M | } |
50 | | |
51 | | } // anonymous namespace |
52 | | |
53 | | namespace yb { |
54 | | |
55 | | RWMutex::RWMutex() |
56 | | #ifndef NDEBUG |
57 | | : writer_tid_(0) |
58 | | #endif |
59 | 10.8k | { |
60 | 10.8k | Init(Priority::PREFER_READING); |
61 | 10.8k | } |
62 | | |
63 | | RWMutex::RWMutex(Priority prio) |
64 | | #ifndef NDEBUG |
65 | | : writer_tid_(0) |
66 | | #endif |
67 | 5.46k | { |
68 | 5.46k | Init(prio); |
69 | 5.46k | } |
70 | | |
71 | 16.2k | void RWMutex::Init(Priority prio) { |
72 | | #ifdef __linux__ |
73 | | // Adapt from priority to the pthread type. |
74 | | int kind = PTHREAD_RWLOCK_PREFER_READER_NP; |
75 | | switch (prio) { |
76 | | case Priority::PREFER_READING: |
77 | | kind = PTHREAD_RWLOCK_PREFER_READER_NP; |
78 | | break; |
79 | | case Priority::PREFER_WRITING: |
80 | | kind = PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP; |
81 | | break; |
82 | | } |
83 | | |
84 | | // Initialize the new rwlock with the user's preference. |
85 | | pthread_rwlockattr_t attr; |
86 | | int rv = pthread_rwlockattr_init(&attr); |
87 | | DCHECK_EQ(0, rv) << strerror(rv); |
88 | | rv = pthread_rwlockattr_setkind_np(&attr, kind); |
89 | | DCHECK_EQ(0, rv) << strerror(rv); |
90 | | rv = pthread_rwlock_init(&native_handle_, &attr); |
91 | | DCHECK_EQ(0, rv) << strerror(rv); |
92 | | rv = pthread_rwlockattr_destroy(&attr); |
93 | | DCHECK_EQ(0, rv) << strerror(rv); |
94 | | #else |
95 | 16.2k | int rv = pthread_rwlock_init(&native_handle_, NULL); |
96 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
97 | 16.2k | #endif |
98 | 16.2k | } |
99 | | |
100 | 3.87k | RWMutex::~RWMutex() { |
101 | 3.87k | int rv = pthread_rwlock_destroy(&native_handle_); |
102 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
103 | 3.87k | } |
104 | | |
105 | 18.3M | void RWMutex::ReadLock() { |
106 | 18.3M | CheckLockState(LockState::NEITHER); |
107 | 18.3M | int rv = pthread_rwlock_rdlock(&native_handle_); |
108 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
109 | 18.3M | MarkForReading(); |
110 | 18.3M | } |
111 | | |
112 | 24.6M | void RWMutex::ReadUnlock() { |
113 | 24.6M | CheckLockState(LockState::READER); |
114 | 24.6M | UnmarkForReading(); |
115 | 24.6M | unlock_rwlock(&native_handle_); |
116 | 24.6M | } |
117 | | |
118 | 14.9M | bool RWMutex::TryReadLock() { |
119 | 14.9M | CheckLockState(LockState::NEITHER); |
120 | 14.9M | int rv = pthread_rwlock_tryrdlock(&native_handle_); |
121 | 14.9M | if (rv == EBUSY) { |
122 | 8.57M | return false; |
123 | 8.57M | } |
124 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
125 | 6.32M | MarkForReading(); |
126 | 6.32M | return true; |
127 | 6.32M | } |
128 | | |
129 | 1.87M | void RWMutex::WriteLock() { |
130 | 1.87M | CheckLockState(LockState::NEITHER); |
131 | 1.87M | int rv = pthread_rwlock_wrlock(&native_handle_); |
132 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
133 | 1.87M | MarkForWriting(); |
134 | 1.87M | } |
135 | | |
136 | 1.88M | void RWMutex::WriteUnlock() { |
137 | 1.88M | CheckLockState(LockState::WRITER); |
138 | 1.88M | UnmarkForWriting(); |
139 | 1.88M | unlock_rwlock(&native_handle_); |
140 | 1.88M | } |
141 | | |
142 | 7.65M | bool RWMutex::TryWriteLock() { |
143 | 7.65M | CheckLockState(LockState::NEITHER); |
144 | 7.65M | int rv = pthread_rwlock_trywrlock(&native_handle_); |
145 | 7.65M | if (rv == EBUSY) { |
146 | 7.65M | return false; |
147 | 7.65M | } |
148 | 0 | DCHECK_EQ(0, rv) << strerror(rv); |
149 | 4.05k | MarkForWriting(); |
150 | 4.05k | return true; |
151 | 4.05k | } |
152 | | |
153 | | #ifndef NDEBUG |
154 | | |
155 | 5 | void RWMutex::AssertAcquiredForReading() const { |
156 | 5 | lock_guard<simple_spinlock> l(tid_lock_); |
157 | 5 | CHECK(ContainsKey(reader_tids_, Env::Default()->gettid())); |
158 | 5 | } |
159 | | |
160 | 0 | void RWMutex::AssertAcquiredForWriting() const { |
161 | 0 | lock_guard<simple_spinlock> l(tid_lock_); |
162 | 0 | CHECK_EQ(Env::Default()->gettid(), writer_tid_); |
163 | 0 | } |
164 | | |
165 | 69.3M | void RWMutex::CheckLockState(LockState state) const { |
166 | 69.3M | auto my_tid = Env::Default()->gettid(); |
167 | 69.3M | bool is_reader; |
168 | 69.3M | bool is_writer; |
169 | 69.3M | { |
170 | 69.3M | lock_guard<simple_spinlock> l(tid_lock_); |
171 | 69.3M | is_reader = ContainsKey(reader_tids_, my_tid); |
172 | 69.3M | is_writer = writer_tid_ == my_tid; |
173 | 69.3M | } |
174 | | |
175 | 69.3M | switch (state) { |
176 | 42.8M | case LockState::NEITHER: |
177 | 3 | CHECK(!is_reader) << "Invalid state, already holding lock for reading"; |
178 | 80 | CHECK(!is_writer) << "Invalid state, already holding lock for writing"; |
179 | 42.8M | break; |
180 | 24.6M | case LockState::READER: |
181 | 7 | CHECK(!is_writer) << "Invalid state, already holding lock for writing"; |
182 | 52 | CHECK(is_reader) << "Invalid state, wasn't holding lock for reading"; |
183 | 24.6M | break; |
184 | 1.88M | case LockState::WRITER: |
185 | 4 | CHECK(!is_reader) << "Invalid state, already holding lock for reading"; |
186 | 6 | CHECK(is_writer) << "Invalid state, wasn't holding lock for writing"; |
187 | 1.88M | break; |
188 | 69.3M | } |
189 | 69.3M | } |
190 | | |
191 | 24.6M | void RWMutex::MarkForReading() { |
192 | 24.6M | lock_guard<simple_spinlock> l(tid_lock_); |
193 | 24.6M | reader_tids_.insert(Env::Default()->gettid()); |
194 | 24.6M | } |
195 | | |
196 | 1.88M | void RWMutex::MarkForWriting() { |
197 | 1.88M | lock_guard<simple_spinlock> l(tid_lock_); |
198 | 1.88M | writer_tid_ = Env::Default()->gettid(); |
199 | 1.88M | } |
200 | | |
201 | 24.6M | void RWMutex::UnmarkForReading() { |
202 | 24.6M | lock_guard<simple_spinlock> l(tid_lock_); |
203 | 24.6M | reader_tids_.erase(Env::Default()->gettid()); |
204 | 24.6M | } |
205 | | |
206 | 1.88M | void RWMutex::UnmarkForWriting() { |
207 | 1.88M | lock_guard<simple_spinlock> l(tid_lock_); |
208 | 1.88M | writer_tid_ = 0; |
209 | 1.88M | } |
210 | | |
211 | | #endif |
212 | | |
213 | | } // namespace yb |