Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Core/GameEngine/Include/Common/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@

#include <Utility/hash_map_adapter.h>

#include "mutex.h"

//----------------------------------------------------------------------------
// Forward References
//----------------------------------------------------------------------------
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -168,7 +174,9 @@ class FileSystem : public SubsystemInterface
rts::string_key<AsciiString>, FileExistData,
rts::string_key_hash<AsciiString>,
rts::string_key_equal<AsciiString> > FileExistMap;

mutable FileExistMap m_fileExist;
mutable FastCriticalSectionClass m_fileExistMutex;
#endif
};

Expand Down
21 changes: 16 additions & 5 deletions Core/GameEngine/Source/Common/System/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand Down Expand Up @@ -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())
{
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
Loading