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