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/ceph_assert.h"
25 #include "common/valgrind.h"
31 mutable pthread_rwlock_t L
;
34 mutable std::atomic
<unsigned> nrlock
= { 0 }, nwlock
= { 0 };
37 std::string
unique_name(const char* name
) const;
40 RWLock(const RWLock
& other
) = delete;
41 const RWLock
& operator=(const RWLock
& other
) = delete;
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
),
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
);
59 // Next block is in {} to possibly connect to the above if when code is used.
61 pthread_rwlock_init(&L
, NULL
);
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());
69 bool is_locked() const {
71 return (nrlock
> 0) || (nwlock
> 0);
74 bool is_wlocked() const {
79 // The following check is racy but we are about to destroy
80 // the object and we assume that there are no other users.
82 ceph_assert(!is_locked());
83 pthread_rwlock_destroy(&L
);
84 if (lockdep
&& g_lockdep
) {
85 lockdep_unregister(id
);
89 void unlock(bool lockdep
=true) const {
94 ceph_assert(nrlock
> 0);
98 if (lockdep
&& this->lockdep
&& g_lockdep
)
99 id
= lockdep_will_unlock(name
.c_str(), id
);
100 int r
= pthread_rwlock_unlock(&L
);
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
);
109 if (lockdep
&& g_lockdep
) id
= lockdep_locked(name
.c_str(), id
);
113 bool try_get_read() const {
114 if (pthread_rwlock_tryrdlock(&L
) == 0) {
117 if (lockdep
&& g_lockdep
) id
= lockdep_locked(name
.c_str(), id
);
122 void put_read() const {
128 void unlock_shared() {
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
);
137 if (lockdep
&& this->lockdep
&& g_lockdep
)
138 id
= lockdep_locked(name
.c_str(), id
);
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
);
159 void get(bool for_write
) {
169 const RWLock
&m_lock
;
174 explicit RLocker(const RWLock
& lock
) : m_lock(lock
) {
196 explicit WLocker(RWLock
& lock
) : m_lock(lock
) {
226 explicit Context(RWLock
& l
) : lock(l
), state(Untaken
) {}
227 Context(RWLock
& l
, LockState s
) : lock(l
), state(s
) {}
230 ceph_assert(state
== Untaken
);
233 state
= TakenForWrite
;
237 ceph_assert(state
== Untaken
);
240 state
= TakenForRead
;
244 ceph_assert(state
!= Untaken
);
250 ceph_assert(state
== TakenForRead
);
255 LockState
get_state() { return state
; }
256 void set_state(LockState s
) {
261 return (state
!= Untaken
);
265 return (state
== TakenForRead
);
269 return (state
== TakenForWrite
);
274 #endif // !CEPH_RWLock_Posix__H