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
|
#ifndef ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H
|
||||||
#define ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H
|
#define ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
#include <spinscale/lockSet.h>
|
||||||
|
|
||||||
namespace sscl {
|
namespace sscl {
|
||||||
|
|
||||||
@@ -21,10 +25,17 @@ class AsynchronousContinuationChainLink
|
|||||||
: public std::enable_shared_from_this<AsynchronousContinuationChainLink>
|
: public std::enable_shared_from_this<AsynchronousContinuationChainLink>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~AsynchronousContinuationChainLink() = default;
|
virtual ~AsynchronousContinuationChainLink() = default;
|
||||||
|
|
||||||
virtual std::shared_ptr<AsynchronousContinuationChainLink>
|
virtual std::shared_ptr<AsynchronousContinuationChainLink>
|
||||||
getCallersContinuationShPtr() const = 0;
|
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
|
} // namespace sscl
|
||||||
|
|||||||
@@ -11,15 +11,11 @@
|
|||||||
|
|
||||||
namespace sscl {
|
namespace sscl {
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
template <class OriginalCbFnT>
|
|
||||||
class SerializedAsynchronousContinuation;
|
|
||||||
class Qutex;
|
class Qutex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief LockSet - Manages a collection of locks for acquisition/release
|
* @brief LockSet - Manages a collection of locks for acquisition/release
|
||||||
*/
|
*/
|
||||||
template <class OriginalCbFnT>
|
|
||||||
class LockSet
|
class LockSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -44,15 +40,10 @@ public:
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
* @param parentContinuation Reference to the parent
|
|
||||||
* SerializedAsynchronousContinuation
|
|
||||||
* @param qutexes Vector of Qutex references that must be acquired
|
* @param qutexes Vector of Qutex references that must be acquired
|
||||||
*/
|
*/
|
||||||
LockSet(
|
explicit LockSet(std::vector<std::reference_wrapper<Qutex>> qutexes = {})
|
||||||
SerializedAsynchronousContinuation<OriginalCbFnT> &parentContinuation,
|
: allLocksAcquired(false), registeredInQutexQueues(false)
|
||||||
std::vector<std::reference_wrapper<Qutex>> qutexes = {})
|
|
||||||
: parentContinuation(parentContinuation), allLocksAcquired(false),
|
|
||||||
registeredInQutexQueues(false)
|
|
||||||
{
|
{
|
||||||
/* Convert Qutex references to LockUsageDesc (iterators will be filled
|
/* Convert Qutex references to LockUsageDesc (iterators will be filled
|
||||||
* in during registration)
|
* in during registration)
|
||||||
@@ -131,7 +122,6 @@ public:
|
|||||||
bool tryAcquireOrBackOff(
|
bool tryAcquireOrBackOff(
|
||||||
LockerAndInvokerBase &lockvoker,
|
LockerAndInvokerBase &lockvoker,
|
||||||
std::optional<std::reference_wrapper<Qutex>> &firstFailedQutex
|
std::optional<std::reference_wrapper<Qutex>> &firstFailedQutex
|
||||||
= std::nullopt
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!registeredInQutexQueues)
|
if (!registeredInQutexQueues)
|
||||||
@@ -251,7 +241,6 @@ public:
|
|||||||
std::vector<LockUsageDesc> locks;
|
std::vector<LockUsageDesc> locks;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SerializedAsynchronousContinuation<OriginalCbFnT> &parentContinuation;
|
|
||||||
bool allLocksAcquired, registeredInQutexQueues;
|
bool allLocksAcquired, registeredInQutexQueues;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,16 @@ public:
|
|||||||
Callback<OriginalCbFnT> originalCbFn,
|
Callback<OriginalCbFnT> originalCbFn,
|
||||||
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
||||||
: PostedAsynchronousContinuation<OriginalCbFnT>(caller, originalCbFn),
|
: 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>
|
template<typename... Args>
|
||||||
void callOriginalCb(Args&&... args)
|
void callOriginalCb(Args&&... args)
|
||||||
{
|
{
|
||||||
@@ -50,7 +57,7 @@ public:
|
|||||||
{ requiredLocks.releaseQutexEarly(qutex); }
|
{ requiredLocks.releaseQutexEarly(qutex); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LockSet<OriginalCbFnT> requiredLocks;
|
LockSet requiredLocks;
|
||||||
std::atomic<bool> isAwakeOrBeingAwakened{false};
|
std::atomic<bool> isAwakeOrBeingAwakened{false};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,18 +291,16 @@ const
|
|||||||
*/
|
*/
|
||||||
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
|
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
|
||||||
this->getCallersContinuationShPtr();
|
this->getCallersContinuationShPtr();
|
||||||
currContin != nullptr;
|
currContin != nullptr;
|
||||||
currContin = currContin->getCallersContinuationShPtr())
|
currContin = currContin->getCallersContinuationShPtr())
|
||||||
{
|
{
|
||||||
auto serializedCont = std::dynamic_pointer_cast<
|
auto heldLockSet = currContin->getLockSet();
|
||||||
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
|
if (!heldLockSet.has_value()) { continue; }
|
||||||
|
|
||||||
if (serializedCont == nullptr) { continue; }
|
|
||||||
|
|
||||||
// Add this continuation's locks to the held locks list
|
// 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 != nullptr;
|
||||||
currContin = currContin->getCallersContinuationShPtr())
|
currContin = currContin->getCallersContinuationShPtr())
|
||||||
{
|
{
|
||||||
auto serializedCont = std::dynamic_pointer_cast<
|
auto heldLockSet = currContin->getLockSet();
|
||||||
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
|
if (!heldLockSet.has_value()) { continue; }
|
||||||
|
|
||||||
if (serializedCont == nullptr) { continue; }
|
|
||||||
|
|
||||||
// Check if the firstFailedQutex is in this continuation's LockSet
|
// Check if the firstFailedQutex is in this continuation's LockSet
|
||||||
try {
|
try {
|
||||||
serializedCont->requiredLocks.getLockUsageDesc(firstFailedQutex);
|
heldLockSet->get().getLockUsageDesc(firstFailedQutex);
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
std::cerr << __func__ << ": " << e.what() << std::endl;
|
std::cerr << __func__ << ": " << e.what() << std::endl;
|
||||||
continue;
|
continue;
|
||||||
@@ -344,7 +347,7 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
|
|||||||
<< "firstFailedQutex @" << &firstFailedQutex
|
<< "firstFailedQutex @" << &firstFailedQutex
|
||||||
<< " (" << firstFailedQutex.name << ") in LockSet of "
|
<< " (" << firstFailedQutex.name << ") in LockSet of "
|
||||||
<< "SerializedAsynchronousContinuation @"
|
<< "SerializedAsynchronousContinuation @"
|
||||||
<< serializedCont.get() << std::endl;
|
<< currContin.get() << std::endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -425,27 +428,25 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
|
|||||||
*/
|
*/
|
||||||
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
|
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
|
||||||
this->serializedContinuation.getCallersContinuationShPtr();
|
this->serializedContinuation.getCallersContinuationShPtr();
|
||||||
currContin != nullptr;
|
currContin != nullptr;
|
||||||
currContin = currContin->getCallersContinuationShPtr())
|
currContin = currContin->getCallersContinuationShPtr())
|
||||||
{
|
{
|
||||||
auto serializedCont = std::dynamic_pointer_cast<
|
auto heldLockSet = currContin->getLockSet();
|
||||||
SerializedAsynchronousContinuation<OriginalCbFnT>>(currContin);
|
if (!heldLockSet.has_value()) { continue; }
|
||||||
|
|
||||||
if (serializedCont == nullptr) { continue; }
|
|
||||||
|
|
||||||
// Check if this continuation holds the foreign lock
|
// Check if this continuation holds the foreign lock
|
||||||
try {
|
try {
|
||||||
const auto& lockUsageDesc = serializedCont->requiredLocks
|
const auto& lockUsageDesc = heldLockSet
|
||||||
.getLockUsageDesc(foreignLock);
|
->get().getLockUsageDesc(foreignLock);
|
||||||
|
|
||||||
// Matched! We hold a lock that the foreign owner is waiting for
|
// Matched! We hold a lock that the foreign owner is waiting for
|
||||||
std::cout << __func__ << ": Gridlock detected: We hold lock @"
|
std::cout << __func__ << ": Gridlock detected: We hold lock @"
|
||||||
<< &foreignLock << " (" << foreignLock.name << ") in "
|
<< &foreignLock << " (" << foreignLock.name << ") in "
|
||||||
"continuation @" << serializedCont.get()
|
"continuation @" << currContin.get()
|
||||||
<< ", while foreign owner @" << &foreignOwner
|
<< ", while foreign owner @" << &foreignOwner
|
||||||
<< " holds lock @" << &firstFailedQutex << " ("
|
<< " holds lock @" << &firstFailedQutex << " ("
|
||||||
<< firstFailedQutex.name << ") that we're waiting for"
|
<< firstFailedQutex.name << ") that we're waiting for"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user