]>
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/ceph_assert.h"
24 #include "include/common_fwd.h"
26 #include "ceph_time.h"
31 namespace mutex_debug_detail
{
33 class mutex_debugging_base
38 bool lockdep
; // track this mutex using lockdep_*
39 bool backtrace
; // gather backtrace on lock acquisition
42 std::thread::id locked_by
= {};
44 bool _enable_lockdep() const {
45 return lockdep
&& g_lockdep
;
48 void _will_lock(bool recursive
=false); // about to lock
49 void _locked(); // just locked
50 void _will_unlock(); // about to unlock
52 mutex_debugging_base(std::string group
, bool ld
= true, bool bt
= false);
53 ~mutex_debugging_base();
56 bool is_locked() const {
59 bool is_locked_by_me() const {
60 return nlock
> 0 && locked_by
== std::this_thread::get_id();
62 operator bool() const {
63 return nlock
> 0 && locked_by
== std::this_thread::get_id();
67 // Since this is a /debugging/ mutex just define it in terms of the
68 // pthread error check mutex.
69 template<bool Recursive
>
70 class mutex_debug_impl
: public mutex_debugging_base
76 pthread_mutexattr_t a
;
77 pthread_mutexattr_init(&a
);
80 r
= pthread_mutexattr_settype(&a
, PTHREAD_MUTEX_RECURSIVE
);
82 r
= pthread_mutexattr_settype(&a
, PTHREAD_MUTEX_ERRORCHECK
);
84 r
= pthread_mutex_init(&m
, &a
);
88 bool enable_lockdep(bool no_lockdep
) const {
91 } else if (no_lockdep
) {
94 return _enable_lockdep();
99 static constexpr bool recursive
= Recursive
;
101 mutex_debug_impl(std::string group
, bool ld
= true, bool bt
= false)
102 : mutex_debugging_base(group
, ld
, bt
) {
106 // Mutex is Destructible
107 ~mutex_debug_impl() {
108 int r
= pthread_mutex_destroy(&m
);
112 // Mutex concept is non-Copyable
113 mutex_debug_impl(const mutex_debug_impl
&) = delete;
114 mutex_debug_impl
& operator =(const mutex_debug_impl
&) = delete;
116 // Mutex concept is non-Movable
117 mutex_debug_impl(mutex_debug_impl
&&) = delete;
118 mutex_debug_impl
& operator =(mutex_debug_impl
&&) = delete;
121 int r
= pthread_mutex_lock(&m
);
122 // Allowed error codes for Mutex concept
123 if (unlikely(r
== EPERM
||
126 throw std::system_error(r
, std::generic_category());
131 void unlock_impl() noexcept
{
132 int r
= pthread_mutex_unlock(&m
);
136 bool try_lock_impl() {
137 int r
= pthread_mutex_trylock(&m
);
144 throw std::system_error(r
, std::generic_category());
147 pthread_mutex_t
* native_handle() {
153 ceph_assert(nlock
== 0);
154 locked_by
= std::this_thread::get_id();
159 ceph_assert(nlock
> 0);
161 ceph_assert(locked_by
== std::this_thread::get_id());
163 ceph_assert(nlock
== 0);
165 locked_by
= std::thread::id();
168 bool try_lock(bool no_lockdep
= false) {
169 bool locked
= try_lock_impl();
171 if (enable_lockdep(no_lockdep
))
178 void lock(bool no_lockdep
= false) {
179 if (enable_lockdep(no_lockdep
))
180 _will_lock(recursive
);
182 if (try_lock(no_lockdep
))
186 if (enable_lockdep(no_lockdep
))
191 void unlock(bool no_lockdep
= false) {
193 if (enable_lockdep(no_lockdep
))
201 } // namespace mutex_debug_detail
202 typedef mutex_debug_detail::mutex_debug_impl
<false> mutex_debug
;
203 typedef mutex_debug_detail::mutex_debug_impl
<true> mutex_recursive_debug
;