]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/mutex_debug.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / common / mutex_debug.h
CommitLineData
7c673cae
FG
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
11fdf7f2 23#include "include/ceph_assert.h"
7c673cae
FG
24
25#include "ceph_time.h"
26#include "likely.h"
27#include "lockdep.h"
28
29class CephContext;
30class PerfCounters;
31
32namespace ceph {
33namespace mutex_debug_detail {
11fdf7f2
TL
34
35class mutex_debugging_base
36{
7c673cae
FG
37protected:
38 std::string name;
39 int id;
40 bool backtrace; // gather backtrace on lock acquisition
41
42 int nlock;
43 std::thread::id locked_by;
11fdf7f2 44
7c673cae
FG
45
46 void _register();
11fdf7f2 47 void _will_lock(bool recursive=false); // about to lock
7c673cae 48 void _locked(); // just locked
11fdf7f2 49 void _will_unlock(); // about to unlock
7c673cae 50
11fdf7f2
TL
51 mutex_debugging_base(const std::string &n, bool bt = false);
52 mutex_debugging_base(const char *n, bool bt = false);
7c673cae
FG
53 ~mutex_debugging_base();
54
7c673cae
FG
55public:
56 bool is_locked() const {
57 return (nlock > 0);
58 }
59 bool is_locked_by_me() const {
60 return nlock > 0 && locked_by == std::this_thread::get_id();
61 }
62 operator bool() const {
63 return nlock > 0 && locked_by == std::this_thread::get_id();
64 }
65};
66
7c673cae
FG
67// Since this is a /debugging/ mutex just define it in terms of the
68// pthread error check mutex.
69template<bool Recursive>
11fdf7f2
TL
70class mutex_debug_impl : public mutex_debugging_base
71{
7c673cae
FG
72private:
73 pthread_mutex_t m;
7c673cae 74
11fdf7f2 75 void _init() {
7c673cae
FG
76 pthread_mutexattr_t a;
77 pthread_mutexattr_init(&a);
78 int r;
79 if (recursive)
80 r = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
81 else
82 r = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK);
11fdf7f2 83 ceph_assert(r == 0);
7c673cae 84 r = pthread_mutex_init(&m, &a);
11fdf7f2
TL
85 ceph_assert(r == 0);
86 }
87
88 bool enable_lockdep(bool no_lockdep) const {
89 if (recursive) {
90 return false;
91 } else if (no_lockdep) {
92 return false;
93 } else {
94 return g_lockdep;
95 }
96 }
97
98public:
99 static constexpr bool recursive = Recursive;
100
101 // Mutex concept is DefaultConstructible
102 mutex_debug_impl(const std::string &n, bool bt = false)
103 : mutex_debugging_base(n, bt) {
104 _init();
105 }
106 mutex_debug_impl(const char *n, bool bt = false)
107 : mutex_debugging_base(n, bt) {
108 _init();
7c673cae 109 }
11fdf7f2 110
7c673cae
FG
111 // Mutex is Destructible
112 ~mutex_debug_impl() {
113 int r = pthread_mutex_destroy(&m);
11fdf7f2 114 ceph_assert(r == 0);
7c673cae
FG
115 }
116
117 // Mutex concept is non-Copyable
118 mutex_debug_impl(const mutex_debug_impl&) = delete;
119 mutex_debug_impl& operator =(const mutex_debug_impl&) = delete;
120
121 // Mutex concept is non-Movable
122 mutex_debug_impl(mutex_debug_impl&&) = delete;
123 mutex_debug_impl& operator =(mutex_debug_impl&&) = delete;
124
125 void lock_impl() {
126 int r = pthread_mutex_lock(&m);
127 // Allowed error codes for Mutex concept
128 if (unlikely(r == EPERM ||
129 r == EDEADLK ||
130 r == EBUSY)) {
131 throw std::system_error(r, std::generic_category());
132 }
11fdf7f2 133 ceph_assert(r == 0);
7c673cae
FG
134 }
135
136 void unlock_impl() noexcept {
137 int r = pthread_mutex_unlock(&m);
11fdf7f2 138 ceph_assert(r == 0);
7c673cae
FG
139 }
140
141 bool try_lock_impl() {
142 int r = pthread_mutex_trylock(&m);
143 switch (r) {
144 case 0:
145 return true;
146 case EBUSY:
147 return false;
148 default:
149 throw std::system_error(r, std::generic_category());
150 }
151 }
11fdf7f2
TL
152 pthread_mutex_t* native_handle() {
153 return &m;
154 }
155
156 void _post_lock() {
157 if (!recursive)
158 ceph_assert(nlock == 0);
159 locked_by = std::this_thread::get_id();
160 nlock++;
161 }
162
163 void _pre_unlock() {
164 ceph_assert(nlock > 0);
165 --nlock;
166 ceph_assert(locked_by == std::this_thread::get_id());
167 if (!recursive)
168 ceph_assert(nlock == 0);
169 if (nlock == 0)
170 locked_by = std::thread::id();
171 }
172
173 bool try_lock(bool no_lockdep = false) {
174 bool locked = try_lock_impl();
175 if (locked) {
176 if (enable_lockdep(no_lockdep))
177 _locked();
178 _post_lock();
179 }
180 return locked;
181 }
182
183 void lock(bool no_lockdep = false) {
184 if (enable_lockdep(no_lockdep))
185 _will_lock(recursive);
186
187 if (try_lock())
188 return;
189
190 lock_impl();
191 if (enable_lockdep(no_lockdep))
192 _locked();
193 _post_lock();
194 }
195
196 void unlock(bool no_lockdep = false) {
197 _pre_unlock();
198 if (enable_lockdep(no_lockdep))
199 _will_unlock();
200 unlock_impl();
201 }
202
7c673cae 203};
11fdf7f2
TL
204
205
7c673cae
FG
206} // namespace mutex_debug_detail
207typedef mutex_debug_detail::mutex_debug_impl<false> mutex_debug;
208typedef mutex_debug_detail::mutex_debug_impl<true> mutex_recursive_debug;
209} // namespace ceph
210
211#endif