]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/shared_mutex_debug.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / common / shared_mutex_debug.cc
1 #include "shared_mutex_debug.h"
2
3 #include <system_error>
4
5 #include "acconfig.h"
6 #include "common/valgrind.h"
7
8 namespace ceph {
9
10 shared_mutex_debug::shared_mutex_debug(std::string group,
11 bool track_lock,
12 bool enable_lock_dep,
13 bool prioritize_write)
14 : mutex_debugging_base{std::move(group),
15 enable_lock_dep,
16 false /* backtrace */},
17 track(track_lock)
18 {
19 #ifdef HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
20 if (prioritize_write) {
21 pthread_rwlockattr_t attr;
22 pthread_rwlockattr_init(&attr);
23 // PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
24 // Setting the lock kind to this avoids writer starvation as long as
25 // long as any read locking is not done in a recursive fashion.
26 pthread_rwlockattr_setkind_np(&attr,
27 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
28 pthread_rwlock_init(&rwlock, &attr);
29 pthread_rwlockattr_destroy(&attr);
30 } else
31 #endif
32 // Next block is in {} to possibly connect to the above if when code is used.
33 {
34 pthread_rwlock_init(&rwlock, NULL);
35 }
36 ANNOTATE_BENIGN_RACE_SIZED(&id, sizeof(id), "shared_mutex_debug lockdep id");
37 ANNOTATE_BENIGN_RACE_SIZED(&nlock, sizeof(nlock), "shared_mutex_debug nwlock");
38 ANNOTATE_BENIGN_RACE_SIZED(&nrlock, sizeof(nrlock), "shared_mutex_debug nrlock");
39 }
40
41 // exclusive
42 void shared_mutex_debug::lock()
43 {
44 if (_enable_lockdep()) {
45 _will_lock();
46 }
47 if (int r = pthread_rwlock_wrlock(&rwlock); r != 0) {
48 throw std::system_error(r, std::generic_category());
49 }
50 if (_enable_lockdep()) {
51 _locked();
52 }
53 _post_lock();
54 }
55
56 bool shared_mutex_debug::try_lock()
57 {
58 int r = pthread_rwlock_trywrlock(&rwlock);
59 switch (r) {
60 case 0:
61 if (_enable_lockdep()) {
62 _locked();
63 }
64 _post_lock();
65 return true;
66 case EBUSY:
67 return false;
68 default:
69 throw std::system_error(r, std::generic_category());
70 }
71 }
72
73 void shared_mutex_debug::unlock()
74 {
75 _pre_unlock();
76 if (_enable_lockdep()) {
77 _will_unlock();
78 }
79 if (int r = pthread_rwlock_unlock(&rwlock); r != 0) {
80 throw std::system_error(r, std::generic_category());
81 }
82 }
83
84 // shared locking
85 void shared_mutex_debug::lock_shared()
86 {
87 if (_enable_lockdep()) {
88 _will_lock();
89 }
90 if (int r = pthread_rwlock_rdlock(&rwlock); r != 0) {
91 throw std::system_error(r, std::generic_category());
92 }
93 if (_enable_lockdep()) {
94 _locked();
95 }
96 _post_lock_shared();
97 }
98
99 bool shared_mutex_debug::try_lock_shared()
100 {
101 if (_enable_lockdep()) {
102 _will_unlock();
103 }
104 switch (int r = pthread_rwlock_rdlock(&rwlock); r) {
105 case 0:
106 if (_enable_lockdep()) {
107 _locked();
108 }
109 _post_lock_shared();
110 return true;
111 case EBUSY:
112 return false;
113 default:
114 throw std::system_error(r, std::generic_category());
115 }
116 }
117
118 void shared_mutex_debug::unlock_shared()
119 {
120 _pre_unlock_shared();
121 if (_enable_lockdep()) {
122 _will_unlock();
123 }
124 if (int r = pthread_rwlock_unlock(&rwlock); r != 0) {
125 throw std::system_error(r, std::generic_category());
126 }
127 }
128
129 // exclusive locking
130 void shared_mutex_debug::_pre_unlock()
131 {
132 if (track) {
133 ceph_assert(nlock > 0);
134 --nlock;
135 ceph_assert(locked_by == std::this_thread::get_id());
136 ceph_assert(nlock == 0);
137 locked_by = std::thread::id();
138 }
139 }
140
141 void shared_mutex_debug::_post_lock()
142 {
143 if (track) {
144 ceph_assert(nlock == 0);
145 locked_by = std::this_thread::get_id();
146 ++nlock;
147 }
148 }
149
150 // shared locking
151 void shared_mutex_debug::_pre_unlock_shared()
152 {
153 if (track) {
154 ceph_assert(nrlock > 0);
155 nrlock--;
156 }
157 }
158
159 void shared_mutex_debug::_post_lock_shared()
160 {
161 if (track) {
162 ++nrlock;
163 }
164 }
165
166 } // namespace ceph