]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/RWLock.h
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / common / RWLock.h
CommitLineData
7c673cae
FG
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>
11fdf7f2 22#include "include/ceph_assert.h"
b32b8144 23#include "acconfig.h"
7c673cae 24#include "lockdep.h"
7c673cae
FG
25#include "common/valgrind.h"
26
31f18b77
FG
27#include <atomic>
28
7c673cae
FG
29class RWLock final
30{
31 mutable pthread_rwlock_t L;
32 std::string name;
33 mutable int id;
31f18b77 34 mutable std::atomic<unsigned> nrlock = { 0 }, nwlock = { 0 };
7c673cae
FG
35 bool track, lockdep;
36
37 std::string unique_name(const char* name) const;
38
39public:
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)
31f18b77 44 : name(n), id(-1), track(track_lock),
7c673cae 45 lockdep(ld) {
b32b8144 46#if defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
7c673cae
FG
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);
11fdf7f2 56 pthread_rwlockattr_destroy(&attr);
7c673cae
FG
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 {
11fdf7f2 70 ceph_assert(track);
31f18b77 71 return (nrlock > 0) || (nwlock > 0);
7c673cae
FG
72 }
73
74 bool is_wlocked() const {
11fdf7f2 75 ceph_assert(track);
31f18b77 76 return (nwlock > 0);
7c673cae
FG
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)
11fdf7f2 82 ceph_assert(!is_locked());
7c673cae
FG
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) {
31f18b77
FG
91 if (nwlock > 0) {
92 nwlock--;
7c673cae 93 } else {
11fdf7f2 94 ceph_assert(nrlock > 0);
31f18b77 95 nrlock--;
7c673cae
FG
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);
11fdf7f2 101 ceph_assert(r == 0);
7c673cae
FG
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);
11fdf7f2 108 ceph_assert(r == 0);
7c673cae
FG
109 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
110 if (track)
31f18b77 111 nrlock++;
7c673cae
FG
112 }
113 bool try_get_read() const {
114 if (pthread_rwlock_tryrdlock(&L) == 0) {
115 if (track)
31f18b77 116 nrlock++;
7c673cae
FG
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 }
9f95a23c
TL
125 void lock_shared() {
126 get_read();
127 }
128 void unlock_shared() {
129 put_read();
130 }
7c673cae
FG
131 // write
132 void get_write(bool lockdep=true) {
133 if (lockdep && this->lockdep && g_lockdep)
134 id = lockdep_will_lock(name.c_str(), id);
135 int r = pthread_rwlock_wrlock(&L);
11fdf7f2 136 ceph_assert(r == 0);
7c673cae
FG
137 if (lockdep && this->lockdep && g_lockdep)
138 id = lockdep_locked(name.c_str(), id);
139 if (track)
31f18b77 140 nwlock++;
7c673cae
FG
141
142 }
143 bool try_get_write(bool lockdep=true) {
144 if (pthread_rwlock_trywrlock(&L) == 0) {
145 if (lockdep && this->lockdep && g_lockdep)
146 id = lockdep_locked(name.c_str(), id);
147 if (track)
31f18b77 148 nwlock++;
7c673cae
FG
149 return true;
150 }
151 return false;
152 }
153 void put_write() {
154 unlock();
155 }
9f95a23c
TL
156 void lock() {
157 get_write();
158 }
7c673cae
FG
159 void get(bool for_write) {
160 if (for_write) {
161 get_write();
162 } else {
163 get_read();
164 }
165 }
166
167public:
168 class RLocker {
169 const RWLock &m_lock;
170
171 bool locked;
172
173 public:
174 explicit RLocker(const RWLock& lock) : m_lock(lock) {
175 m_lock.get_read();
176 locked = true;
177 }
178 void unlock() {
11fdf7f2 179 ceph_assert(locked);
7c673cae
FG
180 m_lock.unlock();
181 locked = false;
182 }
183 ~RLocker() {
184 if (locked) {
185 m_lock.unlock();
186 }
187 }
188 };
189
190 class WLocker {
191 RWLock &m_lock;
192
193 bool locked;
194
195 public:
196 explicit WLocker(RWLock& lock) : m_lock(lock) {
197 m_lock.get_write();
198 locked = true;
199 }
200 void unlock() {
11fdf7f2 201 ceph_assert(locked);
7c673cae
FG
202 m_lock.unlock();
203 locked = false;
204 }
205 ~WLocker() {
206 if (locked) {
207 m_lock.unlock();
208 }
209 }
210 };
211
212 class Context {
213 RWLock& lock;
214
215 public:
216 enum LockState {
217 Untaken = 0,
218 TakenForRead = 1,
219 TakenForWrite = 2,
220 };
221
222 private:
223 LockState state;
224
225 public:
226 explicit Context(RWLock& l) : lock(l), state(Untaken) {}
227 Context(RWLock& l, LockState s) : lock(l), state(s) {}
228
229 void get_write() {
11fdf7f2 230 ceph_assert(state == Untaken);
7c673cae
FG
231
232 lock.get_write();
233 state = TakenForWrite;
234 }
235
236 void get_read() {
11fdf7f2 237 ceph_assert(state == Untaken);
7c673cae
FG
238
239 lock.get_read();
240 state = TakenForRead;
241 }
242
243 void unlock() {
11fdf7f2 244 ceph_assert(state != Untaken);
7c673cae
FG
245 lock.unlock();
246 state = Untaken;
247 }
248
249 void promote() {
11fdf7f2 250 ceph_assert(state == TakenForRead);
7c673cae
FG
251 unlock();
252 get_write();
253 }
254
255 LockState get_state() { return state; }
256 void set_state(LockState s) {
257 state = s;
258 }
259
260 bool is_locked() {
261 return (state != Untaken);
262 }
263
264 bool is_rlocked() {
265 return (state == TakenForRead);
266 }
267
268 bool is_wlocked() {
269 return (state == TakenForWrite);
270 }
271 };
272};
273
274#endif // !CEPH_RWLock_Posix__H