diff --git a/Include/Aurora/Async/Async.hpp b/Include/Aurora/Async/Async.hpp index 62b75dd5..b2b51bb7 100644 --- a/Include/Aurora/Async/Async.hpp +++ b/Include/Aurora/Async/Async.hpp @@ -26,16 +26,23 @@ namespace Aurora::Async AUKN_SYM WorkerPId_t GetCurrentWorkerPId(); /// Async app only | Thread pools must use the IThreadPool::NewFence function - AUKN_SYM AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task, bool supportsBlocking = false); + AUKN_SYM AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task); /** * @brief Creates an asynchronous job object to be executed on an async runner * @param worker A worker id pair. Supports AuAsync::kThreadIdAny to run on any runner within the group. * @param task An interface to run the job/work/task in question - * @param supportsBlocking Optimization hint for IWorkItem::BlockUntilComplete() * @return */ - AUKN_SYM AuSPtr NewWorkItem(const WorkerPId_t &worker, const AuSPtr &task, bool supportsBlocking = false); + AUKN_SYM AuSPtr NewWorkItem(const WorkerPId_t &worker, const AuSPtr &task); + + /** + * @brief + * @param worker + * @param func + * @return + */ + AUKN_SYM AuSPtr NewWorkFunction(const WorkerPId_t &worker, AuVoidFunc func); /// Async app only | Thread pools must use the IThreadPool::NewFence function AUKN_SYM AuSPtr NewFence(); diff --git a/Include/Aurora/Async/AuFutures.hpp b/Include/Aurora/Async/AuFutures.hpp index ac336279..4a3e7108 100644 --- a/Include/Aurora/Async/AuFutures.hpp +++ b/Include/Aurora/Async/AuFutures.hpp @@ -157,26 +157,20 @@ public: static AuSPtr> New() { - AuDebug::AddMemoryCrunch(); - auto pRet = AuSPtr>(new AuFuture(), AuDefaultDeleter> {}); - AuDebug::DecMemoryCrunch(); - return pRet; + AU_DEBUG_MEMCRUNCH; + return AuSPtr>(new AuFuture(), AuDefaultDeleter> {}); } static AuSPtr> New(AuConsumer callback) { - AuDebug::AddMemoryCrunch(); - auto pRet = AuSPtr>(new AuFuture(callback), AuDefaultDeleter> {}); - AuDebug::DecMemoryCrunch(); - return pRet; + AU_DEBUG_MEMCRUNCH; + return AuSPtr>(new AuFuture(callback), AuDefaultDeleter> {}); } static AuSPtr> New(AuConsumer callback, ErrorCallback_f onFailure) { - AuDebug::AddMemoryCrunch(); - auto pRet = AuSPtr>(new AuFuture(callback, onFailure), AuDefaultDeleter> {}); - AuDebug::DecMemoryCrunch(); - return pRet; + AU_DEBUG_MEMCRUNCH; + return AuSPtr>(new AuFuture(callback, onFailure), AuDefaultDeleter> {}); } protected: @@ -271,13 +265,11 @@ private: return; } - AuDebug::AddMemoryCrunch(); AuAsync::NewWorkItem(this->pid.value(), AuMakeSharedPanic([pThat = this->SharedFromThis()] { AU_LOCK_GUARD(pThat->mutex); pThat->SubmitComplete(); }))->Dispatch(); - AuDebug::DecMemoryCrunch(); } } diff --git a/Include/Aurora/Async/IThreadPool.hpp b/Include/Aurora/Async/IThreadPool.hpp index 876a1c75..197c554b 100644 --- a/Include/Aurora/Async/IThreadPool.hpp +++ b/Include/Aurora/Async/IThreadPool.hpp @@ -74,8 +74,10 @@ namespace Aurora::Async // virtual AuSPtr NewWorkItem(const WorkerId_t &worker, - const AuSPtr &task, - bool bSupportsBlocking = false) = 0; + const AuSPtr &task) = 0; + + virtual AuSPtr NewWorkFunction(const WorkerId_t &worker, + AuVoidFunc callback) = 0; virtual AuSPtr NewFence() = 0; diff --git a/Include/Aurora/Debug/Debug.hpp b/Include/Aurora/Debug/Debug.hpp index ac3255c8..6bfd675b 100644 --- a/Include/Aurora/Debug/Debug.hpp +++ b/Include/Aurora/Debug/Debug.hpp @@ -83,15 +83,13 @@ namespace Aurora::Debug AUKN_SYM AuResult DemangleName(const AuString &pName); AUKN_SYM void DebugBreak(); - - AUKN_SYM void AddMemoryCrunch(); - AUKN_SYM void DecMemoryCrunch(); } #include "SysErrors.hpp" #include "SysPanic.hpp" #include "SysAssertions.hpp" #include "ErrorStack.hpp" +#include "MemoryCrunch.hpp" struct AuDbgStringSharedException : AuStringException { diff --git a/Include/Aurora/Debug/MemoryCrunch.hpp b/Include/Aurora/Debug/MemoryCrunch.hpp new file mode 100644 index 00000000..c486e445 --- /dev/null +++ b/Include/Aurora/Debug/MemoryCrunch.hpp @@ -0,0 +1,29 @@ +/*** + Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: MemoryCrunch.hpp + Date: 2021-6-9 - 2023-10-08 + Author: Reece +***/ +#pragma once + +namespace Aurora::Debug +{ + AUKN_SYM void AddMemoryCrunch(); + AUKN_SYM void DecMemoryCrunch(); + + struct MemoryCrunch + { + inline MemoryCrunch() + { + AddMemoryCrunch(); + } + + inline ~MemoryCrunch() + { + DecMemoryCrunch(); + } + }; + +#define AU_DEBUG_MEMCRUNCH Aurora::Debug::MemoryCrunch AU_CONCAT(__crunch, __COUNTER__); +} \ No newline at end of file diff --git a/Include/Aurora/Logging/Logging.hpp b/Include/Aurora/Logging/Logging.hpp index e1e1cc89..1c9ed7d9 100644 --- a/Include/Aurora/Logging/Logging.hpp +++ b/Include/Aurora/Logging/Logging.hpp @@ -17,11 +17,7 @@ #include "Sinks.hpp" #include "LogClasses.hpp" -namespace Aurora::Debug -{ - AUKN_SYM void AddMemoryCrunch(); - AUKN_SYM void DecMemoryCrunch(); -} +#include namespace Aurora::Logging { @@ -41,35 +37,31 @@ namespace Aurora::Logging template inline void WriteLinef(AuUInt8 level, const AuString &tag, const Line_t &msg, T&& ... args) { - Aurora::Debug::AddMemoryCrunch(); + AU_DEBUG_MEMCRUNCH; + try { WriteLine(level, ConsoleMessage(EAnsiColor::eReset, tag, fmt::format(msg, AuForward(args)...))); } catch (...) { - Aurora::Debug::DecMemoryCrunch(); throw; - return; } - Aurora::Debug::DecMemoryCrunch(); } template inline void WriteLinef(AuUInt8 level, EAnsiColor color, const AuString &tag, const Line_t &msg, T&& ... args) { - Aurora::Debug::AddMemoryCrunch(); + AU_DEBUG_MEMCRUNCH; + try { WriteLine(level, ConsoleMessage(color, tag, fmt::format(msg, AuForward(args)...))); } catch (...) - { - Aurora::Debug::DecMemoryCrunch(); + {; throw; - return; } - Aurora::Debug::DecMemoryCrunch(); } template diff --git a/Source/Async/AsyncApp.cpp b/Source/Async/AsyncApp.cpp index 63ba2c3a..bfcf89f6 100644 --- a/Source/Async/AsyncApp.cpp +++ b/Source/Async/AsyncApp.cpp @@ -138,9 +138,14 @@ namespace Aurora::Async return ThreadPool::Exiting(); } - AuSPtr AsyncApp::NewWorkItem(const WorkerId_t &worker, const AuSPtr &task, bool supportsBlocking) + AuSPtr AsyncApp::NewWorkItem(const WorkerId_t &worker, const AuSPtr &task) { - return ThreadPool::NewWorkItem(worker, task, supportsBlocking); + return ThreadPool::NewWorkItem(worker, task); + } + + AuSPtr AsyncApp::NewWorkFunction(const WorkerId_t &worker, AuVoidFunc callback) + { + return ThreadPool::NewWorkFunction(worker, callback); } AuSPtr AsyncApp::NewFence() diff --git a/Source/Async/AsyncApp.hpp b/Source/Async/AsyncApp.hpp index 3c150688..a98bf112 100644 --- a/Source/Async/AsyncApp.hpp +++ b/Source/Async/AsyncApp.hpp @@ -29,7 +29,8 @@ namespace Aurora::Async bool Exiting() override; AuUInt32 PollAndCount(bool bStrict = true) override; AuUInt32 RunAllPending() override; - AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task, bool supportsBlocking) override; + AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task) override; + AuSPtr NewWorkFunction(const WorkerId_t &worker, AuVoidFunc callback) override; AuSPtr NewFence() override; Threading::Threads::ThreadShared_t ResolveHandle(WorkerId_t) override; AuBST> GetThreads() override; diff --git a/Source/Async/Schedular.cpp b/Source/Async/Schedular.cpp index de089708..def3cdda 100644 --- a/Source/Async/Schedular.cpp +++ b/Source/Async/Schedular.cpp @@ -242,12 +242,13 @@ namespace Aurora::Async gThread->Run(); } - + bool Schedule(AuUInt64 ns, IThreadPoolInternal *pool, WorkerId_t target, AuSPtr runnable) { AU_LOCK_GUARD(gSchedLock); + AU_DEBUG_MEMCRUNCH; AuAtomicAdd(&pool->uAtomicCounter, 1u); SchedNextTime(ns); return AuTryInsert(gOrderedEntries, diff --git a/Source/Async/ThreadPool.cpp b/Source/Async/ThreadPool.cpp index ffe16fe2..008d1252 100644 --- a/Source/Async/ThreadPool.cpp +++ b/Source/Async/ThreadPool.cpp @@ -136,7 +136,7 @@ namespace Aurora::Async return; } - AuDebug::AddMemoryCrunch(); + AU_DEBUG_MEMCRUNCH; if (bIncrement) { @@ -156,8 +156,6 @@ namespace Aurora::Async pWorker->cvVariable->Signal(); pWorker->eventLs->Set(); } - - AuDebug::DecMemoryCrunch(); } IThreadPool *ThreadPool::ToThreadPool() @@ -775,8 +773,7 @@ namespace Aurora::Async } AuSPtr ThreadPool::NewWorkItem(const WorkerId_t &worker, - const AuSPtr &task, - bool bSupportsBlocking) + const AuSPtr &task) { // Error pass-through if (!task) @@ -784,12 +781,20 @@ namespace Aurora::Async return {}; } - return AuMakeShared(this, WorkerPId_t { AuAsync::GetCurrentWorkerPId().pool, worker }, task, bSupportsBlocking); + return AuMakeShared(this, WorkerPId_t { this->SharedFromThis(), worker }, task); } + AuSPtr ThreadPool::NewWorkFunction(const WorkerId_t &worker, + AuVoidFunc callback) + + { + SysAssert(callback); + return AuMakeShared(this, WorkerPId_t { this->SharedFromThis(), worker }, AuMove(callback)); + } + AuSPtr ThreadPool::NewFence() { - return AuMakeShared(this, AuAsync::GetCurrentWorkerPId(), AuSPtr{}, true); + return AuMakeShared(this, AuAsync::GetCurrentWorkerPId(), AuSPtr{}); } AuThreads::ThreadShared_t ThreadPool::ResolveHandle(WorkerId_t id) @@ -920,7 +925,7 @@ namespace Aurora::Async pFeature->Init(); })); - auto pWorkItem = this->NewWorkItem(id, work, !bNonBlock)->Dispatch(); + auto pWorkItem = this->NewWorkItem(id, work)->Dispatch(); SysAssert(pWorkItem); if (!bNonBlock) diff --git a/Source/Async/ThreadPool.hpp b/Source/Async/ThreadPool.hpp index db83702c..216f51dd 100644 --- a/Source/Async/ThreadPool.hpp +++ b/Source/Async/ThreadPool.hpp @@ -57,7 +57,8 @@ namespace Aurora::Async virtual AuUInt32 PollAndCount(bool bStrict = true) override; virtual AuUInt32 RunAllPending() override; - virtual AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task, bool supportsBlocking) override; + virtual AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task) override; + virtual AuSPtr NewWorkFunction(const WorkerId_t &worker, AuVoidFunc callback) override; virtual AuSPtr NewFence() override; virtual Threading::Threads::ThreadShared_t ResolveHandle(WorkerId_t) override; diff --git a/Source/Async/WorkItem.cpp b/Source/Async/WorkItem.cpp index d58e670c..42075e95 100644 --- a/Source/Async/WorkItem.cpp +++ b/Source/Async/WorkItem.cpp @@ -13,10 +13,18 @@ namespace Aurora::Async { + FuncWorker::FuncWorker(IThreadPoolInternal *owner, + const WorkerPId_t &worker, + AuVoidFunc &&func) : + WorkItem(owner, worker, {}), + func(func) + { + + } + WorkItem::WorkItem(IThreadPoolInternal *owner, const WorkerPId_t &worker, - const AuSPtr &task, - bool bSupportsBlocking) : + const AuSPtr &task) : worker_(worker), task_(task), owner_(owner), finishedEvent_(false, true, true) { @@ -250,15 +258,11 @@ namespace Aurora::Async Fail(); } - void WorkItem::RunAsyncLocked2() + void WorkItem::DispatchTask(IWorkItemHandler::ProcessInfo &info) { - AU_LOCK_GUARD(this->lock2); - - IWorkItemHandler::ProcessInfo info(true); - info.pool = this->owner_->ToThreadPool(); - if (this->task_) { + try { this->task_->DispatchFrame(info); @@ -271,7 +275,17 @@ namespace Aurora::Async return; } } + } + void WorkItem::RunAsyncLocked2() + { + AU_LOCK_GUARD(this->lock2); + + IWorkItemHandler::ProcessInfo info(true); + info.pool = this->owner_->ToThreadPool(); + + DispatchTask(info); + RunAsyncLocked2(info); } @@ -448,37 +462,68 @@ namespace Aurora::Async return AuStaticPointerCast(pool); } - AUKN_SYM AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task, bool supportsBlocking) + void FuncWorker::DispatchTask(IWorkItemHandler::ProcessInfo &info) { + if (func) + { + func(); + } + } + + AUKN_SYM AuSPtr NewWorkItem(const WorkerId_t &worker, const AuSPtr &task) + { + AU_DEBUG_MEMCRUNCH; + if (!task) { SysPushErrorArg("WorkItem has null task. Running out of memory?"); return {}; } - return AuMakeShared(GetWorkerInternal(), WorkerPId_t { AuAsync::GetCurrentWorkerPId().pool, worker }, task, supportsBlocking); + return AuMakeShared(GetWorkerInternal(), WorkerPId_t { AuAsync::GetCurrentWorkerPId().pool, worker }, task); } - AUKN_SYM AuSPtr NewWorkItem(const WorkerPId_t &worker, const AuSPtr &task, bool supportsBlocking) + AUKN_SYM AuSPtr NewWorkFunction(const WorkerPId_t &worker, AuVoidFunc func) { + AU_DEBUG_MEMCRUNCH; + + if (!func) + { + SysPushErrorArg("WorkItem has null function"); + return {}; + } + + if (!worker) + { + SysPushErrorArg("invalid worker"); + return {}; + } + + return AuMakeSharedThrow(GetWorkerInternal(worker.pool).get(), worker, AuMove(func)); + } + + AUKN_SYM AuSPtr NewWorkItem(const WorkerPId_t &worker, const AuSPtr &task) + { + AU_DEBUG_MEMCRUNCH; + if (!task) { SysPushErrorArg("WorkItem has null task. Running out of memory?"); return {}; } - if (!worker.pool) + if (!worker) { - SysPushErrorArg("WorkItem has null pool"); + SysPushErrorArg("invalid worker"); return {}; } - return AuMakeShared(GetWorkerInternal(worker.pool).get(), worker, task, supportsBlocking); + return AuMakeSharedThrow(GetWorkerInternal(worker.pool).get(), worker, task); } AUKN_SYM AuSPtr NewFence() { - return AuMakeShared(GetWorkerInternal(), AuAsync::GetCurrentWorkerPId(), AuSPtr{}, true); + return AuMakeShared(GetWorkerInternal(), AuAsync::GetCurrentWorkerPId(), AuSPtr{}); } void *WorkItem::GetPrivateData() diff --git a/Source/Async/WorkItem.hpp b/Source/Async/WorkItem.hpp index e8f55a11..b188af0a 100644 --- a/Source/Async/WorkItem.hpp +++ b/Source/Async/WorkItem.hpp @@ -18,8 +18,7 @@ namespace Aurora::Async { WorkItem(IThreadPoolInternal *owner, const WorkerPId_t &worker, - const AuSPtr &task, - bool bSupportsBlocking); + const AuSPtr &task); ~WorkItem(); AuSPtr WaitFor(const AuSPtr &workItem) override; @@ -60,6 +59,8 @@ namespace Aurora::Async void DispatchEx(bool check); void DispatchExLocked(bool check); + virtual void DispatchTask(IWorkItemHandler::ProcessInfo &info); + AuSPtr task_; WorkerPId_t worker_; EWorkPrio prio_ = EWorkPrio::eNormalPrio; @@ -80,4 +81,16 @@ namespace Aurora::Async bool Schedule(); void SendOff(); }; + + struct FuncWorker : WorkItem + { + FuncWorker(IThreadPoolInternal *owner, + const WorkerPId_t &worker, + AuVoidFunc &&func); + + void DispatchTask(IWorkItemHandler::ProcessInfo &info) override; + + private: + AuVoidFunc func; + }; } \ No newline at end of file diff --git a/Source/Console/Commands/Commands.cpp b/Source/Console/Commands/Commands.cpp index a5cc1285..37f11223 100644 --- a/Source/Console/Commands/Commands.cpp +++ b/Source/Console/Commands/Commands.cpp @@ -105,15 +105,10 @@ namespace Aurora::Console::Commands } else { - Async::DispatchWork(workerId, - Async::TaskFromConsumerRefT([](const CommandDispatch &dispatch) -> void - { - dispatch.callback->OnCommand(dispatch.arguments); - }), - {}, - CommandDispatch(res.result, callback), - false - ); + Async::NewWorkFunction(workerId, [=]() -> void + { + callback->OnCommand(res.result); + }); } return true; @@ -186,7 +181,7 @@ namespace Aurora::Console::Commands } else { - NewWorkItem(gCommandDispatcher, AuMakeShared(func), true)->Dispatch()->BlockUntilComplete(); + NewWorkItem(gCommandDispatcher, AuMakeShared(func))->Dispatch()->BlockUntilComplete(); } } diff --git a/Source/Debug/Debug.cpp b/Source/Debug/Debug.cpp index 79638e23..a52aa987 100644 --- a/Source/Debug/Debug.cpp +++ b/Source/Debug/Debug.cpp @@ -372,7 +372,8 @@ namespace Aurora::Debug AUKN_SYM AuString StackTraceEntry::Stringify() const { - AddMemoryCrunch(); + AU_DEBUG_MEMCRUNCH; + const auto frame = *this; AuString backTraceBuffer; @@ -418,19 +419,18 @@ namespace Aurora::Debug backTraceBuffer += "\t\t[proprietary]\n"; } - DecMemoryCrunch(); return backTraceBuffer; } catch (...) { - DecMemoryCrunch(); return {}; } } AUKN_SYM AuString StringifyStackTrace(const StackTrace &backtrace) { - AddMemoryCrunch(); + AU_DEBUG_MEMCRUNCH; + AuString backTraceBuffer; try @@ -445,12 +445,10 @@ namespace Aurora::Debug backTraceBuffer += frame.Stringify(); } - DecMemoryCrunch(); return backTraceBuffer; } catch (...) { - DecMemoryCrunch(); return {}; } } diff --git a/Source/Debug/ExceptionWatcher.NT.cpp b/Source/Debug/ExceptionWatcher.NT.cpp index f7e93d53..1fd02dd8 100644 --- a/Source/Debug/ExceptionWatcher.NT.cpp +++ b/Source/Debug/ExceptionWatcher.NT.cpp @@ -266,17 +266,15 @@ static thread_local AuUInt tlsThrowCounter; extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *throwInfo, void *caller) { - AuDebug::AddMemoryCrunch(); + AU_DEBUG_MEMCRUNCH; if (!throwInfo) { - AuDebug::DecMemoryCrunch(); return; } if (!exception) { - AuDebug::DecMemoryCrunch(); return; } @@ -286,14 +284,12 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t { if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(caller), reinterpret_cast(&handle))) { - AuDebug::DecMemoryCrunch(); return; } } if (handle == INVALID_HANDLE_VALUE) { - AuDebug::DecMemoryCrunch(); return; } @@ -301,7 +297,6 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t if ((tlsThrowCounter++) == 7) // TODO: this might be stupid. we should configure for panic on second { tlsThrowCounter--; - AuDebug::DecMemoryCrunch(); return; } @@ -331,5 +326,4 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t Aurora::Exit::PostLevel(AuThreads::GetThread(), Aurora::Exit::ETriggerLevel::eProblematicEvent); tlsThrowCounter--; - AuDebug::DecMemoryCrunch(); } \ No newline at end of file diff --git a/Source/Exit/AuExit.cpp b/Source/Exit/AuExit.cpp index 26e64851..c2fb9677 100644 --- a/Source/Exit/AuExit.cpp +++ b/Source/Exit/AuExit.cpp @@ -46,9 +46,10 @@ namespace Aurora::Exit void PostLevel(AuThreads::IAuroraThread *thread, ETriggerLevel level) { + AU_DEBUG_MEMCRUNCH; + bool bOldTerminatingValue; - AuDebug::AddMemoryCrunch(); { AU_LOCK_GUARD(gMutex); @@ -75,7 +76,6 @@ namespace Aurora::Exit { if (AuAtomicTestAndSet(&gProblemCounter, 1)) { - AuDebug::DecMemoryCrunch(); return; } } @@ -102,7 +102,6 @@ namespace Aurora::Exit // Has already sent eSafeTermination? if (isPreempting) { - AuDebug::DecMemoryCrunch(); return; } @@ -123,7 +122,6 @@ namespace Aurora::Exit Process::Exit(0); } } - AuDebug::DecMemoryCrunch(); } AUKN_SYM bool ExitHandlerAdd(ETriggerLevel level, const AuSPtr &callback) diff --git a/Source/IO/Net/AuNetWorker.hpp b/Source/IO/Net/AuNetWorker.hpp index 975aefa1..f743420c 100644 --- a/Source/IO/Net/AuNetWorker.hpp +++ b/Source/IO/Net/AuNetWorker.hpp @@ -74,26 +74,18 @@ namespace Aurora::IO::Net auto old = this->callbacks_; auto temp = AuMakeShared>([=](const AuSPtr &response) { - auto pWorkItem = this->origin_.pool->NewWorkItem(this->origin_, AuMakeShared([response, callbacks = old]() + auto pWorkItem = this->origin_.pool->NewWorkFunction(this->origin_,[response, callbacks = old]() { callbacks->OnSuccess(response.get()); - }, []() - { - SysPanic("Eh"); - })); - SysAssert(pWorkItem); + }); SysAssert(pWorkItem->Dispatch(), "A network task failed to dispatch critically"); }, [=](const AuSPtr &response) { - auto pWorkItem = this->origin_.pool->NewWorkItem(this->origin_, AuMakeShared([response, callbacks = old]() + auto pWorkItem = this->origin_.pool->NewWorkFunction(this->origin_, [response, callbacks = old]() { callbacks->OnFailure(response.get()); - }, []() - { - SysPanic("Eh"); - })); - SysAssert(pWorkItem); + }); SysAssert(pWorkItem->Dispatch(), "A network task failed to dispatch critically"); });