diff --git a/include/spinscale/lockSet.h b/include/spinscale/lockSet.h index 51466b2..78edeba 100644 --- a/include/spinscale/lockSet.h +++ b/include/spinscale/lockSet.h @@ -197,15 +197,52 @@ public: allLocksAcquired = false; } - const LockUsageDesc &getLockUsageDesc(const Qutex &criterionLock) const + std::optional> + findLockUsageDesc(const Qutex &criterionLock) { for (auto& lockUsageDesc : locks) { if (&lockUsageDesc.qutex.get() == &criterionLock) { - return lockUsageDesc; + return std::ref(lockUsageDesc); } } + return std::nullopt; + } + + std::optional> + findLockUsageDesc(const Qutex &criterionLock) const + { + for (const auto& lockUsageDesc : locks) + { + if (&lockUsageDesc.qutex.get() == &criterionLock) { + return std::cref(lockUsageDesc); + } + } + + return std::nullopt; + } + + LockUsageDesc &getLockUsageDesc(const Qutex &criterionLock) + { + auto lockUsageDesc = findLockUsageDesc(criterionLock); + if (lockUsageDesc.has_value()) { + return lockUsageDesc->get(); + } + + // Should never happen if the LockSet is properly constructed + throw std::runtime_error( + std::string(__func__) + + ": Qutex not found in this LockSet"); + } + + const LockUsageDesc &getLockUsageDesc(const Qutex &criterionLock) const + { + auto lockUsageDesc = findLockUsageDesc(criterionLock); + if (lockUsageDesc.has_value()) { + return lockUsageDesc->get(); + } + // Should never happen if the LockSet is properly constructed throw std::runtime_error( std::string(__func__) + @@ -225,8 +262,7 @@ public: ": LockSet::releaseQutexEarly() called but allLocksAcquired is false"); } - auto& lockUsageDesc = const_cast( - getLockUsageDesc(qutex)); + auto& lockUsageDesc = getLockUsageDesc(qutex); if (!lockUsageDesc.hasBeenReleased) { diff --git a/include/spinscale/serializedAsynchronousContinuation.h b/include/spinscale/serializedAsynchronousContinuation.h index 340bbfe..e4a06c4 100644 --- a/include/spinscale/serializedAsynchronousContinuation.h +++ b/include/spinscale/serializedAsynchronousContinuation.h @@ -335,16 +335,17 @@ SerializedAsynchronousContinuation auto heldLockSet = currContin->getLockSet(); if (!heldLockSet.has_value()) { continue; } - // Check if the firstFailedQutex is in this continuation's LockSet - try { - heldLockSet->get().getLockUsageDesc(firstFailedQutex); - } catch (const std::runtime_error& e) { - std::cerr << __func__ << ": " << e.what() << std::endl; - continue; - } + // A miss is expected here; only a hit indicates a potential deadlock. + auto lockUsageDesc = heldLockSet->get().findLockUsageDesc( + firstFailedQutex); + if (!lockUsageDesc.has_value() + || lockUsageDesc->get().hasBeenReleased) + { + continue; + } - std::cout << __func__ << ":Deadlock detected: Found " - << "firstFailedQutex @" << &firstFailedQutex + std::cout << __func__ << ":Deadlock detected: Found " + << "firstFailedQutex @" << &firstFailedQutex << " (" << firstFailedQutex.name << ") in LockSet of " << "SerializedAsynchronousContinuation @" << currContin.get() << std::endl; @@ -434,25 +435,21 @@ SerializedAsynchronousContinuation auto heldLockSet = currContin->getLockSet(); if (!heldLockSet.has_value()) { continue; } - // Check if this continuation holds the foreign lock - try { - const auto& lockUsageDesc = heldLockSet - ->get().getLockUsageDesc(foreignLock); + // A miss is expected here; a hit indicates a potential gridlock. + auto lockUsageDesc = heldLockSet->get().findLockUsageDesc( + foreignLock); + if (!lockUsageDesc.has_value()) { continue; } - // 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 @" << currContin.get() - << ", while foreign owner @" << &foreignOwner + // 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 @" << currContin.get() + << ", while foreign owner @" << &foreignOwner << " holds lock @" << &firstFailedQutex << " (" << firstFailedQutex.name << ") that we're waiting for" << std::endl; - return true; - } catch (const std::runtime_error& e) { - // This continuation doesn't hold the foreign lock. Continue. - continue; - } + return true; } }