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;