mirror of
https://github.com/latentPrion/libspinscale.git
synced 2026-04-17 22:44:25 +00:00
SerializedAC:analyze all locksets in contin chain;
Not only those of type <OriginCbT>. * Fix indentation too.
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -25,6 +29,13 @@ public:
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
/**
|
||||
@@ -287,15 +294,13 @@ const
|
||||
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;
|
||||
}
|
||||
@@ -428,20 +431,18 @@ 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 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"
|
||||
|
||||
Reference in New Issue
Block a user