]>
git.proxmox.com Git - ceph.git/blob - 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
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #ifndef CEPH_COMMON_MUTEX_DEBUG_H
16 #define CEPH_COMMON_MUTEX_DEBUG_H
18 #include <system_error>
23 #include "include/assert.h"
25 #include "ceph_time.h"
33 namespace mutex_debug_detail
{
34 class mutex_debugging_base
{
38 bool backtrace
; // gather backtrace on lock acquisition
41 std::thread::id locked_by
;
46 void _will_lock(); // about to lock
47 void _locked(); // just locked
48 void _will_unlock(); // about to unlock
50 mutex_debugging_base(const std::string
&n
= std::string(), bool bt
= false,
51 CephContext
*cct
= nullptr);
52 ~mutex_debugging_base();
54 ceph::mono_time
before_lock_blocks();
55 void after_lock_blocks(ceph::mono_time start
,
59 bool is_locked() const {
62 bool is_locked_by_me() const {
63 return nlock
> 0 && locked_by
== std::this_thread::get_id();
65 operator bool() const {
66 return nlock
> 0 && locked_by
== std::this_thread::get_id();
70 template<typename Mutex
>
71 class mutex_debugging
: public mutex_debugging_base
{
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)) {}
79 ~mutex_debugging() = default;
84 locked_by
= std::this_thread::get_id();
91 assert(locked_by
== std::this_thread::get_id());
95 locked_by
= std::thread::id();
98 bool try_lock(bool no_lockdep
= false) {
99 bool locked
= impl
->try_lock_impl();
101 if (g_lockdep
&& !no_lockdep
)
108 void lock(bool no_lockdep
= false) {
109 if (g_lockdep
&& !no_lockdep
)
115 auto t
= before_lock_blocks();
117 after_lock_blocks(t
, no_lockdep
);
121 void unlock(bool no_lockdep
= false) {
123 if (!no_lockdep
&& g_lockdep
)
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
> > {
136 static constexpr bool recursive
= Recursive
;
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
);
146 r
= pthread_mutexattr_settype(&a
, PTHREAD_MUTEX_RECURSIVE
);
148 r
= pthread_mutexattr_settype(&a
, PTHREAD_MUTEX_ERRORCHECK
);
150 r
= pthread_mutex_init(&m
, &a
);
153 // Mutex is Destructible
154 ~mutex_debug_impl() {
155 int r
= pthread_mutex_destroy(&m
);
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;
163 // Mutex concept is non-Movable
164 mutex_debug_impl(mutex_debug_impl
&&) = delete;
165 mutex_debug_impl
& operator =(mutex_debug_impl
&&) = delete;
168 int r
= pthread_mutex_lock(&m
);
169 // Allowed error codes for Mutex concept
170 if (unlikely(r
== EPERM
||
173 throw std::system_error(r
, std::generic_category());
178 void unlock_impl() noexcept
{
179 int r
= pthread_mutex_unlock(&m
);
183 bool try_lock_impl() {
184 int r
= pthread_mutex_trylock(&m
);
191 throw std::system_error(r
, std::generic_category());
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
;