164 lines
3.7 KiB
C++
164 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->spinSemaphore);
|
|
#else
|
|
SignalSafeSleepLockYield(pArrow->spinSemaphore2.AsPointer());
|
|
#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();
|
|
last->spinSemaphore2->Unlock();
|
|
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;
|
|
}
|
|
} |