From 85ac7157723ab4c5a74a28af0998251dfca13543 Mon Sep 17 00:00:00 2001 From: Hayodea Hekol Date: Thu, 5 Mar 2026 21:22:50 -0400 Subject: [PATCH] SerializedAC:analyze all locksets in contin chain; Not only those of type . * Fix indentation too. --- .../asynchronousContinuationChainLink.h | 13 ++++- include/spinscale/lockSet.h | 15 +---- .../serializedAsynchronousContinuation.h | 57 ++++++++++--------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/include/spinscale/asynchronousContinuationChainLink.h b/include/spinscale/asynchronousContinuationChainLink.h index e9b05da..79ffd08 100644 --- a/include/spinscale/asynchronousContinuationChainLink.h +++ b/include/spinscale/asynchronousContinuationChainLink.h @@ -1,7 +1,11 @@ #ifndef ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H #define ASYNCHRONOUS_CONTINUATION_CHAIN_LINK_H +#include #include +#include +#include +#include namespace sscl { @@ -21,10 +25,17 @@ class AsynchronousContinuationChainLink : public std::enable_shared_from_this { public: - virtual ~AsynchronousContinuationChainLink() = default; + virtual ~AsynchronousContinuationChainLink() = default; virtual std::shared_ptr getCallersContinuationShPtr() const = 0; + + virtual std::optional> + getLockSet() const + { return std::nullopt; } + + virtual std::optional> getLockSet() + { return std::nullopt; } }; } // namespace sscl diff --git a/include/spinscale/lockSet.h b/include/spinscale/lockSet.h index e00687c..51466b2 100644 --- a/include/spinscale/lockSet.h +++ b/include/spinscale/lockSet.h @@ -11,15 +11,11 @@ namespace sscl { -// Forward declarations -template -class SerializedAsynchronousContinuation; class Qutex; /** * @brief LockSet - Manages a collection of locks for acquisition/release */ -template 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 &parentContinuation, - std::vector> qutexes = {}) - : parentContinuation(parentContinuation), allLocksAcquired(false), - registeredInQutexQueues(false) + explicit LockSet(std::vector> 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> &firstFailedQutex - = std::nullopt ) { if (!registeredInQutexQueues) @@ -251,7 +241,6 @@ public: std::vector locks; private: - SerializedAsynchronousContinuation &parentContinuation; bool allLocksAcquired, registeredInQutexQueues; }; diff --git a/include/spinscale/serializedAsynchronousContinuation.h b/include/spinscale/serializedAsynchronousContinuation.h index 2c4b4de..340bbfe 100644 --- a/include/spinscale/serializedAsynchronousContinuation.h +++ b/include/spinscale/serializedAsynchronousContinuation.h @@ -26,9 +26,16 @@ public: Callback originalCbFn, std::vector> requiredLocks) : PostedAsynchronousContinuation(caller, originalCbFn), - requiredLocks(*this, std::move(requiredLocks)) + requiredLocks(std::move(requiredLocks)) {} + std::optional> + getLockSet() const override + { return std::cref(requiredLocks); } + + std::optional> getLockSet() override + { return std::ref(requiredLocks); } + template void callOriginalCb(Args&&... args) { @@ -50,7 +57,7 @@ public: { requiredLocks.releaseQutexEarly(qutex); } public: - LockSet requiredLocks; + LockSet requiredLocks; std::atomic isAwakeOrBeingAwakened{false}; /** @@ -284,18 +291,16 @@ const */ for (std::shared_ptr currContin = this->getCallersContinuationShPtr(); - currContin != nullptr; - currContin = currContin->getCallersContinuationShPtr()) + currContin != nullptr; + currContin = currContin->getCallersContinuationShPtr()) { - auto serializedCont = std::dynamic_pointer_cast< - SerializedAsynchronousContinuation>(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 currContin != nullptr; currContin = currContin->getCallersContinuationShPtr()) { - auto serializedCont = std::dynamic_pointer_cast< - SerializedAsynchronousContinuation>(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 << "firstFailedQutex @" << &firstFailedQutex << " (" << firstFailedQutex.name << ") in LockSet of " << "SerializedAsynchronousContinuation @" - << serializedCont.get() << std::endl; + << currContin.get() << std::endl; return true; } @@ -425,27 +428,25 @@ SerializedAsynchronousContinuation */ for (std::shared_ptr currContin = this->serializedContinuation.getCallersContinuationShPtr(); - currContin != nullptr; - currContin = currContin->getCallersContinuationShPtr()) + currContin != nullptr; + currContin = currContin->getCallersContinuationShPtr()) { - auto serializedCont = std::dynamic_pointer_cast< - SerializedAsynchronousContinuation>(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) {