1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
17 #ifndef CEPH_RWLock_Posix__H
18 #define CEPH_RWLock_Posix__H
22 #include <include/assert.h>
24 #include "common/valgrind.h"
30 mutable pthread_rwlock_t L;
33 mutable std::atomic<unsigned> nrlock = { 0 }, nwlock = { 0 };
36 std::string unique_name(const char* name) const;
39 RWLock(const RWLock& other) = delete;
40 const RWLock& operator=(const RWLock& other) = delete;
42 RWLock(const std::string &n, bool track_lock=true, bool ld=true, bool prioritize_write=false)
43 : name(n), id(-1), track(track_lock),
45 #if defined(PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
46 if (prioritize_write) {
47 pthread_rwlockattr_t attr;
48 pthread_rwlockattr_init(&attr);
49 // PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
50 // Setting the lock kind to this avoids writer starvation as long as
51 // long as any read locking is not done in a recursive fashion.
52 pthread_rwlockattr_setkind_np(&attr,
53 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
54 pthread_rwlock_init(&L, &attr);
57 // Next block is in {} to possibly connect to the above if when code is used.
59 pthread_rwlock_init(&L, NULL);
61 ANNOTATE_BENIGN_RACE_SIZED(&id, sizeof(id), "RWLock lockdep id");
62 ANNOTATE_BENIGN_RACE_SIZED(&nrlock, sizeof(nrlock), "RWlock nrlock");
63 ANNOTATE_BENIGN_RACE_SIZED(&nwlock, sizeof(nwlock), "RWlock nwlock");
64 if (lockdep && g_lockdep) id = lockdep_register(name.c_str());
67 bool is_locked() const {
69 return (nrlock > 0) || (nwlock > 0);
72 bool is_wlocked() const {
77 // The following check is racy but we are about to destroy
78 // the object and we assume that there are no other users.
81 pthread_rwlock_destroy(&L);
82 if (lockdep && g_lockdep) {
83 lockdep_unregister(id);
87 void unlock(bool lockdep=true) const {
96 if (lockdep && this->lockdep && g_lockdep)
97 id = lockdep_will_unlock(name.c_str(), id);
98 int r = pthread_rwlock_unlock(&L);
103 void get_read() const {
104 if (lockdep && g_lockdep) id = lockdep_will_lock(name.c_str(), id);
105 int r = pthread_rwlock_rdlock(&L);
107 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
111 bool try_get_read() const {
112 if (pthread_rwlock_tryrdlock(&L) == 0) {
115 if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
120 void put_read() const {
125 void get_write(bool lockdep=true) {
126 if (lockdep && this->lockdep && g_lockdep)
127 id = lockdep_will_lock(name.c_str(), id);
128 int r = pthread_rwlock_wrlock(&L);
130 if (lockdep && this->lockdep && g_lockdep)
131 id = lockdep_locked(name.c_str(), id);
136 bool try_get_write(bool lockdep=true) {
137 if (pthread_rwlock_trywrlock(&L) == 0) {
138 if (lockdep && this->lockdep && g_lockdep)
139 id = lockdep_locked(name.c_str(), id);
150 void get(bool for_write) {
160 const RWLock &m_lock;
165 explicit RLocker(const RWLock& lock) : m_lock(lock) {
187 explicit WLocker(RWLock& lock) : m_lock(lock) {
217 explicit Context(RWLock& l) : lock(l), state(Untaken) {}
218 Context(RWLock& l, LockState s) : lock(l), state(s) {}
221 assert(state == Untaken);
224 state = TakenForWrite;
228 assert(state == Untaken);
231 state = TakenForRead;
235 assert(state != Untaken);
241 assert(state == TakenForRead);
246 LockState get_state() { return state; }
247 void set_state(LockState s) {
252 return (state != Untaken);
256 return (state == TakenForRead);
260 return (state == TakenForWrite);
265 #endif // !CEPH_RWLock_Posix__H