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   	{
(1) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
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) {
(1) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
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
167