diff --git a/Benchmarks/Google/Core/GoogleBenchmarkMain.cpp b/Benchmarks/Google/Core/GoogleBenchmarkMain.cpp index f405e1a96df..0db05987906 100644 --- a/Benchmarks/Google/Core/GoogleBenchmarkMain.cpp +++ b/Benchmarks/Google/Core/GoogleBenchmarkMain.cpp @@ -47,23 +47,17 @@ class EngineCriticalSections public: EngineCriticalSections() { - TheAsciiStringCriticalSection = &m_asciiString; - TheUnicodeStringCriticalSection = &m_unicodeString; TheDmaCriticalSection = &m_dma; TheMemoryPoolCriticalSection = &m_memoryPool; } ~EngineCriticalSections() { - TheAsciiStringCriticalSection = nullptr; - TheUnicodeStringCriticalSection = nullptr; TheDmaCriticalSection = nullptr; TheMemoryPoolCriticalSection = nullptr; } private: - CriticalSection m_asciiString; - CriticalSection m_unicodeString; CriticalSection m_dma; CriticalSection m_memoryPool; }; diff --git a/Core/GameEngine/Include/Common/AsciiString.h b/Core/GameEngine/Include/Common/AsciiString.h index 6065881b27e..7505183db7e 100644 --- a/Core/GameEngine/Include/Common/AsciiString.h +++ b/Core/GameEngine/Include/Common/AsciiString.h @@ -49,6 +49,7 @@ #include "Lib/BaseType.h" #include "Common/Debug.h" #include "Common/Errors.h" +#include class UnicodeString; @@ -80,11 +81,11 @@ class AsciiString { private: - // Note, this is a Plain Old Data Structure... don't - // add a ctor/dtor, 'cuz they won't ever be called. + // This header data is allocated in raw storage with an explicit lifetime. + // It is constructed when string data is allocated and destroyed when the string is freed. struct AsciiStringData { - unsigned short m_refCount; // reference count + std::atomic m_refCount; // reference count unsigned short m_numCharsAllocated; // length of data allocated // char m_stringdata[]; diff --git a/Core/GameEngine/Include/Common/UnicodeString.h b/Core/GameEngine/Include/Common/UnicodeString.h index 9a12d79708d..952a2017480 100644 --- a/Core/GameEngine/Include/Common/UnicodeString.h +++ b/Core/GameEngine/Include/Common/UnicodeString.h @@ -49,6 +49,7 @@ #include "Lib/BaseType.h" #include "Common/Debug.h" #include "Common/Errors.h" +#include class AsciiString; @@ -80,11 +81,11 @@ class UnicodeString { private: - // Note, this is a Plain Old Data Structure... don't - // add a ctor/dtor, 'cuz they won't ever be called. + // This header data is allocated in raw storage with an explicit lifetime. + // It is constructed when string data is allocated and destroyed when the string is freed. struct UnicodeStringData { - unsigned short m_refCount; // reference count + std::atomic m_refCount; // reference count unsigned short m_numCharsAllocated; // length of data allocated // WideChar m_stringdata[]; diff --git a/Core/GameEngine/Source/Common/System/AsciiString.cpp b/Core/GameEngine/Source/Common/System/AsciiString.cpp index ca53aede056..12ef2de8cd2 100644 --- a/Core/GameEngine/Source/Common/System/AsciiString.cpp +++ b/Core/GameEngine/Source/Common/System/AsciiString.cpp @@ -44,7 +44,6 @@ /////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine -#include "Common/CriticalSection.h" #include "WWLib/utf8.h" @@ -121,7 +120,6 @@ static StringCaseInfo getStringCaseInfo(const char *str) // ----------------------------------------------------- AsciiString::AsciiString(const AsciiString& stringSrc) : m_data(stringSrc.m_data) { - ScopedCriticalSection scopedCriticalSection(TheAsciiStringCriticalSection); if (m_data) ++m_data->m_refCount; validate(); @@ -184,7 +182,8 @@ void AsciiString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveData DEBUG_ASSERTCRASH(numCharsNeeded <= MAX_LEN, ("AsciiString::ensureUniqueBufferOfSize exceeds max string length %d with requested length %d", MAX_LEN, numCharsNeeded)); int minBytes = sizeof(AsciiStringData) + numCharsNeeded*sizeof(char); int actualBytes = TheDynamicMemoryAllocator->getActualAllocationSize(minBytes); - AsciiStringData* newData = (AsciiStringData*)TheDynamicMemoryAllocator->allocateBytesDoNotZero(actualBytes, "STR_AsciiString::ensureUniqueBufferOfSize"); + void* rawData = TheDynamicMemoryAllocator->allocateBytesDoNotZero(actualBytes, "STR_AsciiString::ensureUniqueBufferOfSize"); + AsciiStringData* newData = new(rawData) AsciiStringData; newData->m_refCount = 1; newData->m_numCharsAllocated = (actualBytes - sizeof(AsciiStringData))/sizeof(char); @@ -214,16 +213,17 @@ void AsciiString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveData // ----------------------------------------------------- void AsciiString::releaseBuffer() { - ScopedCriticalSection scopedCriticalSection(TheAsciiStringCriticalSection); - validate(); if (m_data) { - if (--m_data->m_refCount == 0) + AsciiStringData* oldData = m_data; + m_data = nullptr; + + if (--oldData->m_refCount == 0) { - TheDynamicMemoryAllocator->freeBytes(m_data); + oldData->~AsciiStringData(); + TheDynamicMemoryAllocator->freeBytes(oldData); } - m_data = nullptr; } validate(); } @@ -253,15 +253,15 @@ AsciiString::AsciiString(const char* s, int len) : m_data(nullptr) // ----------------------------------------------------- void AsciiString::set(const AsciiString& stringSrc) { - ScopedCriticalSection scopedCriticalSection(TheAsciiStringCriticalSection); - validate(); if (&stringSrc != this) { + AsciiStringData* newData = stringSrc.m_data; + if (newData) + ++newData->m_refCount; + releaseBuffer(); - m_data = stringSrc.m_data; - if (m_data) - ++m_data->m_refCount; + m_data = newData; } validate(); } diff --git a/Core/GameEngine/Source/Common/System/UnicodeString.cpp b/Core/GameEngine/Source/Common/System/UnicodeString.cpp index 27b7e11c0cb..0c7ca508268 100644 --- a/Core/GameEngine/Source/Common/System/UnicodeString.cpp +++ b/Core/GameEngine/Source/Common/System/UnicodeString.cpp @@ -44,7 +44,6 @@ /////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine -#include "Common/CriticalSection.h" #include "WWLib/utf8.h" @@ -66,7 +65,6 @@ void UnicodeString::validate() const // ----------------------------------------------------- UnicodeString::UnicodeString(const UnicodeString& stringSrc) : m_data(stringSrc.m_data) { - ScopedCriticalSection scopedCriticalSection(TheUnicodeStringCriticalSection); if (m_data) ++m_data->m_refCount; validate(); @@ -100,7 +98,8 @@ void UnicodeString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveDa DEBUG_ASSERTCRASH(numCharsNeeded <= MAX_LEN, ("UnicodeString::ensureUniqueBufferOfSize exceeds max string length %d with requested length %d", MAX_LEN, numCharsNeeded)); int minBytes = sizeof(UnicodeStringData) + numCharsNeeded*sizeof(WideChar); int actualBytes = TheDynamicMemoryAllocator->getActualAllocationSize(minBytes); - UnicodeStringData* newData = (UnicodeStringData*)TheDynamicMemoryAllocator->allocateBytesDoNotZero(actualBytes, "STR_UnicodeString::ensureUniqueBufferOfSize"); + void* rawData = TheDynamicMemoryAllocator->allocateBytesDoNotZero(actualBytes, "STR_UnicodeString::ensureUniqueBufferOfSize"); + UnicodeStringData* newData = new(rawData) UnicodeStringData; newData->m_refCount = 1; newData->m_numCharsAllocated = (actualBytes - sizeof(UnicodeStringData))/sizeof(WideChar); @@ -130,17 +129,19 @@ void UnicodeString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveDa // ----------------------------------------------------- void UnicodeString::releaseBuffer() { - ScopedCriticalSection scopedCriticalSection(TheUnicodeStringCriticalSection); - validate(); if (m_data) { - if (--m_data->m_refCount == 0) + UnicodeStringData* oldData = m_data; + m_data = nullptr; + + if (--oldData->m_refCount == 0) { - TheDynamicMemoryAllocator->freeBytes(m_data); + oldData->~UnicodeStringData(); + TheDynamicMemoryAllocator->freeBytes(oldData); } - m_data = nullptr; } + validate(); } // ----------------------------------------------------- @@ -167,15 +168,15 @@ UnicodeString::UnicodeString(const WideChar* s, int len) : m_data(nullptr) // ----------------------------------------------------- void UnicodeString::set(const UnicodeString& stringSrc) { - ScopedCriticalSection scopedCriticalSection(TheUnicodeStringCriticalSection); - validate(); if (&stringSrc != this) { + UnicodeStringData* newData = stringSrc.m_data; + if (newData) + ++newData->m_refCount; + releaseBuffer(); - m_data = stringSrc.m_data; - if (m_data) - ++m_data->m_refCount; + m_data = newData; } validate(); } diff --git a/Generals/Code/GameEngine/Include/Common/CriticalSection.h b/Generals/Code/GameEngine/Include/Common/CriticalSection.h index 125c7daee97..bd28f141836 100644 --- a/Generals/Code/GameEngine/Include/Common/CriticalSection.h +++ b/Generals/Code/GameEngine/Include/Common/CriticalSection.h @@ -94,7 +94,5 @@ class ScopedCriticalSection // These should be null on creation then non-null in WinMain or equivalent. // This allows us to be silently non-threadsafe for WB and other single-threaded apps. -extern CriticalSection *TheAsciiStringCriticalSection; -extern CriticalSection *TheUnicodeStringCriticalSection; extern CriticalSection *TheDmaCriticalSection; extern CriticalSection *TheMemoryPoolCriticalSection; diff --git a/Generals/Code/GameEngine/Source/Common/System/CriticalSection.cpp b/Generals/Code/GameEngine/Source/Common/System/CriticalSection.cpp index de62b21ad85..6044bc9a570 100644 --- a/Generals/Code/GameEngine/Source/Common/System/CriticalSection.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/CriticalSection.cpp @@ -27,8 +27,6 @@ #include "Common/CriticalSection.h" // Definitions. -CriticalSection *TheAsciiStringCriticalSection = nullptr; -CriticalSection *TheUnicodeStringCriticalSection = nullptr; CriticalSection *TheDmaCriticalSection = nullptr; CriticalSection *TheMemoryPoolCriticalSection = nullptr; diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index ff5074470da..9e529a2fa1e 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -767,7 +767,7 @@ static Bool initializeAppWindows( HINSTANCE hInstance, Int nCmdShow, Bool runWin } // Necessary to allow memory managers and such to have useful critical sections -static CriticalSection critSec1, critSec2, critSec3, critSec4; +static CriticalSection critSec3, critSec4; // UnHandledExceptionFilter =================================================== /** Handler for unhandled win32 exceptions. */ @@ -806,8 +806,6 @@ Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, // default in a DevStudio project // - TheAsciiStringCriticalSection = &critSec1; - TheUnicodeStringCriticalSection = &critSec2; TheDmaCriticalSection = &critSec3; TheMemoryPoolCriticalSection = &critSec4; @@ -911,8 +909,6 @@ Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, #ifdef RTS_ENABLE_CRASHDUMP MiniDumper::shutdownMiniDumper(); #endif - TheAsciiStringCriticalSection = nullptr; - TheUnicodeStringCriticalSection = nullptr; TheDmaCriticalSection = nullptr; TheMemoryPoolCriticalSection = nullptr; diff --git a/GeneralsMD/Code/GameEngine/Include/Common/CriticalSection.h b/GeneralsMD/Code/GameEngine/Include/Common/CriticalSection.h index 54e79084087..3651b2be0e2 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/CriticalSection.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/CriticalSection.h @@ -94,7 +94,5 @@ class ScopedCriticalSection // These should be null on creation then non-null in WinMain or equivalent. // This allows us to be silently non-threadsafe for WB and other single-threaded apps. -extern CriticalSection *TheAsciiStringCriticalSection; -extern CriticalSection *TheUnicodeStringCriticalSection; extern CriticalSection *TheDmaCriticalSection; extern CriticalSection *TheMemoryPoolCriticalSection; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/CriticalSection.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/CriticalSection.cpp index 6d7e9125387..253297b1b06 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/CriticalSection.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/CriticalSection.cpp @@ -27,8 +27,6 @@ #include "Common/CriticalSection.h" // Definitions. -CriticalSection *TheAsciiStringCriticalSection = nullptr; -CriticalSection *TheUnicodeStringCriticalSection = nullptr; CriticalSection *TheDmaCriticalSection = nullptr; CriticalSection *TheMemoryPoolCriticalSection = nullptr; diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index 864c5576164..6a16c6585e5 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -769,7 +769,7 @@ static Bool initializeAppWindows( HINSTANCE hInstance, Int nCmdShow, Bool runWin } // Necessary to allow memory managers and such to have useful critical sections -static CriticalSection critSec1, critSec2, critSec3, critSec4; +static CriticalSection critSec3, critSec4; // UnHandledExceptionFilter =================================================== /** Handler for unhandled win32 exceptions. */ @@ -813,8 +813,6 @@ Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, // default in a DevStudio project // - TheAsciiStringCriticalSection = &critSec1; - TheUnicodeStringCriticalSection = &critSec2; TheDmaCriticalSection = &critSec3; TheMemoryPoolCriticalSection = &critSec4; @@ -940,7 +938,6 @@ Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, #ifdef RTS_ENABLE_CRASHDUMP MiniDumper::shutdownMiniDumper(); #endif - TheUnicodeStringCriticalSection = nullptr; TheDmaCriticalSection = nullptr; TheMemoryPoolCriticalSection = nullptr; diff --git a/Tests/Google/Core/GoogleTestMain.cpp b/Tests/Google/Core/GoogleTestMain.cpp index c53d3bf48b2..e328bede416 100644 --- a/Tests/Google/Core/GoogleTestMain.cpp +++ b/Tests/Google/Core/GoogleTestMain.cpp @@ -46,23 +46,17 @@ class EngineCriticalSections public: EngineCriticalSections() { - TheAsciiStringCriticalSection = &m_asciiString; - TheUnicodeStringCriticalSection = &m_unicodeString; TheDmaCriticalSection = &m_dma; TheMemoryPoolCriticalSection = &m_memoryPool; } ~EngineCriticalSections() { - TheAsciiStringCriticalSection = nullptr; - TheUnicodeStringCriticalSection = nullptr; TheDmaCriticalSection = nullptr; TheMemoryPoolCriticalSection = nullptr; } private: - CriticalSection m_asciiString; - CriticalSection m_unicodeString; CriticalSection m_dma; CriticalSection m_memoryPool; };