diff --git a/Include/Aurora/Debug/ErrorStack.hpp b/Include/Aurora/Debug/ErrorStack.hpp index ddbdf47e..0fbacec6 100644 --- a/Include/Aurora/Debug/ErrorStack.hpp +++ b/Include/Aurora/Debug/ErrorStack.hpp @@ -23,7 +23,7 @@ namespace Aurora::Debug AuOptional optOsErrorCode; AuUInt16 uDebugBuildSourceLineHint {}; - AUKN_SYM AuString ToString(); + AUKN_SYM const AuString &ToString(); }; struct ErrorStack @@ -42,7 +42,7 @@ namespace Aurora::Debug return this->HasCaptured() && bool(this->pHead->pNextThreadMesage); } - inline StackTrace *ToStackTrace() + inline AuOptionalToStackTrace() { if (!this->HasCaptured()) { @@ -54,23 +54,43 @@ namespace Aurora::Debug return {}; } - return &this->pHead->optStackTrace.value(); + return this->pHead->optStackTrace.value(); } - inline AuOptional ToString() + inline AuOptional ToString() { - return this->HasCaptured() ? this->pHead->ToString() : AuString {}; + static const AuString kOutOfMemoryString = "Aurora: Out of Memory"; + + if (this->HasCaptured()) + { + return this->pHead->ToString(); + } + else if (this->HasOOMCondition()) + { + return kOutOfMemoryString; + } + else + { + return {}; + } } inline AuSPtr FirstMessage() { return this->pHead; } + + inline bool HasOOMCondition() + { + return this->bOutOfMemory; + } protected: + friend ErrorStackAccessor; + AuSPtr pHead; ErrorStack *pNext {}; - friend ErrorStackAccessor; + bool bOutOfMemory {}; }; } diff --git a/Source/Debug/ErrorStack.cpp b/Source/Debug/ErrorStack.cpp index 244e37c4..b87557a6 100644 --- a/Source/Debug/ErrorStack.cpp +++ b/Source/Debug/ErrorStack.cpp @@ -17,6 +17,9 @@ namespace Aurora::Debug { + static thread_local AuString tlsLastMessageError; + static AuString strFailureCategoryCache[128]; + struct ErrorStackAccessor { void SetNext(ErrorStack *pStack, ErrorStack *pNext) @@ -38,9 +41,14 @@ namespace Aurora::Debug { return pStack->pHead; } + + void SetOOM(ErrorStack *pStack) + { + pStack->bOutOfMemory = true; + } }; - AUKN_SYM AuString ThreadMessage::ToString() + AUKN_SYM const AuString &ThreadMessage::ToString() { if (this->pStringMessage) { @@ -49,12 +57,30 @@ namespace Aurora::Debug if (eFailureCategory) { - return fmt::format("Debug::EFailureCategory = {}", (AuUInt)*eFailureCategory); + auto uIndex = (AuUInt)*eFailureCategory; + + if (AuArraySize(strFailureCategoryCache) <= uIndex) + { + return tlsLastMessageError = fmt::format("Debug::EFailureCategory = {}", (AuUInt)*eFailureCategory); + } + else + { + auto &stringBuffer = strFailureCategoryCache[uIndex]; + + if (stringBuffer.size()) + { + return stringBuffer; + } + else + { + return stringBuffer = fmt::format("Debug::EFailureCategory = {}", (AuUInt)*eFailureCategory); + } + } } if (optOsErrorCode) { - return fmt::format("OS = {}", (AuUInt)*optOsErrorCode); + return tlsLastMessageError = fmt::format("OS = {}", (AuUInt)*optOsErrorCode); } return "Unknown error."; @@ -163,4 +189,20 @@ namespace Aurora::Debug } } } + + void OnOutOfMemory() + { + ErrorStackAccessor dumb; + auto itr = tlsErrorStackBase; + + if (itr) + { + dumb.SetOOM(itr); + while (auto pNext = dumb.GetNext(itr)) + { + dumb.SetOOM(itr); + itr = pNext; + } + } + } } \ No newline at end of file diff --git a/Source/Debug/ErrorStack.hpp b/Source/Debug/ErrorStack.hpp index bf115054..f2e52b84 100644 --- a/Source/Debug/ErrorStack.hpp +++ b/Source/Debug/ErrorStack.hpp @@ -9,6 +9,7 @@ namespace Aurora::Debug { + void OnOutOfMemory(); void PushErrorStackInternal(AuSPtr pMessage); bool ShouldPushErrorStackInternal(); } \ No newline at end of file diff --git a/Source/Memory/Memory.cpp b/Source/Memory/Memory.cpp index 6b9e6064..fced56fc 100644 --- a/Source/Memory/Memory.cpp +++ b/Source/Memory/Memory.cpp @@ -15,6 +15,7 @@ #endif #include +#include namespace Aurora::Memory { @@ -66,11 +67,23 @@ namespace Aurora::Memory } } + static void OnOOM(AuUInt uLength) + { + tlsLastOutOfMemory = AuTime::CurrentClockNS(); + + AuDebug::OnOutOfMemory(); + + if (auto pLowNotification = tlsMemoryLowNotification) + { + pLowNotification(uLength, 4); + } + } + #define CHECK_WRAP_RETURN(exp, exp2, string) \ auto pRet = exp; \ if (!pRet) \ { \ - tlsLastOutOfMemory = AuTime::CurrentClockNS(); \ + OnOOM(length); \ \ bool bCrunchFlag {}; \ if (((bCrunchFlag = AuDebug::IsTlsMemoryCrunchActive()) || \ @@ -165,6 +178,10 @@ namespace Aurora::Memory gLeakFinderAlloc(pRet, uNewSize); } } + else if (buffer && length) + { + OnOOM(length); + } } if (!pRet) @@ -210,6 +227,10 @@ namespace Aurora::Memory gLeakFinderAlloc(pRet, uNewSize); } } + else if (buffer && length) + { + OnOOM(length); + } } if (!pRet) @@ -255,6 +276,10 @@ namespace Aurora::Memory gLeakFinderAlloc(pRet, uNewSize); } } + else if (buffer && length) + { + OnOOM(length); + } } if (!pRet) @@ -300,6 +325,10 @@ namespace Aurora::Memory gLeakFinderAlloc(pRet, uNewSize); } } + else if (buffer && length) + { + OnOOM(length); + } } if (!pRet)