#ifndef QUTEX_ACQUISITION_HISTORY_TRACKER_H #define QUTEX_ACQUISITION_HISTORY_TRACKER_H #include #include #include #include namespace smo { // Forward declarations class Qutex; class AsynchronousContinuationChainLink; /** * @brief QutexAcquisitionHistoryTracker - Tracks acquisition history for * gridlock detection * * This class maintains a central acquisition history to track all lockvokers * suspected of being gridlocked. It stores information about what locks each * timed-out lockvoker wants and what locks they hold in their continuation * history. */ class QutexAcquisitionHistoryTracker { public: /** * @brief Type definition for the acquisition history entry * * pair.first: The firstFailedQutex that this lockvoker WANTS but can't * acquire * pair.second: A unique_ptr to a list of all acquired Qutexes in this * lockvoker's continuation history */ typedef std::pair< std::reference_wrapper, std::unique_ptr>> > AcquisitionHistoryEntry; /** * @brief Type definition for the acquisition history map * * Key: std::shared_ptr * (the continuation that contains the timed-out lockvoker) * Value: AcquisitionHistoryEntry * (its wanted lock (aka: firstFailedQutex/pair.first) + held locks) */ typedef std::unordered_map< std::shared_ptr, AcquisitionHistoryEntry > AcquisitionHistoryMap; public: static QutexAcquisitionHistoryTracker& getInstance() { static QutexAcquisitionHistoryTracker instance; return instance; } /** * @brief Add a continuation to the acquisition history if it doesn't * already exist * @param continuation Shared pointer to the * AsynchronousContinuationChainLink * @param wantedLock The lock that this continuation wants but can't * acquire * @param heldLocks Unique pointer to list of locks held in this * continuation's history (will be moved) */ void addIfNotExists( std::shared_ptr &continuation, Qutex& wantedLock, std::unique_ptr>> heldLocks ) { auto it = acquisitionHistory.find(continuation); // If a continuation already exists, don't add it again if (it != acquisitionHistory.end()) { return; } acquisitionHistory.emplace(continuation, std::make_pair( std::ref(wantedLock), std::move(heldLocks))); } /** * @brief Remove a continuation from the acquisition history * * @param continuation Shared pointer to the * AsynchronousContinuationChainLink to remove * @return true if the continuation was found and removed, false if not found */ bool remove( std::shared_ptr &continuation ) { auto it = acquisitionHistory.find(continuation); if (it != acquisitionHistory.end()) { acquisitionHistory.erase(it); return true; } return false; } bool heuristicallyTraceContinuationHistoryForGridlockOn( Qutex &firstFailedQutex) const; bool completelyTraceContinuationHistoryForGridlockOn( Qutex &firstFailedQutex) const; // Disable copy constructor and assignment operator QutexAcquisitionHistoryTracker( const QutexAcquisitionHistoryTracker&) = delete; QutexAcquisitionHistoryTracker& operator=( const QutexAcquisitionHistoryTracker&) = delete; private: QutexAcquisitionHistoryTracker() = default; ~QutexAcquisitionHistoryTracker() = default; private: AcquisitionHistoryMap acquisitionHistory; }; } // namespace smo #endif // QUTEX_ACQUISITION_HISTORY_TRACKER_H