AuroraRuntime/Source/Grug/AuGrug.cpp
Jamie Reece Wilson 0571aa8dd4 [+] AU_LOCK_GLOBAL_GUARD
[+] AuThreading::GetShutdownReadLock()
2024-09-09 03:46:38 +01:00

264 lines
6.3 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuGrug.cpp
Date: 2022-01-03
File: Flusher.cpp
Date: 2021-8-27
Author: Reece
Note: Grug couples async telemetry, console flushing, and log dispatching
to one lazy working thread w/ high performance thread primitives for
when urgent telemetry events are raised.
***/
#include <Source/RuntimeInternal.hpp>
#include "AuGrug.hpp"
#include <Source/Logging/AuLogger.hpp>
#include <Source/Console/ConsoleFIO/ConsoleFIO.hpp>
#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();
void LinuxSuperSecretFuckGlibc();
#endif
namespace Aurora::Grug
{
static const auto kGrugSleepMs = 300;
static const auto kGrugFlushMs = 600;
static AuThreads::ThreadUnique_t gGrugsBigWorld;
static AuSemaphore gArrows;
static AuBinarySemaphore gArrowsRetarded(false, true, true);
static AuMutex gOtherMutex;
static AuList<AuTuple<AuUInt, bool, bool>> gHandlesToClose;
static AuList<AuThreadPrimitives::IEvent *> gEventsToTrigger;
static void SlowStartupTasks()
{
Console::ConsoleFIO::FIOCleanup();
}
// grug require only 1 strand
static void GrugWorld()
{
// ignorerino
#if defined(AURORA_IS_LINUX_DERIVED)
::LinuxSuperSecretFuckGlibc();
#endif
// grug surive first night
SlowStartupTasks();
// this thread must never encounter an out of memory condition. begin out of memory mitigations.
AuDebug::AddMemoryCrunch();
Utility::RateLimiter limiter;
limiter.SetNextStep(AuMSToNS<AuUInt64>(kGrugFlushMs));
// grug has cave
while (AuIsThreadRunning())
{
// grug anoyd
// grug pump all async log messages
GrugFlushWrites();
// adhd grug wonder around the log pool every 500ms (rate limited to 100ms sleeps)
if (limiter.CheckExchangePass())
{
// poo2loo
GrugFlushFlushs();
}
// grug give up
// grug sleep for 100ms or until poked
if (gArrowsRetarded->TryLock() ||
gArrows->LockMS(kGrugSleepMs))
{
DequeueOneArrow();
}
// grug has to carry stupid platforms
#if defined(AURORA_IS_LINUX_DERIVED)
::LinuxSuperSecretIOTick();
#endif
// grug done
GrugDoIoWork();
}
}
static void DestroyFlushThread()
{
gGrugsBigWorld.reset();
}
static void InitFlushThread()
{
if (gGrugsBigWorld)
{
return;
}
// Startup a runner thread that will take care of all the stress of triggering IO every so often on a remote thread
gGrugsBigWorld = AuMove(AuThreads::Spawn(std::bind(GrugWorld),
false,
{},
"Cave Grug"
));
if (!gGrugsBigWorld)
{
return;
}
// he's a lazy bastard
gGrugsBigWorld->SetThrottle(AuThreads::EThreadThrottle::eEfficient);
gGrugsBigWorld->SetPriority(AuThreads::EThreadPriority::ePrioLow);
}
void InitGrug()
{
InitFlushThread();
}
void DeinitGrug()
{
if (bool(gGrugsBigWorld) && gGrugsBigWorld.get() != AuThreads::GetThread())
{
gGrugsBigWorld.reset();
}
GrugFlushWrites();
GrugFlushFlushs();
DeinitArrows();
}
void NotifyGrugOfTelemetry()
{
gArrows->Unlock(1);
}
void DrachenlordScreech()
{
gArrowsRetarded->Set();
}
bool IsGrug()
{
if (!gGrugsBigWorld) return false;
return AuThreads::GetThread() == gGrugsBigWorld.get();
}
void NotifyGrugOfLogs()
{
if (Grug::IsGrug())
{
Grug::GrugFlushWrites();
}
else
{
Grug::DrachenlordScreech();
}
}
void GrugFlushWrites()
{
Logging::ForceFlushLoggers();
}
void GrugDoIoWork()
{
decltype(gHandlesToClose) toClose;
decltype(gEventsToTrigger) toTrigger;
if (gHandlesToClose.empty() &&
gEventsToTrigger.empty())
{
return;
}
{
AU_LOCK_GLOBAL_GUARD(gOtherMutex);
toClose = AuMove(gHandlesToClose);
toTrigger = AuMove(gEventsToTrigger);
}
for (const auto [uHandle, bFlush, bWriteEoS] : toClose)
{
if (!SysHandleIsNonZero(uHandle))
{
continue;
}
if (bWriteEoS)
{
SysWriteEoS(uHandle);
}
if (bFlush)
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
if (AuIO::IsHandleFile(uHandle))
#endif
{
SysFlushHandle(uHandle);
}
}
SysCloseHandle(uHandle);
}
for (const auto pEvent : toTrigger)
{
pEvent->Set();
}
}
void GrugFlushFlushs()
{
Logging::ForceFlushFlush();
Console::PumpOffMain();
Console::ForceFlush();
GrugDoIoWork();
}
void CloseHandle(AuUInt64 handle, bool bFlush, bool bWriteEoS)
{
{
AU_DEBUG_MEMCRUNCH;
AU_LOCK_GLOBAL_GUARD(gOtherMutex);
gHandlesToClose.push_back(AuMakeTuple(AuUInt(handle), bFlush, bWriteEoS));
}
NotifyGrugOfTelemetry();
}
void WaitForGrugTick()
{
AuEvent event(false, true, true);
if (gGrugsBigWorld &&
gGrugsBigWorld.get() == AuThreads::GetThread())
{
return;
}
{
AU_DEBUG_MEMCRUNCH;
AU_LOCK_GLOBAL_GUARD(gOtherMutex);
gEventsToTrigger.push_back(event.AsPointer());
}
{
NotifyGrugOfTelemetry();
}
event->Lock();
}
}