Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / common / mutex_debug.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7  *
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.
12  *
13  */
14
15 #ifndef CEPH_COMMON_MUTEX_DEBUG_H
16 #define CEPH_COMMON_MUTEX_DEBUG_H
17
18 #include <system_error>
19 #include <thread>
20
21 #include <pthread.h>
22
23 #include "include/assert.h"
24
25 #include "ceph_time.h"
26 #include "likely.h"
27 #include "lockdep.h"
28
29 class CephContext;
30 class PerfCounters;
31
32 namespace ceph {
33 namespace mutex_debug_detail {
34 class mutex_debugging_base {
35 protected:
36   std::string name;
37   int id;
38   bool backtrace; // gather backtrace on lock acquisition
39
40   int nlock;
41   std::thread::id locked_by;
42   CephContext *cct;
43   PerfCounters *logger;
44
45   void _register();
46   void _will_lock(); // about to lock
47   void _locked(); // just locked
48     void _will_unlock(); // about to unlock
49
50   mutex_debugging_base(const std::string &n = std::string(), bool bt = false,
51                        CephContext *cct = nullptr);
52   ~mutex_debugging_base();
53
54   ceph::mono_time before_lock_blocks();
55   void after_lock_blocks(ceph::mono_time start,
56                          bool no_lockdep);
57
58 public:
59   bool is_locked() const {
60     return (nlock > 0);
61   }
62   bool is_locked_by_me() const {
63     return nlock > 0 && locked_by == std::this_thread::get_id();
64   }
65   operator bool() const {
66     return nlock > 0 && locked_by == std::this_thread::get_id();
67   }
68 };
69
70 template<typename Mutex>
71 class mutex_debugging : public mutex_debugging_base {
72   Mutex* impl;
73
74 public:
75   mutex_debugging(const std::string &n = std::string(), bool bt = false,
76                   CephContext *cct = nullptr) :
77     mutex_debugging_base(n, bt, cct), impl(static_cast<Mutex*>(this)) {}
78
79   ~mutex_debugging() = default;
80
81   void _post_lock() {
82     if (!impl->recursive)
83       assert(nlock == 0);
84     locked_by = std::this_thread::get_id();
85     nlock++;
86   }
87
88   void _pre_unlock() {
89     assert(nlock > 0);
90     --nlock;
91     assert(locked_by == std::this_thread::get_id());
92     if (!impl->recursive)
93       assert(nlock == 0);
94     if (nlock == 0)
95       locked_by = std::thread::id();
96   }
97
98   bool try_lock(bool no_lockdep = false) {
99     bool locked = impl->try_lock_impl();
100     if (locked) {
101       if (g_lockdep && !no_lockdep)
102         _locked();
103       _post_lock();
104     }
105     return locked;
106   }
107
108   void lock(bool no_lockdep = false) {
109     if (g_lockdep && !no_lockdep)
110       _will_lock();
111
112     if (try_lock())
113       return;
114
115     auto t = before_lock_blocks();
116     impl->lock_impl();
117     after_lock_blocks(t, no_lockdep);
118     _post_lock();
119   }
120
121   void unlock(bool no_lockdep = false) {
122     _pre_unlock();
123     if (!no_lockdep && g_lockdep)
124       _will_unlock();
125     impl->unlock_impl();
126   }
127 };
128
129 // Since this is a /debugging/ mutex just define it in terms of the
130 // pthread error check mutex.
131 template<bool Recursive>
132 class mutex_debug_impl : public mutex_debugging<mutex_debug_impl<Recursive> > {
133 private:
134   pthread_mutex_t m;
135 public:
136   static constexpr bool recursive = Recursive;
137
138   // Mutex concept is DefaultConstructible
139   mutex_debug_impl(const std::string &n = std::string(), bool bt = false,
140                    CephContext *cct = nullptr) :
141     mutex_debugging<mutex_debug_impl<Recursive> >(n, bt, cct) {
142     pthread_mutexattr_t a;
143     pthread_mutexattr_init(&a);
144     int r;
145     if (recursive)
146       r = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
147     else
148       r = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK);
149     assert(r == 0);
150     r = pthread_mutex_init(&m, &a);
151     assert(r == 0);
152   }
153   // Mutex is Destructible
154   ~mutex_debug_impl() {
155     int r = pthread_mutex_destroy(&m);
156     assert(r == 0);
157   }
158
159   // Mutex concept is non-Copyable
160   mutex_debug_impl(const mutex_debug_impl&) = delete;
161   mutex_debug_impl& operator =(const mutex_debug_impl&) = delete;
162
163   // Mutex concept is non-Movable
164   mutex_debug_impl(mutex_debug_impl&&) = delete;
165   mutex_debug_impl& operator =(mutex_debug_impl&&) = delete;
166
167   void lock_impl() {
168     int r = pthread_mutex_lock(&m);
169     // Allowed error codes for Mutex concept
170     if (unlikely(r == EPERM ||
171                  r == EDEADLK ||
172                  r == EBUSY)) {
173       throw std::system_error(r, std::generic_category());
174     }
175     assert(r == 0);
176   }
177
178   void unlock_impl() noexcept {
179     int r = pthread_mutex_unlock(&m);
180     assert(r == 0);
181   }
182
183   bool try_lock_impl() {
184     int r = pthread_mutex_trylock(&m);
185     switch (r) {
186     case 0:
187       return true;
188     case EBUSY:
189       return false;
190     default:
191       throw std::system_error(r, std::generic_category());
192     }
193   }
194 };
195 } // namespace mutex_debug_detail
196 typedef mutex_debug_detail::mutex_debug_impl<false> mutex_debug;
197 typedef mutex_debug_detail::mutex_debug_impl<true> mutex_recursive_debug;
198 } // namespace ceph
199
200 #endif