/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: LoopQueue.NT.hpp Date: 2022-2-1W2 Author: Reece ***/ #pragma once namespace Aurora::Loop { struct LoopQueue : ILoopQueue { LoopQueue(); ~LoopQueue(); bool SourceAdd(const AuSPtr &source) override; bool SourceAddWithTimeout(const AuSPtr &source, AuUInt32 ms) override; bool SourceRemove(const AuSPtr &source) override; AuUInt32 GetSourceCount() override; bool AddCallback(const AuSPtr &source, const AuSPtr &subscriber) override; bool AddCallbackEx(const AuSPtr &source, const AuSPtr &subscriber) override; bool AddCallback(const AuSPtr &subscriber) override; void ChugPathConfigure(AuUInt32 sectionTickTime, AuSInt sectionDequeCount) override; void ChugHint(bool value) override; bool Commit() override; bool HasFinished() override; bool IsSignaled() override; bool WaitAll(AuUInt32 timeout) override; AuUInt32 WaitAny(AuUInt32 timeout) override; AuList> WaitAnyEx(AuUInt32 timeout) override; void Sync(); void Unlock(); private: void ConsiderEvicitingTimeoutsAll(); struct ExtendeSourceInfo { inline ExtendeSourceInfo(AuSPtr in) : source(in) {} AuSPtr source; AuSPtr sourceBase; AuThreadPrimitives::SpinLock lock; // im too brain dead to think of a solution to the AddCallback thread safety issue, so i'm going to optimize Wait[...]s subscriber lookup with filtered ccaches in here, protected by this spinlock AuList> globalSubscribers; AuList> specificSubscribers; AuList> timeoutSubscribers; AuUInt32 timeoutAbs; bool ConsiderTimeout() const { if ((timeoutAbs) && (AuTime::CurrentInternalClockMS() >= timeoutAbs)) { for (const auto &handler : timeoutSubscribers) { try { handler->OnTimeout(sourceBase); } catch (...) { SysPushErrorCatch(); } } return true; } return false; } }; bool IsValid(); void RemoveSourceNB(const AuSPtr &source, bool removeHandles); bool WaitAnyNBSpurious(AuUInt32 timeout, AuUInt32 &chuggerIndex, AuList> *trigger, bool poll); bool ChugWaitAny(AuUInt32 timeout, AuUInt32 &chuggerIndex, AuUInt32 &offset); // AuList> msgCallbacks_; AuList> removedSources_; AuThreadPrimitives::SpinLock sourceMutex_; AuList, AuUInt32>> sources_; // // OS Cache AuThreadPrimitives::RWLockUnique_t rwMutex_ = AuThreadPrimitives::RWLockUnique(); bool bIsWinLoop_ {}; bool bIsThreadSafe_ {}; AuList handleArray_; AuUInt32 slowTickMs_ {1}; AuUInt32 slowTickRate_ {MAXIMUM_WAIT_OBJECTS}; bool forceChug_ {}; AuList loopSourceExs_; AuSPtr msgSource_; HANDLE hEvent_ {INVALID_HANDLE_VALUE}; }; }