Add QutexAcquisitionHistoryTracker; integrate plumbing
We add the new Qutex acquisision history tracker that allows us to dynamically detect qutex gridlocks. We've integrated it into LockerAndInvoker::operator() in a preliminary way. We also moved all of the trace*ForGridlockOn() methods into the new QutexAcquisitionHistoryTracker singleton class. They're more appropriately located there. They're still unimplemented though.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <asynchronousContinuation.h>
|
||||
#include <lockerAndInvokerBase.h>
|
||||
#include <callback.h>
|
||||
#include <qutexAcquisitionHistoryTracker.h>
|
||||
|
||||
namespace smo {
|
||||
|
||||
@@ -36,6 +37,10 @@ public:
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Return list of all qutexes in predecessors' LockSets; excludes self.
|
||||
std::unique_ptr<std::forward_list<std::reference_wrapper<Qutex>>>
|
||||
getAcquiredQutexHistory() const;
|
||||
|
||||
public:
|
||||
LockSet<OriginalCbFnT> requiredLocks;
|
||||
std::atomic<bool> isAwakeOrBeingAwakened{false};
|
||||
@@ -116,8 +121,33 @@ public:
|
||||
bool isDeadlock = traceContinuationHistoryForDeadlockOn(
|
||||
firstFailedQutex);
|
||||
|
||||
bool isGridlock = heuristicallyTraceContinuationHistoryForGridlockOn(
|
||||
firstFailedQutex);
|
||||
bool gridlockIsHeuristicallyLikely = false;
|
||||
bool gridlockIsAlgorithmicallyLikely = false;
|
||||
|
||||
if (gridlockLikely)
|
||||
{
|
||||
auto tracker = QutexAcquisitionHistoryTracker
|
||||
::getInstance();
|
||||
|
||||
auto heldLocks = serializedContinuation
|
||||
.getAcquiredQutexHistory();
|
||||
|
||||
// Add this continuation to the tracker
|
||||
tracker.addIfNotExists(
|
||||
serializedContinuation.shared_from_this(),
|
||||
firstFailedQutex, std::move(heldLocks));
|
||||
|
||||
gridlockIsHeuristicallyLikely = tracker
|
||||
.heuristicallyTraceContinuationHistoryForGridlockOn(
|
||||
firstFailedQutex);
|
||||
|
||||
gridlockIsAlgorithmicallyLikely = tracker
|
||||
.completelyTraceContinuationHistoryForGridlockOn(
|
||||
firstFailedQutex);
|
||||
}
|
||||
|
||||
bool isGridlock = (gridlockIsHeuristicallyLikely
|
||||
|| gridlockIsAlgorithmicallyLikely);
|
||||
|
||||
if (!isDeadlock && !isGridlock)
|
||||
{ return; }
|
||||
@@ -145,6 +175,28 @@ public:
|
||||
* can't acquire the locks anyway.
|
||||
*/
|
||||
serializedContinuation.requiredLocks.unregisterFromQutexQueues();
|
||||
|
||||
#ifdef CONFIG_ENABLE_DEBUG_LOCKS
|
||||
/** EXPLANATION:
|
||||
* If we were being tracked for gridlock detection but successfully
|
||||
* acquired all locks, it was a false positive due to timed delay,
|
||||
* long-running operation, or I/O delay
|
||||
*/
|
||||
if (gridlockLikely)
|
||||
{
|
||||
bool removed = QutexAcquisitionHistoryTracker::getInstance()
|
||||
.remove(serializedContinuation.shared_from_this());
|
||||
|
||||
if (removed)
|
||||
{
|
||||
std::cerr << "LockerAndInvoker::operator(): False positive gridlock "
|
||||
"detection - continuation was being tracked but successfully "
|
||||
"acquired all locks. This was likely due to timed delay, "
|
||||
"long-running operation, or I/O delay." << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
invocationTarget();
|
||||
}
|
||||
|
||||
@@ -227,10 +279,6 @@ public:
|
||||
};
|
||||
|
||||
bool traceContinuationHistoryForDeadlockOn(Qutex &firstFailedQutex);
|
||||
bool heuristicallyTraceContinuationHistoryForGridlockOn(
|
||||
Qutex &firstFailedQutex);
|
||||
bool completelyTraceContinuationHistoryForGridlockOn(
|
||||
Qutex &firstFailedQutex);
|
||||
bool traceContinuationHistoryForDeadlock(void)
|
||||
{
|
||||
for (auto& lockUsageDesc
|
||||
|
||||
Reference in New Issue
Block a user