Files
ThordekkCore/DEADLOCK_ROOT_CAUSE_ANALYSIS.md
T
2026-01-20 21:28:45 -03:00

5.1 KiB

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

// 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.