SerializedAC:analyze all locksets in contin chain;

Not only those of type <OriginCbT>.
* Fix indentation too.
This commit is contained in:
2026-03-05 21:22:50 -04:00
parent e98aae7e7e
commit 85ac715772
3 changed files with 43 additions and 42 deletions

View File

@@ -1,7 +1,11 @@
#ifndef ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H
#define ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H
#include <functional>
#include <memory>
#include <optional>
#include <vector>
#include <spinscale/lockSet.h>
namespace sscl {
@@ -21,10 +25,17 @@ class AsynchronousContinuationChainLink
: public std::enable_shared_from_this<AsynchronousContinuationChainLink>
{
public:
virtual ~AsynchronousContinuationChainLink() = default;
virtual ~AsynchronousContinuationChainLink() = default;
virtual std::shared_ptr<AsynchronousContinuationChainLink>
getCallersContinuationShPtr() const = 0;
virtual std::optional<std::reference_wrapper<const LockSet>>
getLockSet() const
{ return std::nullopt; }
virtual std::optional<std::reference_wrapper<LockSet>> getLockSet()
{ return std::nullopt; }
};
} // namespace sscl

View File

@@ -11,15 +11,11 @@
namespace sscl {
// Forward declarations
template <class OriginalCbFnT>
class SerializedAsynchronousContinuation;
class Qutex;
/**
* @brief LockSet - Manages a collection of locks for acquisition/release
*/
template <class OriginalCbFnT>
class LockSet
{
public:
@@ -44,15 +40,10 @@ public:
public:
/**
* @brief Constructor
* @param parentContinuation Reference to the parent
* SerializedAsynchronousContinuation
* @param qutexes Vector of Qutex references that must be acquired
*/
LockSet(
SerializedAsynchronousContinuation<OriginalCbFnT> &parentContinuation,
std::vector<std::reference_wrapper<Qutex>> qutexes = {})
: parentContinuation(parentContinuation), allLocksAcquired(false),
registeredInQutexQueues(false)
explicit LockSet(std::vector<std::reference_wrapper<Qutex>> qutexes = {})
: allLocksAcquired(false), registeredInQutexQueues(false)
{
/* Convert Qutex references to LockUsageDesc (iterators will be filled
* in during registration)
@@ -131,7 +122,6 @@ public:
bool tryAcquireOrBackOff(
LockerAndInvokerBase &lockvoker,
std::optional<std::reference_wrapper<Qutex>> &firstFailedQutex
= std::nullopt
)
{
if (!registeredInQutexQueues)
@@ -251,7 +241,6 @@ public:
std::vector<LockUsageDesc> locks;
private:
SerializedAsynchronousContinuation<OriginalCbFnT> &parentContinuation;
bool allLocksAcquired, registeredInQutexQueues;
};

View File

@@ -26,9 +26,16 @@ public:
Callback<OriginalCbFnT> originalCbFn,
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
: PostedAsynchronousContinuation<OriginalCbFnT>(caller, originalCbFn),
requiredLocks(*this, std::move(requiredLocks))
requiredLocks(std::move(requiredLocks))
{}
std::optional<std::reference_wrapper<const LockSet>>
getLockSet() const override
{ return std::cref(requiredLocks); }
std::optional<std::reference_wrapper<LockSet>> getLockSet() override
{ return std::ref(requiredLocks); }
template<typename... Args>
void callOriginalCb(Args&&... args)
{
@@ -50,7 +57,7 @@ public:
{ requiredLocks.releaseQutexEarly(qutex); }
public:
LockSet<OriginalCbFnT> requiredLocks;
LockSet requiredLocks;
std::atomic<bool> isAwakeOrBeingAwakened{false};
/**
@@ -284,18 +291,16 @@ const
*/
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
this->getCallersContinuationShPtr();
currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr())
currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr())
{
auto serializedCont = std::dynamic_pointer_cast<
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
if (serializedCont == nullptr) { continue; }
auto heldLockSet = currContin->getLockSet();
if (!heldLockSet.has_value()) { continue; }
// Add this continuation's locks to the held locks list
for (size_t i = 0; i < serializedCont->requiredLocks.locks.size(); ++i)
for (size_t i = 0; i < heldLockSet->get().locks.size(); ++i)
{
heldLocks->push_front(serializedCont->requiredLocks.locks[i].qutex);
heldLocks->push_front(heldLockSet->get().locks[i].qutex);
}
}
@@ -327,14 +332,12 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr())
{
auto serializedCont = std::dynamic_pointer_cast<
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
if (serializedCont == nullptr) { continue; }
auto heldLockSet = currContin->getLockSet();
if (!heldLockSet.has_value()) { continue; }
// Check if the firstFailedQutex is in this continuation's LockSet
try {
serializedCont->requiredLocks.getLockUsageDesc(firstFailedQutex);
heldLockSet->get().getLockUsageDesc(firstFailedQutex);
} catch (const std::runtime_error& e) {
std::cerr << __func__ << ": " << e.what() << std::endl;
continue;
@@ -344,7 +347,7 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
<< "firstFailedQutex @" << &firstFailedQutex
<< " (" << firstFailedQutex.name << ") in LockSet of "
<< "SerializedAsynchronousContinuation @"
<< serializedCont.get() << std::endl;
<< currContin.get() << std::endl;
return true;
}
@@ -425,27 +428,25 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
*/
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
this->serializedContinuation.getCallersContinuationShPtr();
currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr())
currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr())
{
auto serializedCont = std::dynamic_pointer_cast<
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
if (serializedCont == nullptr) { continue; }
auto heldLockSet = currContin->getLockSet();
if (!heldLockSet.has_value()) { continue; }
// Check if this continuation holds the foreign lock
try {
const auto& lockUsageDesc = serializedCont->requiredLocks
.getLockUsageDesc(foreignLock);
const auto& lockUsageDesc = heldLockSet
->get().getLockUsageDesc(foreignLock);
// Matched! We hold a lock that the foreign owner is waiting for
std::cout << __func__ << ": Gridlock detected: We hold lock @"
<< &foreignLock << " (" << foreignLock.name << ") in "
"continuation @" << serializedCont.get()
"continuation @" << currContin.get()
<< ", while foreign owner @" << &foreignOwner
<< " holds lock @" << &firstFailedQutex << " ("
<< firstFailedQutex.name << ") that we're waiting for"
<< std::endl;
<< " holds lock @" << &firstFailedQutex << " ("
<< firstFailedQutex.name << ") that we're waiting for"
<< std::endl;
return true;
} catch (const std::runtime_error& e) {