17#include <system_error>
20#include <unordered_map>
24#ifdef DEBUG_LOCKCONTENTION
26template <
typename LockType>
32template void ContendedLock(std::string_view
name, std::string_view file,
int nLine, std::unique_lock<std::mutex>& lock);
33template void ContendedLock(std::string_view
name, std::string_view file,
int nLine, std::unique_lock<std::recursive_mutex>& lock);
55 std::string&& thread_name)
59 m_thread_name(
std::move(thread_name)),
65 "'%s' in %s:%s%s (in thread '%s')",
69 std::string
Name()
const
78 const std::string m_thread_name;
83using LockStack = std::vector<LockStackItem>;
84using LockStacks = std::unordered_map<std::thread::id, LockStack>;
86using LockPair = std::pair<void*, void*>;
87using LockOrders = std::map<LockPair, LockStack>;
108 LogError(
"POTENTIAL DEADLOCK DETECTED");
109 LogError(
"Previous lock order was:");
136 tfm::format(std::cerr,
"Assertion failed: detected inconsistent lock order for %s, details in debug log.\n",
s2.back().second.ToString());
148 if (i.first == mutex) {
155 "Assertion failed: detected double lock for %s, details in debug log.\n",
159 throw std::logic_error(
"double lock detected");
162template <
typename MutexType>
166 std::is_base_of_v<RecursiveMutex, MutexType> ||
167 std::is_base_of_v<std::recursive_mutex, MutexType>;
215 lockdata.m_lock_stacks.erase(std::this_thread::get_id());
219template <
typename MutexType>
224template void EnterCritical(
const char*,
const char*,
int, std::mutex*,
bool);
225template void EnterCritical(
const char*,
const char*,
int, std::recursive_mutex*,
bool);
241 LogError(
"INCONSISTENT LOCK ORDER DETECTED");
242 LogError(
"Current lock order (least recent first) is:");
244 LogError(
" %s", i.second.ToString());
247 tfm::format(std::cerr,
"%s:%s %s was not most recent critical section locked, details in debug log.\n", file, line,
guardname);
250 throw std::logic_error(
strprintf(
"%s was not most recent critical section locked",
guardname));
277 if (i.first == mutex)
return true;
283template <
typename MutexType>
293template <
typename MutexType>
308 LockOrders::iterator it =
lockdata.lockorders.lower_bound(
item);
309 while (it !=
lockdata.lockorders.end() && it->first.first ==
cs) {
310 const LockPair invitem = std::make_pair(it->first.second, it->first.first);
326 const auto it =
lockdata.m_lock_stacks.find(std::this_thread::get_id());
327 if (it ==
lockdata.m_lock_stacks.end()) {
330 return it->second.empty();
constexpr std::string_view Name(LogLevel level) noexcept
std::string ThreadGetInternalName()
Get the thread's internal (in-memory) name; used e.g.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs)
void EnterCritical(const char *pszName, const char *pszFile, int nLine, MutexType *cs, bool fTry=false)
void DeleteLock(void *cs)
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, const char *file, int line)
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) LOCKS_EXCLUDED(cs)
#define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category)
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.