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