2025-09-22 21:29:43 -04:00
|
|
|
#include <config.h>
|
|
|
|
|
#include <serializedAsynchronousContinuation.h>
|
|
|
|
|
#include <qutex.h>
|
|
|
|
|
|
|
|
|
|
namespace smo {
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_ENABLE_DEBUG_LOCKS
|
2025-09-27 20:51:20 -04:00
|
|
|
|
|
|
|
|
template <class OriginalCbFnT>
|
|
|
|
|
template <class InvocationTargetT>
|
|
|
|
|
bool
|
|
|
|
|
SerializedAsynchronousContinuation<OriginalCbFnT>
|
|
|
|
|
::LockerAndInvoker<InvocationTargetT>
|
|
|
|
|
::traceContinuationHistoryForDeadlockOn(Qutex& firstFailedQutex)
|
|
|
|
|
{
|
|
|
|
|
/** EXPLANATION:
|
|
|
|
|
* In this function we will trace through the chain of continuations that
|
|
|
|
|
* led up to this Lockvoker's continuation. For each continuation which is
|
|
|
|
|
* a SerializedAsynchronousContinuation, we check through its LockSet to see
|
|
|
|
|
* if it contains the lock that failed acquisition. If it does, we have a
|
|
|
|
|
* deadlock.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* We can't start with the continuation directly referenced by this starting
|
|
|
|
|
* Lockvoker as it would contain the all locks we're currently trying to
|
|
|
|
|
* acquire...and rightly so because it's the continuation for this current
|
|
|
|
|
* lockvoker.
|
|
|
|
|
*/
|
|
|
|
|
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
|
|
|
|
|
this->serializedContinuation.getCallersContinuation();
|
|
|
|
|
currContin != nullptr;
|
|
|
|
|
currContin = currContin->getCallersContinuation())
|
|
|
|
|
{
|
|
|
|
|
auto serializedCont = std::dynamic_pointer_cast<
|
|
|
|
|
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
|
|
|
|
|
|
|
|
|
|
if (serializedCont == nullptr) { continue; }
|
|
|
|
|
|
|
|
|
|
// Check if the firstFailedQutex is in this continuation's LockSet
|
|
|
|
|
try {
|
|
|
|
|
const auto& lockUsageDesc = serializedCont->requiredLocks
|
|
|
|
|
.getLockUsageDesc(firstFailedQutex);
|
|
|
|
|
} catch (const std::runtime_error& e) {
|
|
|
|
|
std::cerr << __func__ << ": " << e.what() << std::endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cout << __func__ << ":Deadlock detected: Found "
|
|
|
|
|
<< "firstFailedQutex @" << &firstFailedQutex
|
|
|
|
|
<< " (" << firstFailedQutex.name << ") in LockSet of "
|
|
|
|
|
<< "SerializedAsynchronousContinuation @"
|
|
|
|
|
<< serializedCont.get() << std::endl;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 12:58:41 -04:00
|
|
|
template <class OriginalCbFnT>
|
|
|
|
|
template <class InvocationTargetT>
|
|
|
|
|
bool
|
|
|
|
|
SerializedAsynchronousContinuation<OriginalCbFnT>
|
|
|
|
|
::LockerAndInvoker<InvocationTargetT>
|
|
|
|
|
::traceContinuationHistoryForGridlockOn(Qutex &firstFailedQutex)
|
|
|
|
|
{
|
|
|
|
|
// Empty implementation - to be filled in later
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 21:29:43 -04:00
|
|
|
template <class OriginalCbFnT>
|
|
|
|
|
template <class InvocationTargetT>
|
|
|
|
|
void
|
|
|
|
|
SerializedAsynchronousContinuation<OriginalCbFnT>
|
|
|
|
|
::LockerAndInvoker<InvocationTargetT>
|
2025-09-27 20:51:20 -04:00
|
|
|
::handleDeadlock(Qutex& firstFailedQutex)
|
2025-09-22 21:29:43 -04:00
|
|
|
{
|
2025-09-27 20:51:20 -04:00
|
|
|
std::cerr << __func__ << ": Deadlock: "
|
2025-09-22 21:29:43 -04:00
|
|
|
<< "Lockvoker has been waiting for "
|
|
|
|
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
|
|
std::chrono::steady_clock::now() - this->creationTimestamp)
|
|
|
|
|
.count()
|
|
|
|
|
<< "ms, failed on qutex @" << &firstFailedQutex
|
|
|
|
|
<< " (" << firstFailedQutex.name << ")" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Explicit template instantiations for the types we need
|
|
|
|
|
// Add more as needed for your specific use cases
|
|
|
|
|
|
|
|
|
|
} // namespace smo
|