]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/RWLock.h
update sources to v12.2.3
[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>
22#include <include/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);
56 } else
57#endif
58 // Next block is in {} to possibly connect to the above if when code is used.
59 {
60 pthread_rwlock_init(&L, NULL);
61 }
62 ANNOTATE_BENIGN_RACE_SIZED(&id, sizeof(id), "RWLock lockdep id");
63 ANNOTATE_BENIGN_RACE_SIZED(&nrlock, sizeof(nrlock), "RWlock nrlock");
64 ANNOTATE_BENIGN_RACE_SIZED(&nwlock, sizeof(nwlock), "RWlock nwlock");
65 if (lockdep && g_lockdep) id = lockdep_register(name.c_str());
66 }
67
68 bool is_locked() const {
69 assert(track);
31f18b77 70 return (nrlock > 0) || (nwlock > 0);
7c673cae
FG
71 }
72
73 bool is_wlocked() const {
74 assert(track);
31f18b77 75 return (nwlock > 0);
7c673cae
FG
76 }
77 ~RWLock() {
78 // The following check is racy but we are about to destroy
79 // the object and we assume that there are no other users.
80 if (track)
81 assert(!is_locked());
82 pthread_rwlock_destroy(&L);
83 if (lockdep && g_lockdep) {
84 lockdep_unregister(id);
85 }
86 }
87
88 void unlock(bool lockdep=true) const {
89 if (track) {
31f18b77
FG
90 if (nwlock > 0) {
91 nwlock--;
7c673cae 92 } else {
31f18b77
FG
93 assert(nrlock > 0);
94 nrlock--;
7c673cae
FG
95 }
96 }
97 if (lockdep && this->lockdep && g_lockdep)
98 id = lockdep_will_unlock(name.c_str(), id);
99 int r = pthread_rwlock_unlock(&L);
100 assert(r == 0);
101 }
102
103 // read
104 void get_read() const {
105 if (lockdep && g_lockdep) id = lockdep_will_lock(name.c_str(), id);
106 int r = pthread_rwlock_rdlock(&L);
107 assert(r == 0);
108 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
109 if (track)
31f18b77 110 nrlock++;
7c673cae
FG
111 }
112 bool try_get_read() const {
113 if (pthread_rwlock_tryrdlock(&L) == 0) {
114 if (track)
31f18b77 115 nrlock++;
7c673cae
FG
116 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
117 return true;
118 }
119 return false;
120 }
121 void put_read() const {
122 unlock();
123 }
124
125 // write
126 void get_write(bool lockdep=true) {
127 if (lockdep && this->lockdep && g_lockdep)
128 id = lockdep_will_lock(name.c_str(), id);
129 int r = pthread_rwlock_wrlock(&L);
130 assert(r == 0);
131 if (lockdep && this->lockdep && g_lockdep)
132 id = lockdep_locked(name.c_str(), id);
133 if (track)
31f18b77 134 nwlock++;
7c673cae
FG
135
136 }
137 bool try_get_write(bool lockdep=true) {
138 if (pthread_rwlock_trywrlock(&L) == 0) {
139 if (lockdep && this->lockdep && g_lockdep)
140 id = lockdep_locked(name.c_str(), id);
141 if (track)
31f18b77 142 nwlock++;
7c673cae
FG
143 return true;
144 }
145 return false;
146 }
147 void put_write() {
148 unlock();
149 }
150
151 void get(bool for_write) {
152 if (for_write) {
153 get_write();
154 } else {
155 get_read();
156 }
157 }
158
159public:
160 class RLocker {
161 const RWLock &m_lock;
162
163 bool locked;
164
165 public:
166 explicit RLocker(const RWLock& lock) : m_lock(lock) {
167 m_lock.get_read();
168 locked = true;
169 }
170 void unlock() {
171 assert(locked);
172 m_lock.unlock();
173 locked = false;
174 }
175 ~RLocker() {
176 if (locked) {
177 m_lock.unlock();
178 }
179 }
180 };
181
182 class WLocker {
183 RWLock &m_lock;
184
185 bool locked;
186
187 public:
188 explicit WLocker(RWLock& lock) : m_lock(lock) {
189 m_lock.get_write();
190 locked = true;
191 }
192 void unlock() {
193 assert(locked);
194 m_lock.unlock();
195 locked = false;
196 }
197 ~WLocker() {
198 if (locked) {
199 m_lock.unlock();
200 }
201 }
202 };
203
204 class Context {
205 RWLock& lock;
206
207 public:
208 enum LockState {
209 Untaken = 0,
210 TakenForRead = 1,
211 TakenForWrite = 2,
212 };
213
214 private:
215 LockState state;
216
217 public:
218 explicit Context(RWLock& l) : lock(l), state(Untaken) {}
219 Context(RWLock& l, LockState s) : lock(l), state(s) {}
220
221 void get_write() {
222 assert(state == Untaken);
223
224 lock.get_write();
225 state = TakenForWrite;
226 }
227
228 void get_read() {
229 assert(state == Untaken);
230
231 lock.get_read();
232 state = TakenForRead;
233 }
234
235 void unlock() {
236 assert(state != Untaken);
237 lock.unlock();
238 state = Untaken;
239 }
240
241 void promote() {
242 assert(state == TakenForRead);
243 unlock();
244 get_write();
245 }
246
247 LockState get_state() { return state; }
248 void set_state(LockState s) {
249 state = s;
250 }
251
252 bool is_locked() {
253 return (state != Untaken);
254 }
255
256 bool is_rlocked() {
257 return (state == TakenForRead);
258 }
259
260 bool is_wlocked() {
261 return (state == TakenForWrite);
262 }
263 };
264};
265
266#endif // !CEPH_RWLock_Posix__H