[+] Added AuDebug::MemoryCrunch implementation under debug and memory
This commit is contained in:
parent
7be2d3fbdc
commit
1f1d1bbc28
@ -8,7 +8,7 @@
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Debug.hpp"
|
||||
#include <Source/Telemetry/Telemetry.hpp>
|
||||
|
||||
#include "MemoryCrunch.hpp"
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#include "ExceptionWatcher.NT.hpp"
|
||||
#include "ExceptionWatcher.Win32.hpp"
|
||||
@ -447,6 +447,8 @@ namespace Aurora::Debug
|
||||
|
||||
void InitDebug()
|
||||
{
|
||||
InitMemoryCrunch();
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
InitWin32();
|
||||
#endif
|
||||
@ -455,14 +457,4 @@ namespace Aurora::Debug
|
||||
InitNT();
|
||||
#endif
|
||||
}
|
||||
|
||||
AUKN_SYM void AddMemoryCrunch()
|
||||
{
|
||||
// TODO: ...
|
||||
}
|
||||
|
||||
AUKN_SYM void DecMemoryCrunch()
|
||||
{
|
||||
// TODO: ...
|
||||
}
|
||||
}
|
@ -225,17 +225,23 @@ namespace Aurora::Debug
|
||||
}
|
||||
}
|
||||
|
||||
#include "MemoryCrunch.hpp"
|
||||
|
||||
static thread_local AuUInt tlsThrowCounter;
|
||||
|
||||
extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *throwInfo, void *caller)
|
||||
{
|
||||
AuDebug::AddMemoryCrunch();
|
||||
|
||||
if (!throwInfo)
|
||||
{
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!exception)
|
||||
{
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -245,19 +251,22 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t
|
||||
{
|
||||
if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCSTR>(caller), reinterpret_cast<HMODULE *>(&handle)))
|
||||
{
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
|
||||
// we will probably overflow for a bit if an inner try catch borks up somewhere
|
||||
if ((tlsThrowCounter++) == 7)
|
||||
if ((tlsThrowCounter++) == 7) // TODO: this might be stupid. we should configure for panic on second
|
||||
{
|
||||
tlsThrowCounter--;
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -287,4 +296,5 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t
|
||||
|
||||
Aurora::Exit::PostLevel(AuThreads::GetThread(), Aurora::Exit::ETriggerLevel::eProblematicEvent);
|
||||
tlsThrowCounter--;
|
||||
AuDebug::DecMemoryCrunch();
|
||||
}
|
58
Source/Debug/MemoryCrunch.cpp
Normal file
58
Source/Debug/MemoryCrunch.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: MemoryCrunch.cpp
|
||||
Date: 2022-12-07
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Debug.hpp"
|
||||
#include "ErrorStack.hpp"
|
||||
#include <Source/Memory/Heap.hpp>
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
static thread_local AuSInt tlsMemoryCrunchCounter;
|
||||
static auto const kAutoReservePool = 3 * 1024 * 1024;
|
||||
|
||||
AuUInt8 *gReservePoolStart {};
|
||||
AuUInt8 *gReservePoolEnd {};
|
||||
AuSPtr<AuMemory::Heap> gReserveHeap {};
|
||||
|
||||
void InitMemoryCrunch()
|
||||
{
|
||||
gReserveHeap = AuMemory::AllocHeapShared(kAutoReservePool);
|
||||
SysAssert(gReserveHeap);
|
||||
|
||||
auto pHeap = AuStaticCast<AuMemory::BaseHeap>(gReserveHeap);
|
||||
gReservePoolStart = AuReinterpretCast<AuUInt8 *>(pHeap->base_);
|
||||
gReservePoolEnd = AuReinterpretCast<AuUInt8 *>(pHeap->base_) + pHeap->length_;
|
||||
}
|
||||
|
||||
bool IsPointerReserveRange(void *ptr)
|
||||
{
|
||||
auto pChar = (AuUInt8 *)ptr;
|
||||
return pChar >= gReservePoolStart && pChar < gReservePoolEnd;
|
||||
}
|
||||
|
||||
AuSPtr<AuMemory::Heap> GetCrunchInterface()
|
||||
{
|
||||
return gReserveHeap;
|
||||
}
|
||||
|
||||
bool IsTlsMemoryCrunchActive()
|
||||
{
|
||||
return bool(tlsMemoryCrunchCounter);
|
||||
}
|
||||
|
||||
AUKN_SYM void AddMemoryCrunch()
|
||||
{
|
||||
tlsMemoryCrunchCounter++;
|
||||
}
|
||||
|
||||
AUKN_SYM void DecMemoryCrunch()
|
||||
{
|
||||
tlsMemoryCrunchCounter--;
|
||||
SysAssert(tlsMemoryCrunchCounter >= 0, "crunch counter underflow");
|
||||
}
|
||||
}
|
19
Source/Debug/MemoryCrunch.hpp
Normal file
19
Source/Debug/MemoryCrunch.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: MemoryCrunch.hpp
|
||||
Date: 2022-12-07
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
extern AuUInt8 *gReservePoolStart;
|
||||
extern AuUInt8 *gReservePoolEnd;
|
||||
extern AuSPtr<AuMemory::Heap> gReserveHeap;
|
||||
|
||||
bool IsPointerReserveRange(void *ptr);
|
||||
void InitMemoryCrunch();
|
||||
bool IsTlsMemoryCrunchActive();
|
||||
}
|
@ -14,6 +14,8 @@
|
||||
#include "AuExit.Unix.hpp"
|
||||
#endif
|
||||
|
||||
#include <Source/Debug/MemoryCrunch.hpp>
|
||||
|
||||
namespace Aurora::Exit
|
||||
{
|
||||
static AuThreadPrimitives::MutexUnique_t gMutex;
|
||||
@ -46,6 +48,7 @@ namespace Aurora::Exit
|
||||
{
|
||||
bool bOldTerminatingValue;
|
||||
|
||||
AuDebug::AddMemoryCrunch();
|
||||
{
|
||||
AU_LOCK_GUARD(gMutex);
|
||||
|
||||
@ -72,6 +75,7 @@ namespace Aurora::Exit
|
||||
{
|
||||
if (AuAtomicTestAndSet(&gProblemCounter, 1))
|
||||
{
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -98,6 +102,7 @@ namespace Aurora::Exit
|
||||
// Has already sent eSafeTermination?
|
||||
if (isPreempting)
|
||||
{
|
||||
AuDebug::DecMemoryCrunch();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -118,6 +123,7 @@ namespace Aurora::Exit
|
||||
Process::Exit(0);
|
||||
}
|
||||
}
|
||||
AuDebug::DecMemoryCrunch();
|
||||
}
|
||||
|
||||
AUKN_SYM bool ExitHandlerAdd(ETriggerLevel level, const AuSPtr<IExitSubscriber> &callback)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include <Source/Console/Flusher.hpp>
|
||||
#include <Source/Console/Console.hpp>
|
||||
#include <Source/Debug/MemoryCrunch.hpp>
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
void LinuxSuperSecretIOTick();
|
||||
@ -51,6 +52,8 @@ namespace Aurora::Grug
|
||||
|
||||
AU_LOCK_GUARD(gMutex);
|
||||
|
||||
AuDebug::AddMemoryCrunch(); // this thread must never encounter an out of memory condition. begin out of memory mitigations.
|
||||
|
||||
Utility::RateLimiter limiter;
|
||||
limiter.SetNextStep(kGrugFlushMs);
|
||||
|
||||
|
@ -53,11 +53,11 @@ namespace Aurora::Memory
|
||||
#endif
|
||||
}
|
||||
|
||||
struct InternalHeap : Heap, AuEnableSharedFromThis<InternalHeap>
|
||||
struct InternalHeap : BaseHeap, AuEnableSharedFromThis<InternalHeap>
|
||||
{
|
||||
virtual AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment) override;
|
||||
|
||||
InternalHeap() : base_(nullptr), mutex_(nullptr), heap_(nullptr), count_(0)
|
||||
InternalHeap() : mutex_(nullptr), heap_(nullptr), count_(0)
|
||||
{ }
|
||||
|
||||
virtual ~InternalHeap();
|
||||
@ -96,11 +96,11 @@ namespace Aurora::Memory
|
||||
void RequestTermination();
|
||||
|
||||
private:
|
||||
|
||||
AuThreadPrimitives::MutexUnique_t mutex_;
|
||||
void *base_ {};
|
||||
|
||||
O1HeapInstance *heap_ {};
|
||||
int count_ {};
|
||||
AuUInt length_ {};
|
||||
bool isDangling_ {};
|
||||
};
|
||||
|
||||
|
@ -9,5 +9,11 @@
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct BaseHeap : Heap
|
||||
{
|
||||
void *base_ {};
|
||||
AuUInt length_ {};
|
||||
};
|
||||
|
||||
AuSPtr<Heap> AllocateDivisionGlobal(Heap *heap, AuUInt32 length, AuUInt32 alignment);
|
||||
}
|
@ -14,64 +14,151 @@
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <Source/Debug/MemoryCrunch.hpp>
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
AUKN_SYM AuUInt GetChunkSize(const void *head)
|
||||
{
|
||||
return mi_malloc_size(head);
|
||||
if (AuDebug::IsPointerReserveRange((void *)head))
|
||||
{
|
||||
return AuDebug::gReserveHeap->GetChunkSize(head);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::mi_malloc_size(head);
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_WRAP_RETURN(exp, string) \
|
||||
auto pRet = exp; \
|
||||
if (!pRet && gRuntimeConfig.debug.bIsMemoryErrorFatal) \
|
||||
{ \
|
||||
SysPanic(string); \
|
||||
} \
|
||||
#define CHECK_WRAP_RETURN(exp, exp2, string) \
|
||||
auto pRet = exp; \
|
||||
if (!pRet) \
|
||||
{ \
|
||||
if (AuDebug::IsTlsMemoryCrunchActive() && AuDebug::gReserveHeap) \
|
||||
{ \
|
||||
return AuDebug::gReserveHeap-> AU_WHAT exp2; \
|
||||
} \
|
||||
else if (gRuntimeConfig.debug.bIsMemoryErrorFatal) \
|
||||
{ \
|
||||
SysPanic(string); \
|
||||
} \
|
||||
} \
|
||||
return pRet;
|
||||
|
||||
AUKN_SYM void *_ZAlloc(Types::size_t length)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_zalloc(length), "ZAlloc out of memory");
|
||||
CHECK_WRAP_RETURN(::mi_zalloc(length), (ZAlloc(length)), "ZAlloc out of memory");
|
||||
}
|
||||
|
||||
AUKN_SYM void *_ZAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_zalloc_aligned(length, align), "ZAlloc out of memory");
|
||||
CHECK_WRAP_RETURN(::mi_zalloc_aligned(length, align), (ZAlloc(length, align)), "ZAlloc out of memory");
|
||||
}
|
||||
|
||||
AUKN_SYM void *_FAlloc(Types::size_t length)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_malloc(length), "FAlloc out of memory");
|
||||
CHECK_WRAP_RETURN(::mi_malloc(length), (FAlloc(length)), "FAlloc out of memory");
|
||||
}
|
||||
|
||||
AUKN_SYM void *_FAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_malloc_aligned(length, align), "FAlloc out of memory");
|
||||
CHECK_WRAP_RETURN(::mi_malloc_aligned(length, align), (FAlloc(length, align)), "FAllocEx out of memory");
|
||||
}
|
||||
|
||||
AUKN_SYM void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_rezalloc_aligned(buffer, length, align), "ZAlloc out of memory");
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
return AuDebug::gReserveHeap->ZRealloc(buffer, length, align);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pRet = ::mi_rezalloc_aligned(buffer, length, align);
|
||||
if (!pRet)
|
||||
{
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("ZAllocEx out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM void *_ZRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_rezalloc(buffer, length), "ZAlloc out of memory");
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
return AuDebug::gReserveHeap->ZRealloc(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pRet = ::mi_rezalloc(buffer, length);
|
||||
if (!pRet)
|
||||
{
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("ZAlloc out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_realloc_aligned(buffer, length, align), "MAlloc out of memory");
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
return AuDebug::gReserveHeap->FRealloc(buffer, length, align);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pRet = ::mi_realloc_aligned(buffer, length, align);
|
||||
if (!pRet)
|
||||
{
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("FReallocEx out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM void *_FRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
CHECK_WRAP_RETURN(mi_realloc(buffer, length), "MAlloc out of memory");
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
return AuDebug::gReserveHeap->FRealloc(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pRet = ::mi_realloc(buffer, length);
|
||||
if (!pRet)
|
||||
{
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("FRealloc out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM void _Free(void *buffer)
|
||||
{
|
||||
mi_free(buffer);
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
AuDebug::gReserveHeap->Free(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
::mi_free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt GetPageSize()
|
||||
|
Loading…
Reference in New Issue
Block a user