/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuThreadState.hpp Date: 2023-11-04 Author: Reece ***/ #include #include "Async.hpp" #include "AuThreadState.hpp" #include #include "ThreadWorkerQueueShim.hpp" namespace Aurora::Async { ThreadStateSync::ThreadStateSync(): cvVariable(AuUnsafeRaiiToShared(cvWorkMutex.AsPointer())) { } ThreadStateBase::ThreadStateBase() { } ThreadStateBase::~ThreadStateBase() { if (this->asyncLoop) { this->asyncLoop->pParent = nullptr; if (this->asyncLoop) { (void)this->asyncLoop->SourceRemove(this->sync.eventLs); } } } bool ThreadStateSync::Init() { this->eventLs = AuLoop::NewLSAsync(); return true; } bool ThreadStateBase::Init() { if (!(this->asyncLoop = AuMakeShared())) { SysPushErrorMemory(); return {}; } this->asyncLoop->pParent = this; if (!this->asyncLoop->Init()) { SysPushErrorNested(); return {}; } if (!this->sync.Init()) { SysPushErrorNested(); return {}; } if (!this->asyncLoop->SourceAdd(this->sync.eventLs)) { SysPushErrorNested(); return {}; } return true; } void ThreadStateBase::Deinit() { AuResetMember(this->singletons); } void ThreadStateSync::SetEvent(bool bBoth, bool bHasWork) { if (bHasWork) { AuAtomicAdd(&this->cvHasWork, 1u); } if (auto pEvent = this->eventLs) { if (AuAtomicTestAndSet(&this->cvLSActive, 0u) == 0) { pEvent->Set(); } } if (bBoth) { this->cvWorkMutex->Lock(); this->cvWorkMutex->Unlock(); this->cvVariable->Signal(); } } void ThreadStateSync::UpdateCVState(ThreadState *pState) { auto uState = AuAtomicLoad(&pState->sync.cvHasWork); auto uMin = AuMin(uState, pState->pendingWorkItems.size()); if (!uMin) { uMin = 1; } while (uState && AuAtomicCompareExchange(&pState->sync.cvHasWork, uState - uMin, uState) != uState) { uState = pState->sync.cvHasWork; if (uState < uMin) { uMin = uState; } } } }