AuroraRuntime/Source/Grug/Arrow.cpp
J Reece Wilson d81d4564e9 [+] Initial Linux exit signal handler
[*] Linux Semaphore bug (apparently I can't write loops)
[*] Linux sleep bug
2022-04-07 05:35:17 +01:00

134 lines
3.0 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Arrow.cpp
Date: 2022-02-03
Author: Reece
Note: NIX signal aware telemetry IPC to cave grug
***/
#include <Source/RuntimeInternal.hpp>
#include "Grug.hpp"
#include "Arrow.hpp"
#include <Source/Exit/Exit.hpp>
namespace Aurora::Grug
{
static AuList<Arrow *> gReservedArrows; // stacks are slower than vectors under msvc, 'twas a qst bottleneck
static AuThreadPrimitives::SpinLock gSpinLock;
void SignalSafeSleepLockYield(AuThreadPrimitives::SpinLock &lock)
{
#if defined(AURORA_IS_POSIX_DERIVED)
while (!lock.TryLock())
{
sched_yield();
}
#else
lock.Lock();
#endif
}
void HurlArrow(Arrow *pArrow, GrugReport_f pCallback, GrugReport_f pCallbackRunaway)
{
pArrow->pCallback = pCallback;
pArrow->pCallbackRunaway = pCallbackRunaway;
SignalSafeSleepLockYield(pArrow->spinSemaphore);
{
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)
{
AU_LOCK_GUARD(arrow->spinSemaphore);
}
void ArrowThreadAsyncSafe(Arrow *pArrow)
{
SignalSafeSleepLockYield(pArrow->spinSemaphore);
pArrow->spinSemaphore.Unlock();
}
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();
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);
}
}