Redesign of ZoneServer::DeleteSpawns to avoid deadlocks

This commit is contained in:
Emagi 2025-07-01 07:39:51 -04:00
parent 398a4ef1f4
commit 40e83f5e2d

View File

@ -1504,20 +1504,27 @@ void ZoneServer::AddPendingDelete(Spawn* spawn) {
} }
void ZoneServer::DeleteSpawns(bool delete_all) { void ZoneServer::DeleteSpawns(bool delete_all) {
// 1) Snapshot & clear deletelist
MSpawnDeleteList.writelock(__FUNCTION__, __LINE__); MSpawnDeleteList.writelock(__FUNCTION__, __LINE__);
MPendingSpawnRemoval.readlock(__FUNCTION__, __LINE__); std::vector<std::pair<Spawn*,int32>> to_process(
if(spawn_delete_list.size() > 0){ spawn_delete_list.begin(), spawn_delete_list.end()
map<Spawn*, int32>::iterator itr; );
map<Spawn*, int32>::iterator erase_itr; spawn_delete_list.clear();
MSpawnDeleteList.releasewritelock(__FUNCTION__, __LINE__);
MSpawnList.writelock(__FUNCTION__, __LINE__);
int32 current_time = Timer::GetCurrentTime2(); int32 current_time = Timer::GetCurrentTime2();
Spawn* spawn = 0; for (auto &entry : to_process) {
for (itr = spawn_delete_list.begin(); itr != spawn_delete_list.end(); ) { Spawn* spawn = entry.first;
if (delete_all || current_time >= itr->second){ int32 when = entry.second;
// we haven't removed it from the spawn list yet..
if(!delete_all && m_pendingSpawnRemove.count(itr->first->GetID())) if (!delete_all && current_time < when)
continue; continue;
spawn = itr->first; MPendingSpawnRemoval.readlock(__FUNCTION__, __LINE__);
if(!delete_all && m_pendingSpawnRemove.count(spawn->GetID()))
continue;
MPendingSpawnRemoval.releasereadlock(__FUNCTION__, __LINE__);
lua_interface->SetLuaUserDataStale(spawn); lua_interface->SetLuaUserDataStale(spawn);
@ -1536,10 +1543,6 @@ void ZoneServer::DeleteSpawns(bool delete_all) {
tmpNPC->SetBrain(nullptr); tmpNPC->SetBrain(nullptr);
} }
erase_itr = itr++;
spawn_delete_list.erase(erase_itr);
MSpawnList.writelock(__FUNCTION__, __LINE__);
std::map<int32, Spawn*>::iterator sitr = spawn_list.find(spawn->GetID()); std::map<int32, Spawn*>::iterator sitr = spawn_list.find(spawn->GetID());
if(sitr != spawn_list.end()) { if(sitr != spawn_list.end()) {
spawn_list.erase(sitr); spawn_list.erase(sitr);
@ -1559,15 +1562,9 @@ void ZoneServer::DeleteSpawns(bool delete_all) {
} }
housing_spawn_map.erase(spawn->GetID()); housing_spawn_map.erase(spawn->GetID());
} }
MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
safe_delete(spawn); safe_delete(spawn);
} }
else MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
itr++;
}
}
MPendingSpawnRemoval.releasereadlock(__FUNCTION__, __LINE__);
MSpawnDeleteList.releasewritelock(__FUNCTION__, __LINE__);
} }
void ZoneServer::AddDamagedSpawn(Spawn* spawn){ void ZoneServer::AddDamagedSpawn(Spawn* spawn){