/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Exit.cpp Date: 2022-2-5 Author: Reece ***/ #include #include "Exit.hpp" #include #include "MTWatchDog.hpp" namespace Aurora::Exit { static AuThreadPrimitives::MutexUnique_t gMutex; static AuList, ETriggerLevel>> gTriggerSubscribers; static bool gIsAppRunning {true}; static void DispatchHandlersForThread(AuThreads::IAuroraThread *pThread, ETriggerLevel level) { ExitInvoker invoker; invoker.pCaller = pThread; for (const auto &[sub, subLevel] : gTriggerSubscribers) { if (level == subLevel) { try { sub->OnTrigger(level, &invoker); } catch (...) { // Intentionally left empty. Telemetry hooks will report, if possible. } } } } void PostLevel(AuThreads::IAuroraThread *thread, ETriggerLevel level) { AU_LOCK_GUARD(gMutex); bool isTerminate = level == ETriggerLevel::eSafeTermination; bool isPreempting {}; // Prevent double eSafeTermination if (isTerminate && gHasSentTerminate) { isPreempting = true; } // if (isTerminate || level == ETriggerLevel::eSigTerminate) { gIsAppRunning = false; } // ... if (level == ETriggerLevel::eProblematicEvent) { Grug::NotifyGrugOfLogs(); } else { Grug::GrugFlushWrites(); Grug::GrugFlushFlushs(); } // Has already sent eSafeTermination? if (isPreempting) { return; } // Dispatch DispatchHandlersForThread(thread, level); // ... gHasSentTerminate |= isTerminate; // Force exit after calling the subscribers, should the even level be eSigTerminate if (level == ETriggerLevel::eSigTerminate) { Process::Exit(0); } } AUKN_SYM bool ExitHandlerAdd(ETriggerLevel level, const AuSPtr &callback) { AU_LOCK_GUARD(gMutex); return AuTryInsert(gTriggerSubscribers, AuMakePair(callback, level)); } AUKN_SYM void ExitHandlerRemove(const AuSPtr &callback) { AU_LOCK_GUARD(gMutex); AuRemoveAllIf(gTriggerSubscribers, [=](const auto &entry) -> bool { return AuGet<0>(entry) == callback; }); } AUKN_SYM bool IsAppRunning() { return gIsAppRunning; } void InitExit() { gMutex = AuThreadPrimitives::MutexUnique(); InitWatchdog(); } void DeinitExit() { gMutex.reset(); } }