AuroraRuntime/Source/Grug/AuArrow.cpp

166 lines
3.7 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuArrow.cpp
Date: 2022-02-03
Author: Reece
Note: NIX signal aware telemetry IPC to cave grug
***/
#include <Source/RuntimeInternal.hpp>
#include "AuGrug.hpp"
#include "AuArrow.hpp"
#include <Source/Exit/AuExit.hpp>
namespace Aurora::Grug
{
static AuList<Arrow *> gReservedArrows; // stacks are slower than vectors under msvc, 'twas a qst bottleneck
static AuThreadPrimitives::SpinLock gSpinLock;
static bool gDisableGrugMessages {};
void SignalSafeSleepLockYield(AuThreading::IWaitable *pLock)
{
#if defined(AURORA_IS_POSIX_DERIVED)
while (!pLock->TryLock())
{
sched_yield();
}
#else
pLock->Lock();
#endif
}
void HurlArrow(Arrow *pArrow, GrugReport_f pCallback, GrugReport_f pCallbackRunaway)
{
if (gDisableGrugMessages)
{
return;
}
pArrow->pCallback = pCallback;
pArrow->pCallbackRunaway = pCallbackRunaway;
#if !defined(ARROW_NO_MUTEX)
SignalSafeSleepLockYield(pArrow->spinSemaphore2.AsPointer());
#else
SignalSafeSleepLockYield(&pArrow->spinSemaphore);
#endif
{
SignalSafeSleepLockYield(&gSpinLock);
while (!AuTryInsert(gReservedArrows, pArrow))
{
#if defined(AURORA_IS_POSIX_DERIVED)
sched_yield();
#else
AuThreading::ContextYield();
#endif
}
gSpinLock.Unlock();
}
NotifyGrugOfTelemetry();
}
void ArrowWait(Arrow *arrow)
{
if (gDisableGrugMessages)
{
return;
}
#if defined(ARROW_NO_MUTEX)
AU_LOCK_GUARD(arrow->spinSemaphore);
#else
AU_LOCK_GUARD(arrow->spinSemaphore2);
#endif
}
void ArrowThreadAsyncSafe(Arrow *pArrow)
{
#if defined(ARROW_NO_MUTEX)
SignalSafeSleepLockYield(&pArrow->spinSemaphore);
pArrow->spinSemaphore.Unlock();
#else
SignalSafeSleepLockYield(pArrow->spinSemaphore2.AsPointer());
pArrow->spinSemaphore2->Unlock();
#endif
}
void DequeueOneArrow()
{
AU_LOCK_GUARD(gSpinLock);
if (gReservedArrows.empty())
{
return;
}
auto last = *(gReservedArrows.end() - 1);
if (last->pCallback)
{
try
{
last->pCallback(last);
}
catch (...)
{
}
}
auto lastCallback = last->pCallbackRunaway;
last->spinSemaphore.Unlock();
#if !defined(ARROW_NO_MUTEX)
last->spinSemaphore2->Unlock();
#endif
gReservedArrows.pop_back();
if (lastCallback)
{
try
{
lastCallback(last);
}
catch (...)
{
}
}
}
static void HandleProblematicEvent(Arrow *pArrow)
{
Exit::PostLevel(pArrow->thread.ToThread(), Exit::ETriggerLevel::eProblematicEvent);
}
void HurlRaiseProblematicEvent(Arrow *pArrow)
{
HurlArrow(pArrow, {}, HandleProblematicEvent);
ArrowWait(pArrow); // protect the stack, dont trust the caller
}
static void HandleFatal(Arrow *pArrow)
{
Exit::PostLevel(pArrow->thread.ToThread(), Exit::ETriggerLevel::eFatalException);
}
void HurlFatalEvent(Arrow *pArrow)
{
HurlArrow(pArrow, HandleFatal, {});
ArrowWait(pArrow); // wait until the fatal error has been handled
}
void InitArrows()
{
gReservedArrows.reserve(20);
}
void DeinitArrows()
{
gDisableGrugMessages = true;
}
}