/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: WaitSingle.Generic.cpp Date: 2021-10-2 Author: Reece ***/ #include #include "WaitSingleBase.hpp" namespace Aurora::IO::Loop { extern AuRWRenterableLock gWaitForMultipleALLLock; bool WaitSingleBase::IsSignaledNoSpinIfUserland() { return this->IsSignaled(); } bool WaitSingleBase::IsSignaled() { return WaitSingleBase::IsSignaledExt(0); } bool WaitSingleBase::IsSignaledExt(AuUInt8 uFlags) { bool bFlagUser = uFlags & kFlagLSTryNoSpin; if (bFlagUser) { return this->IsSignaledNoSpinIfUserland(); } this->OnPresleep(); bool bRet = this->IsSignaledExt_(uFlags); if (!bRet) { AU_LOCK_GUARD(gWaitForMultipleALLLock->AsReadable()); bRet = this->IsSignaledExt_(uFlags); } this->OnFinishSleep(); return bRet; } bool WaitSingleBase::IsSignaledExt_(AuUInt8 uFlags) { bool val {}; AuUInt one {AuNumericLimits::max()}; AuUInt two {AuNumericLimits::max()}; bool bFlagUser = uFlags & kFlagLSTryNoSpin; bool bFlagNoAlert = uFlags & kFlagLSTryNoIOAlerts; if (this->Singular()) { #if defined(AURORA_IS_POSIX_DERIVED) auto handle = this->GetHandle(); auto handleRw = this->GetWriteHandle(); val = this->WaitForOne(0, handle, handleRw, bFlagNoAlert); #else auto handle = this->GetHandle(); val = this->WaitForOne(0, handle, bFlagNoAlert); #endif if (val) { val = this->OnTrigger(handle); } } else { #if defined(AURORA_IS_POSIX_DERIVED) auto handles = this->GetHandles(); auto handlesRw = this->GetWriteHandles(); val = this->WaitForAtleastOne(0, handles, handlesRw, one, two, bFlagNoAlert); if (one == -1) one = two; #else auto handles = this->GetHandles(); val = this->WaitForAtleastOne(0, handles, one, bFlagNoAlert); #endif if (val) { val = this->OnTrigger(one); } } return val; } bool WaitSingleBase::WaitOn(AuUInt32 timeout) { return WaitSingleBase::WaitOnExt(0, timeout); } bool WaitSingleBase::WaitOnExt(AuUInt8 uFlags, AuUInt32 timeout) { bool bFlagUser = uFlags & kFlagLSTryNoSpin; if (bFlagUser) { if (this->IsSignaledNoSpinIfUserland()) { return true; } uFlags &= ~kFlagLSTryNoSpin; } auto uEndTime = timeout ? AuTime::SteadyClockNS() + AuMSToNS(timeout) : 0; return WaitSingleBase::WaitOnAbsExt(uFlags, uEndTime); } bool WaitSingleBase::WaitOnAbs(AuUInt64 uTimeoutAbs) { return WaitSingleBase::WaitOnAbsExt(0, uTimeoutAbs); } bool WaitSingleBase::WaitOnAbsExt(AuUInt8 uFlags, AuUInt64 uEndTime) { bool val {}; AuUInt32 uMSTimeout {}; AuUInt64 uNSTimeout {}; bool bAgain {}; AuUInt one {AuNumericLimits::max()}; AuUInt two {AuNumericLimits::max()}; bool bFlagUser = uFlags & kFlagLSTryNoSpin; bool bFlagNoAlert = uFlags & kFlagLSTryNoIOAlerts; if (bFlagUser) { if (this->IsSignaledNoSpinIfUserland()) { return true; } } this->OnPresleep(); do { if (uEndTime) { auto uStartTime = Time::SteadyClockNS(); if (uStartTime >= uEndTime) { uMSTimeout = 0; uNSTimeout = 0; } else { uNSTimeout = uEndTime - uStartTime; uMSTimeout = AuNSToMS(uNSTimeout); } if (bAgain && !uMSTimeout) { val = false; break; } } else { uMSTimeout = AuUInt32(-1); } if (this->Singular()) { #if defined(AURORA_IS_POSIX_DERIVED) auto handle = this->GetHandle(); auto handleRw = this->GetWriteHandle(); val = this->WaitForOne(uMSTimeout, handle, handleRw, bFlagNoAlert); #else auto handle = this->GetHandle(); val = this->WaitForOne(uMSTimeout, handle, bFlagNoAlert); #endif if (val) { val = this->OnTrigger(handle); } } else { #if defined(AURORA_IS_POSIX_DERIVED) auto handles = this->GetHandles(); auto handlesRw = this->GetWriteHandles(); val = this->WaitForAtleastOne(uMSTimeout, handles, handlesRw, one, two, bFlagNoAlert); if (one == -1) one = two; #else auto handles = this->GetHandles(); val = this->WaitForAtleastOne(uMSTimeout, handles, one, bFlagNoAlert); #endif if (val) { val = this->OnTrigger(one); } } bAgain = true; } while (uEndTime && !val); this->OnFinishSleep(); return val; } }