]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/RWLock.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / common / RWLock.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15
16
17 #ifndef CEPH_RWLock_Posix__H
18 #define CEPH_RWLock_Posix__H
19
20 #include <pthread.h>
21 #include <string>
22 #include "include/ceph_assert.h"
23 #include "acconfig.h"
24 #include "lockdep.h"
25 #include "common/valgrind.h"
26
27 #include <atomic>
28
29 class RWLock final
30 {
31 mutable pthread_rwlock_t L;
32 std::string name;
33 mutable int id;
34 mutable std::atomic<unsigned> nrlock = { 0 }, nwlock = { 0 };
35 bool track, lockdep;
36
37 std::string unique_name(const char* name) const;
38
39 public:
40 RWLock(const RWLock& other) = delete;
41 const RWLock& operator=(const RWLock& other) = delete;
42
43 RWLock(const std::string &n, bool track_lock=true, bool ld=true, bool prioritize_write=false)
44 : name(n), id(-1), track(track_lock),
45 lockdep(ld) {
46 #if defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
47 if (prioritize_write) {
48 pthread_rwlockattr_t attr;
49 pthread_rwlockattr_init(&attr);
50 // PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
51 // Setting the lock kind to this avoids writer starvation as long as
52 // long as any read locking is not done in a recursive fashion.
53 pthread_rwlockattr_setkind_np(&attr,
54 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
55 pthread_rwlock_init(&L, &attr);
56 pthread_rwlockattr_destroy(&attr);
57 } else
58 #endif
59 // Next block is in {} to possibly connect to the above if when code is used.
60 {
61 pthread_rwlock_init(&L, NULL);
62 }
63 ANNOTATE_BENIGN_RACE_SIZED(&id, sizeof(id), "RWLock lockdep id");
64 ANNOTATE_BENIGN_RACE_SIZED(&nrlock, sizeof(nrlock), "RWlock nrlock");
65 ANNOTATE_BENIGN_RACE_SIZED(&nwlock, sizeof(nwlock), "RWlock nwlock");
66 if (lockdep && g_lockdep) id = lockdep_register(name.c_str());
67 }
68
69 bool is_locked() const {
70 ceph_assert(track);
71 return (nrlock > 0) || (nwlock > 0);
72 }
73
74 bool is_wlocked() const {
75 ceph_assert(track);
76 return (nwlock > 0);
77 }
78 ~RWLock() {
79 // The following check is racy but we are about to destroy
80 // the object and we assume that there are no other users.
81 if (track)
82 ceph_assert(!is_locked());
83 pthread_rwlock_destroy(&L);
84 if (lockdep && g_lockdep) {
85 lockdep_unregister(id);
86 }
87 }
88
89 void unlock(bool lockdep=true) const {
90 if (track) {
91 if (nwlock > 0) {
92 nwlock--;
93 } else {
94 ceph_assert(nrlock > 0);
95 nrlock--;
96 }
97 }
98 if (lockdep && this->lockdep && g_lockdep)
99 id = lockdep_will_unlock(name.c_str(), id);
100 int r = pthread_rwlock_unlock(&L);
101 ceph_assert(r == 0);
102 }
103
104 // read
105 void get_read() const {
106 if (lockdep && g_lockdep) id = lockdep_will_lock(name.c_str(), id);
107 int r = pthread_rwlock_rdlock(&L);
108 ceph_assert(r == 0);
109 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
110 if (track)
111 nrlock++;
112 }
113 bool try_get_read() const {
114 if (pthread_rwlock_tryrdlock(&L) == 0) {
115 if (track)
116 nrlock++;
117 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
118 return true;
119 }
120 return false;
121 }
122 void put_read() const {
123 unlock();
124 }
125
126 // write
127 void get_write(bool lockdep=true) {
128 if (lockdep && this->lockdep && g_lockdep)
129 id = lockdep_will_lock(name.c_str(), id);
130 int r = pthread_rwlock_wrlock(&L);
131 ceph_assert(r == 0);
132 if (lockdep && this->lockdep && g_lockdep)
133 id = lockdep_locked(name.c_str(), id);
134 if (track)
135 nwlock++;
136
137 }
138 bool try_get_write(bool lockdep=true) {
139 if (pthread_rwlock_trywrlock(&L) == 0) {
140 if (lockdep && this->lockdep && g_lockdep)
141 id = lockdep_locked(name.c_str(), id);
142 if (track)
143 nwlock++;
144 return true;
145 }
146 return false;
147 }
148 void put_write() {
149 unlock();
150 }
151
152 void get(bool for_write) {
153 if (for_write) {
154 get_write();
155 } else {
156 get_read();
157 }
158 }
159
160 public:
161 class RLocker {
162 const RWLock &m_lock;
163
164 bool locked;
165
166 public:
167 explicit RLocker(const RWLock& lock) : m_lock(lock) {
168 m_lock.get_read();
169 locked = true;
170 }
171 void unlock() {
172 ceph_assert(locked);
173 m_lock.unlock();
174 locked = false;
175 }
176 ~RLocker() {
177 if (locked) {
178 m_lock.unlock();
179 }
180 }
181 };
182
183 class WLocker {
184 RWLock &m_lock;
185
186 bool locked;
187
188 public:
189 explicit WLocker(RWLock& lock) : m_lock(lock) {
190 m_lock.get_write();
191 locked = true;
192 }
193 void unlock() {
194 ceph_assert(locked);
195 m_lock.unlock();
196 locked = false;
197 }
198 ~WLocker() {
199 if (locked) {
200 m_lock.unlock();
201 }
202 }
203 };
204
205 class Context {
206 RWLock& lock;
207
208 public:
209 enum LockState {
210 Untaken = 0,
211 TakenForRead = 1,
212 TakenForWrite = 2,
213 };
214
215 private:
216 LockState state;
217
218 public:
219 explicit Context(RWLock& l) : lock(l), state(Untaken) {}
220 Context(RWLock& l, LockState s) : lock(l), state(s) {}
221
222 void get_write() {
223 ceph_assert(state == Untaken);
224
225 lock.get_write();
226 state = TakenForWrite;
227 }
228
229 void get_read() {
230 ceph_assert(state == Untaken);
231
232 lock.get_read();
233 state = TakenForRead;
234 }
235
236 void unlock() {
237 ceph_assert(state != Untaken);
238 lock.unlock();
239 state = Untaken;
240 }
241
242 void promote() {
243 ceph_assert(state == TakenForRead);
244 unlock();
245 get_write();
246 }
247
248 LockState get_state() { return state; }
249 void set_state(LockState s) {
250 state = s;
251 }
252
253 bool is_locked() {
254 return (state != Untaken);
255 }
256
257 bool is_rlocked() {
258 return (state == TakenForRead);
259 }
260
261 bool is_wlocked() {
262 return (state == TakenForWrite);
263 }
264 };
265 };
266
267 #endif // !CEPH_RWLock_Posix__H