/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuWakeOnAddress.hpp Date: 2023-3-10 Author: Reece ***/ #pragma once #include "Primitives/AuConditionMutex.Generic.hpp" #include "Primitives/AuConditionVariable.Generic.hpp" namespace Aurora::Threading { static const auto kDefaultWaitPerProcess = 128; struct WaitState; struct WaitBuffer { char buffer[32]; AuUInt8 uSize; static WaitBuffer From(const void *pBuf, AuUInt8 uSize); static bool Compare(const void *pBuf, AuUInt8 uSize, WaitState &state); static bool Compare(const void *pBuf, AuUInt8 uSize, const void *pBuf2); bool Compare(const void *pBuf); bool Compare(WaitState &state); }; struct WaitState { WaitBuffer compare; //AuOptionalEx qwNanoseconds; AuOptionalEx qwNanosecondsAbs; AuOptionalEx uDownsizeMask; AuUInt32 uWordSize {}; }; struct WaitEntry { WaitEntry(); ~WaitEntry(); WaitEntry *pNext {}; WaitEntry *pBefore {}; // synch #if defined(WOA_SEMAPHORE_MODE) #if defined(WOA_SEMAPHORE_SEMAPHORE) // PORT: MacOS (?) WOA_SEMAPHORE_SEMAPHORE semaphore; #else // Testing: Primitives::Semaphore semaphore; #endif #else // Recommended (we can better filter spurious wakes for the cost of a barrier on signal): Primitives::ConditionMutexInternal mutex; // mutex ctor must come before var Primitives::ConditionVariableInternal variable; // ...and something all 2007+ micro and monolithic kernels should have to yield for an event #endif // state const void *pAddress {}; AuUInt8 uSize {}; // bookkeeping (parent container) bool bOverflow {}; bool bAlive {}; void Release(); bool SleepOn(WaitState &state); bool TrySignalAddress(const void *pAddress); }; struct ProcessListWait { WaitEntry *pHead {}; WaitEntry *pTail {}; }; struct ProcessWaitNodeContainer { AuUInt32 uAtomic {}; ProcessListWait waitList; WaitEntry *WaitBufferFrom(const void *pAddress, AuUInt8 uSize, bool bScheduleFirst); template bool IterateWake(T callback); void RemoveSelf(WaitEntry *pSelf); void RemoveEntry(WaitEntry *pSelf, bool bAllUnderLock); void Lock(); void Unlock(); }; struct ProcessWaitContainer { ProcessWaitNodeContainer list[kDefaultWaitPerProcess]; WaitEntry *WaitBufferFrom(const void *pAddress, AuUInt8 uSize, bool bScheduleFirst = true); template bool IterateWake(const void *pAddress, T callback); void RemoveSelf(const void *pAddress, WaitEntry *pSelf); }; }