From 55cac676f5cff31b48ea75405a116562cdea5f63 Mon Sep 17 00:00:00 2001 From: J Reece Wilson Date: Mon, 5 Aug 2024 15:57:13 +0100 Subject: [PATCH] [+] AuLoop::NewSemaphoreEx with max count option for in-process (not ipc) limiting the total wakes. This is required for Xbox, Xbox 360, and Win32 emulators deriving a mutex via a the NT semaphore primitive instead of the builtin binary semaphore (event) and mutex. --- Include/Aurora/IO/Loop/Loop.hpp | 16 ++---- Source/IO/Loop/LSLocalSemaphore.cpp | 89 +++++++++++++++++++++++------ Source/IO/Loop/LSLocalSemaphore.hpp | 3 +- 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/Include/Aurora/IO/Loop/Loop.hpp b/Include/Aurora/IO/Loop/Loop.hpp index ea7a2ff9..64e40676 100644 --- a/Include/Aurora/IO/Loop/Loop.hpp +++ b/Include/Aurora/IO/Loop/Loop.hpp @@ -54,12 +54,6 @@ namespace Aurora::IO::Loop virtual bool Unlock() = 0; }; - struct IConditionVar : virtual ILoopSource - { - virtual bool Signal() = 0; - virtual bool Broadcast() = 0; - }; - struct ITimer : virtual ILoopSource { /* Warning: IO timers use wall time (CurrentClock[M/NS), not SteadyClock[M/N]S()). @@ -77,21 +71,23 @@ namespace Aurora::IO::Loop virtual void *GetLastSignalInfo() = 0; }; - AUKN_SYM AuSPtr NewLSTimer(AuUInt64 absStartTimeMs /*CurrentClockMS()*/, AuUInt32 reschedStepMsOrZero = 0, AuUInt32 maxIterationsOrZero = 0, bool bSingleshot = false /*cannot be changed*/); + AUKN_SYM AuSPtr NewLSTimer(AuUInt64 absStartTimeMs /*CurrentClockMS()*/, AuUInt32 reschedStepMsOrZero = 0, AuUInt32 maxIterationsOrZero = 0, bool bSingleshot = false /*cannot be changed*/); // warn: no IPC counterpart AUKN_SYM AuSPtr NewLSMutex(); AUKN_SYM AuSPtr NewLSMutexSlow(); // interop-ready (usable with DbgLoopSourceToReadFd) AUKN_SYM AuSPtr NewLSEvent(bool bTriggered = false, bool bAtomicRelease = true, bool bPermitMultipleTriggers = false); AUKN_SYM AuSPtr NewLSEventSlow(bool bTriggered = false, bool bAtomicRelease = true, bool bPermitMultipleTriggers = false); // interop-ready (usable with DbgLoopSourceToReadFd) - AUKN_SYM AuSPtr NewLSSemaphore(AuUInt32 uInitialCount = 0); AUKN_SYM AuSPtr NewLSSemaphoreSlow(AuUInt32 uInitialCount = 0); // interop-ready (usable with DbgLoopSourceToReadFd) + AUKN_SYM AuSPtr NewLSSemaphoreEx(AuUInt32 uInitialCount = 0, AuUInt32 uMaxCount = 0); // warn: no IPC counterpart AUKN_SYM AuSPtr NewLSOSHandle(AuUInt); - AUKN_SYM AuSPtr NewLSAsync(Aurora::Async::WorkerPId_t workerPid); - AUKN_SYM AuSPtr NewLSFile(const AuSPtr &fileTransaction); + AUKN_SYM AuSPtr NewLSAsync(Aurora::Async::WorkerPId_t workerPid); // warn: no IPC counterpart + AUKN_SYM AuSPtr NewLSFile(const AuSPtr &fileTransaction); // warn: no IPC counterpart AUKN_SYM AuSPtr NewStdIn(); AUKN_SYM AuSPtr NewLSWin32Source(bool dispatchMessages); AUKN_SYM AuSPtr NewLSAppleSource(); AUKN_SYM AuSPtr NewLSIOHandle(const AuSPtr &pHandle); + // See: AuIO::IPC for IPC event loop objects + // warn: Only works on singular loop sources // warn: You should only use trust the interop-ready sources to serve the HANDLE/fd you expect. // The primary loop-source primitives are capable of bypassing the kernels io scheduler via in-process atomics. diff --git a/Source/IO/Loop/LSLocalSemaphore.cpp b/Source/IO/Loop/LSLocalSemaphore.cpp index abba2102..4c811edc 100644 --- a/Source/IO/Loop/LSLocalSemaphore.cpp +++ b/Source/IO/Loop/LSLocalSemaphore.cpp @@ -21,7 +21,7 @@ namespace Aurora::IO::Loop } - bool LSLocalSemaphore::TryInit(AuUInt32 initialCount) + bool LSLocalSemaphore::TryInit(AuUInt32 initialCount, AuUInt32 uMaxCount) { if (!LSSemaphore::TryInit(initialCount)) { @@ -30,7 +30,7 @@ namespace Aurora::IO::Loop this->uAtomicSemaphore = initialCount; this->uAtomicKernelSemaphore = initialCount; - + this->uMaxCount = uMaxCount; return true; } @@ -81,6 +81,9 @@ namespace Aurora::IO::Loop { AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount); LSSemaphore::AddMany(uCount); + #if !defined(AURORA_IS_MODERNNT_DERIVED) + (void)LSSemaphore::OnTrigger(0); + #endif } #endif else @@ -102,16 +105,31 @@ namespace Aurora::IO::Loop bool LSLocalSemaphore::AddOne() { - auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); + AuUInt32 uNext {}; - #if 0 - if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) + if (auto uMaxValue = this->uMaxCount) { - return true; + while (true) + { + auto uCurrentValue = AuAtomicLoad(&this->uAtomicSemaphore); + uNext = uCurrentValue + 1; + + if (uNext > uMaxValue) + { + return false; + } + + if (AuAtomicCompareExchange(&this->uAtomicSemaphore, uNext, uCurrentValue) == uCurrentValue) + { + break; + } + } + } + else + { + uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); } - AuAtomicAdd(&this->uAtomicKernelSemaphore, 1u); - #else while (true) { auto uCurrentValue = AuAtomicLoad(&this->uAtomicKernelSemaphore); @@ -139,15 +157,36 @@ namespace Aurora::IO::Loop } } } - #endif - LSSemaphore::AddOne(); - return true; + return LSSemaphore::AddOne(); } bool LSLocalSemaphore::AddMany(AuUInt32 uCount) { - auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, uCount); + AuUInt32 uNext {}; + + if (auto uMaxValue = this->uMaxCount) + { + while (true) + { + auto uCurrentValue = AuAtomicLoad(&this->uAtomicSemaphore); + uNext = uCurrentValue + uCount; + + if (uNext > uMaxValue) + { + return false; + } + + if (AuAtomicCompareExchange(&this->uAtomicSemaphore, uNext, uCurrentValue) == uCurrentValue) + { + break; + } + } + } + else + { + uNext = AuAtomicAdd(&this->uAtomicSemaphore, uCount); + } #if 0 if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) @@ -198,8 +237,8 @@ namespace Aurora::IO::Loop } } #endif - LSSemaphore::AddMany(uCount); - return true; + + return LSSemaphore::AddMany(uCount); } bool LSLocalSemaphore::IsSignaled() @@ -307,7 +346,7 @@ namespace Aurora::IO::Loop } - AUKN_SYM AuSPtr NewLSSemaphore(AuUInt32 initialCount) + AUKN_SYM AuSPtr NewLSSemaphore(AuUInt32 uInitialCount) { auto pMutex = AuMakeShared(); if (!pMutex) @@ -316,7 +355,25 @@ namespace Aurora::IO::Loop return {}; } - if (!pMutex->TryInit(initialCount)) + if (!pMutex->TryInit(uInitialCount)) + { + SysPushErrorNested(); + return {}; + } + + return pMutex; + } + + AUKN_SYM AuSPtr NewLSSemaphoreEx(AuUInt32 uInitialCount, AuUInt32 uMaxCount) + { + auto pMutex = AuMakeShared(); + if (!pMutex) + { + SysPushErrorGeneric(); + return {}; + } + + if (!pMutex->TryInit(uInitialCount, uMaxCount)) { SysPushErrorNested(); return {}; diff --git a/Source/IO/Loop/LSLocalSemaphore.hpp b/Source/IO/Loop/LSLocalSemaphore.hpp index 229957f3..84fbdab8 100644 --- a/Source/IO/Loop/LSLocalSemaphore.hpp +++ b/Source/IO/Loop/LSLocalSemaphore.hpp @@ -16,7 +16,7 @@ namespace Aurora::IO::Loop LSLocalSemaphore(); ~LSLocalSemaphore(); - bool TryInit(AuUInt32 initialCount); + bool TryInit(AuUInt32 initialCount, AuUInt32 uMaxCount = 0); bool IsSignaled() override; bool WaitOn(AuUInt32 timeout) override; @@ -40,5 +40,6 @@ namespace Aurora::IO::Loop AuAUInt32 uAtomicSemaphore {}; AuAUInt32 uAtomicKernelSemaphore {}; + AuUInt32 uMaxCount {}; }; } \ No newline at end of file