diff --git a/Core/GameEngine/Include/Common/FileSystem.h b/Core/GameEngine/Include/Common/FileSystem.h index 546242d32a..51bf9153ca 100644 --- a/Core/GameEngine/Include/Common/FileSystem.h +++ b/Core/GameEngine/Include/Common/FileSystem.h @@ -53,6 +53,8 @@ #include +#include "mutex.h" + //---------------------------------------------------------------------------- // Forward References //---------------------------------------------------------------------------- @@ -128,6 +130,10 @@ struct FileInfo { // TheSuperHackers @feature xezon 23/08/2025 Implements file instance access. // Can be used to access different versions of files in different archives under the same name. // Instance 0 refers to the top file that shadows all other files under the same name. +// +// TheSuperHackers @bugfix xezon 26/10/2025 Adds a mutex to the file exist map to try prevent +// application hangs during level load after the file exist map was corrupted because of writes +// from multiple threads. //=============================== class FileSystem : public SubsystemInterface { @@ -168,7 +174,9 @@ class FileSystem : public SubsystemInterface rts::string_key, FileExistData, rts::string_key_hash, rts::string_key_equal > FileExistMap; + mutable FileExistMap m_fileExist; + mutable FastCriticalSectionClass m_fileExistMutex; #endif }; diff --git a/Core/GameEngine/Source/Common/System/FileSystem.cpp b/Core/GameEngine/Source/Common/System/FileSystem.cpp index 8d5589b5f6..46d468d4a0 100644 --- a/Core/GameEngine/Source/Common/System/FileSystem.cpp +++ b/Core/GameEngine/Source/Common/System/FileSystem.cpp @@ -192,6 +192,7 @@ File* FileSystem::openFile( const Char *filename, Int access, size_t bufferSize #if ENABLE_FILESYSTEM_EXISTENCE_CACHE if (file != NULL && (file->getAccess() & File::CREATE)) { + FastCriticalSectionClass::LockClass lock(m_fileExistMutex); FileExistMap::iterator it = m_fileExist.find(FileExistMap::key_type::temporary(filename)); if (it != m_fileExist.end()) { @@ -227,6 +228,7 @@ Bool FileSystem::doesFileExist(const Char *filename, FileInstance instance) cons #if ENABLE_FILESYSTEM_EXISTENCE_CACHE { + FastCriticalSectionClass::LockClass lock(m_fileExistMutex); FileExistMap::const_iterator it = m_fileExist.find(FileExistMap::key_type::temporary(filename)); if (it != m_fileExist.end()) { @@ -244,7 +246,10 @@ Bool FileSystem::doesFileExist(const Char *filename, FileInstance instance) cons if (instance == 0) { #if ENABLE_FILESYSTEM_EXISTENCE_CACHE - m_fileExist[filename]; + { + FastCriticalSectionClass::LockClass lock(m_fileExistMutex); + m_fileExist[filename]; + } #endif return TRUE; } @@ -255,15 +260,21 @@ Bool FileSystem::doesFileExist(const Char *filename, FileInstance instance) cons if (TheArchiveFileSystem->doesFileExist(filename, instance)) { #if ENABLE_FILESYSTEM_EXISTENCE_CACHE - FileExistMap::mapped_type& value = m_fileExist[filename]; - value.instanceExists = max(value.instanceExists, instance); + { + FastCriticalSectionClass::LockClass lock(m_fileExistMutex); + FileExistMap::mapped_type& value = m_fileExist[filename]; + value.instanceExists = max(value.instanceExists, instance); + } #endif return TRUE; } #if ENABLE_FILESYSTEM_EXISTENCE_CACHE - FileExistMap::mapped_type& value = m_fileExist[filename]; - value.instanceDoesNotExist = min(value.instanceDoesNotExist, instance); + { + FastCriticalSectionClass::LockClass lock(m_fileExistMutex); + FileExistMap::mapped_type& value = m_fileExist[filename]; + value.instanceDoesNotExist = min(value.instanceDoesNotExist, instance); + } #endif return FALSE; }