# DEADLOCK ROOT CAUSE ANALYSIS - THE ACTUAL SOURCE ## CRITICAL DISCOVERY: The Deadlock is NOT in BotAI.cpp After 12 deadlock fixes focused on BotAI.cpp, the deadlock persists because **we've been looking in the wrong place**. ## THE ACTUAL DEADLOCK SOURCE **Location**: `GroupInvitationHandler.cpp` **Lines**: 499-507 **Method**: `SendAcceptPacket()` ### The Deadly Lock Acquisition Chain Thread 1 (World Update Thread) acquires locks in this order: 1. BotSessionMgr::UpdateAllSessions() - holds _sessionsMutex 2. BotAI::UpdateAI() - acquires shared_lock on BotAI::_mutex (in UpdateStrategies) 3. GroupInvitationHandler::Update() - called while BotAI::_mutex held 4. SendAcceptPacket() - tries botAI->ActivateStrategy("follow") 5. BotAI::ActivateStrategy() - tries to acquire UNIQUE_LOCK on _mutex 6. **DEADLOCK**: Can't upgrade shared_lock to unique_lock on same thread ## DETAILED ANALYSIS ### The Call Stack At Deadlock: ``` BotAI::UpdateAI() [Holds: shared_lock on BotAI::_mutex] └─ UpdateStrategies(diff) [Acquires shared_lock - OK] └─ _groupInvitationHandler->Update(diff) [Line 157 - still holds shared_lock] └─ ProcessNextInvitation() └─ AcceptInvitationInternal() └─ SendAcceptPacket() └─ Line 499: botAI->GetStrategy("follow") [Tries shared_lock AGAIN] └─ Line 505: botAI->ActivateStrategy("follow") [Tries UNIQUE_LOCK - DEADLOCK] └─ BotAI::ActivateStrategy() └─ std::unique_lock lock(_mutex) [BLOCKED: can't upgrade shared to unique] ``` ### Why This Deadlocks: 1. **BotAI::UpdateStrategies()** acquires `std::shared_lock` on `BotAI::_mutex` 2. Still holding that lock, **BotAI::UpdateAI()** calls `GroupInvitationHandler::Update()` 3. GroupInvitationHandler processes group join, calls `SendAcceptPacket()` 4. SendAcceptPacket() tries to call **BotAI::ActivateStrategy()** (line 505) 5. ActivateStrategy() needs `std::unique_lock` on same `BotAI::_mutex` 6. **DEADLOCK**: Same thread cannot upgrade shared_lock to unique_lock ### Root Cause: **Reentrant lock acquisition from callback context** The GroupInvitationHandler is called FROM BotAI::UpdateAI() while locks are held, then tries to call BACK into BotAI methods that need stronger locks. ## THE SOLUTION ### IMMEDIATE FIX (Remove Redundant Code): **File**: `c:/TrinityBots/TrinityCore/src/modules/Playerbot/Group/GroupInvitationHandler.cpp` **Action**: DELETE lines 497-507 ```cpp // DELETE THESE LINES (they cause the deadlock): // BACKUP FIX: Directly activate follow strategy as fallback TC_LOG_INFO("module.playerbot.group", "Bot directly activating follow strategy", _bot->GetName()); if (botAI->GetStrategy("follow")) // ← Line 499: REENTRANT LOCK { TC_LOG_INFO("module.playerbot.group", "Bot already has follow strategy", _bot->GetName()); } else { botAI->ActivateStrategy("follow"); // ← Line 505: DEADLOCK SOURCE TC_LOG_INFO("module.playerbot.group", "Bot activated follow strategy", _bot->GetName()); } ``` **Reason**: OnGroupJoined() is already called at lines 455 and 494, which properly activates the follow strategy. Lines 497-507 are redundant backup code that creates the deadlock. ### WHY PREVIOUS FIXES DIDN'T WORK All 12 fixes focused on **BotAI::UpdateStrategies()** lock ordering, but that's not the problem: - UpdateStrategies() correctly acquires and releases locks - The issue is in **GroupInvitationHandler::SendAcceptPacket()** calling back into BotAI - The callback happens WHILE BotAI::_mutex is still held (shared) - Then tries to acquire unique_lock on the SAME mutex = deadlock ## VALIDATION After fix, test: 1. Create bot 2. Invite bot to group 3. Bot auto-accepts 4. Bot starts following 5. **NO "resource deadlock would occur" exception** ## THREADING MODEL ### Single Main Thread: ``` Main World Thread: └─> PlayerbotModule::OnUpdate(diff) └─> BotSessionMgr::UpdateAllSessions(diff) └─> For each session (SEQUENTIAL): └─> BotSession::Update(diff) └─> BotAI::UpdateAI(diff) ├─ UpdateStrategies() [shared_lock] └─ GroupInvitationHandler::Update() [CALLBACK - DEADLOCK HERE] ``` **Key**: Single-threaded, but deadlock happens from reentrant callback, not threading. ## COMPREHENSIVE MUTEX INVENTORY **Total**: 200+ mutexes across 150+ classes in Playerbot module **High-Risk** (Direct BotAI interaction): - GroupInvitationHandler::_invitationMutex - BotSession::_packetMutex - BotSessionMgr::_sessionsMutex - ActionPriority::_queueMutex, _poolMutex - CooldownManager::_cooldownMutex, _categoryMutex **Medium-Risk** (Indirect): - All ClassAI specializations (200+ _cooldownMutex) - Combat managers - Performance monitors ## CONCLUSION The deadlock source was **GroupInvitationHandler.cpp lines 497-507**, not BotAI.cpp. **Immediate action**: Delete the redundant backup code that tries to activate strategy from callback context.