diff options
author | jackpoz <giacomopoz@gmail.com> | 2015-07-19 23:04:04 +0200 |
---|---|---|
committer | jackpoz <giacomopoz@gmail.com> | 2015-07-20 20:52:36 +0200 |
commit | aa042e94c2f76e5735a8f745c3fcb7dd54cf6c0b (patch) | |
tree | bce38c07fb3b2659a5ccf12d150e50181d66ed58 | |
parent | 3c4484d782ace3e3662840dfa2574f334c0e8e9a (diff) |
Core/Collision: Fix race conditions in mmaps
Fix a race condition in MMapManager happening whenever a map was unloaded. GridUnload enabled was required to trigger the race condition.
-rw-r--r-- | src/server/collision/Management/MMapManager.cpp | 65 | ||||
-rw-r--r-- | src/server/collision/Management/MMapManager.h | 5 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 15 |
3 files changed, 61 insertions, 24 deletions
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index 847b7bbd001..b71b94e3291 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -32,11 +32,41 @@ namespace MMAP // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost! } + void MMapManager::InitializeThreadUnsafe(const std::vector<uint32>& mapIds) + { + // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime + for (const uint32& mapId : mapIds) + loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)); + + thread_safe_environment = false; + } + + MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const + { + // return the iterator if found or end() if not found/NULL + MMapDataSet::const_iterator itr = loadedMMaps.find(mapId); + if (itr != loadedMMaps.cend() && !itr->second) + itr = loadedMMaps.cend(); + + return itr; + } + bool MMapManager::loadMapData(uint32 mapId) { // we already have this map loaded? - if (loadedMMaps.find(mapId) != loadedMMaps.end()) - return true; + MMapDataSet::iterator itr = loadedMMaps.find(mapId); + if (itr != loadedMMaps.end()) + { + if (itr->second) + return true; + } + else + { + if (thread_safe_environment) + itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first; + else + ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId); + } // load and init dtNavMesh - read parameters from file uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1; @@ -79,7 +109,7 @@ namespace MMAP MMapData* mmap_data = new MMapData(mesh); mmap_data->mmapLoadedTiles.clear(); - loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data)); + itr->second = mmap_data; return true; } @@ -165,21 +195,20 @@ namespace MMAP dtFree(data); return false; } - - return false; } bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y) { // check if we have this map loaded - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) { // file may not exist, therefore not loaded TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y); return false; } - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; // check if we have this tile loaded uint32 packedGridPos = packTileID(x, y); @@ -214,7 +243,8 @@ namespace MMAP bool MMapManager::unloadMap(uint32 mapId) { - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::iterator itr = loadedMMaps.find(mapId); + if (itr == loadedMMaps.end() || !itr->second) { // file may not exist, therefore not loaded TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId); @@ -222,7 +252,7 @@ namespace MMAP } // unload all tiles from given map - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i) { uint32 x = (i->first >> 16); @@ -237,7 +267,7 @@ namespace MMAP } delete mmap; - loadedMMaps.erase(mapId); + itr->second = nullptr; TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId); return true; @@ -246,14 +276,15 @@ namespace MMAP bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId) { // check if we have this map loaded - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) { // file may not exist, therefore not loaded TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId); return false; } - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) { TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId); @@ -271,18 +302,20 @@ namespace MMAP dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId) { - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) return NULL; - return loadedMMaps[mapId]->navMesh; + return itr->second->navMesh; } dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId) { - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) return NULL; - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) { // allocate mesh query diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h index ac01a3c5693..f51f6ecd981 100644 --- a/src/server/collision/Management/MMapManager.h +++ b/src/server/collision/Management/MMapManager.h @@ -60,9 +60,10 @@ namespace MMAP class MMapManager { public: - MMapManager() : loadedTiles(0) { } + MMapManager() : loadedTiles(0), thread_safe_environment(true) {} ~MMapManager(); + void InitializeThreadUnsafe(const std::vector<uint32>& mapIds); bool loadMap(const std::string& basePath, uint32 mapId, int32 x, int32 y); bool unloadMap(uint32 mapId, int32 x, int32 y); bool unloadMap(uint32 mapId); @@ -78,8 +79,10 @@ namespace MMAP bool loadMapData(uint32 mapId); uint32 packTileID(int32 x, int32 y); + MMapDataSet::const_iterator GetMMapData(uint32 mapId) const; MMapDataSet loadedMMaps; uint32 loadedTiles; + bool thread_safe_environment; }; } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index ab109d8dc2f..fc79f351a54 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1375,15 +1375,16 @@ void World::SetInitialWorldSettings() LoadDBCStores(m_dataPath); DetectDBCLang(); - if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager())) - { - std::vector<uint32> mapIds; - for (uint32 mapId = 0; mapId < sMapStore.GetNumRows(); mapId++) - if (sMapStore.LookupEntry(mapId)) - mapIds.push_back(mapId); + std::vector<uint32> mapIds; + for (uint32 mapId = 0; mapId < sMapStore.GetNumRows(); mapId++) + if (sMapStore.LookupEntry(mapId)) + mapIds.push_back(mapId); + if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager())) vmmgr2->InitializeThreadUnsafe(mapIds); - } + + MMAP::MMapManager* mmmgr = MMAP::MMapFactory::createOrGetMMapManager(); + mmmgr->InitializeThreadUnsafe(mapIds); TC_LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); |