[+] 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.
This commit is contained in:
Reece Wilson 2024-08-05 15:57:13 +01:00
parent 7cc41f1359
commit 55cac676f5
3 changed files with 81 additions and 27 deletions

View File

@ -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<ITimer> NewLSTimer(AuUInt64 absStartTimeMs /*CurrentClockMS()*/, AuUInt32 reschedStepMsOrZero = 0, AuUInt32 maxIterationsOrZero = 0, bool bSingleshot = false /*cannot be changed*/);
AUKN_SYM AuSPtr<ITimer> NewLSTimer(AuUInt64 absStartTimeMs /*CurrentClockMS()*/, AuUInt32 reschedStepMsOrZero = 0, AuUInt32 maxIterationsOrZero = 0, bool bSingleshot = false /*cannot be changed*/); // warn: no IPC counterpart
AUKN_SYM AuSPtr<ILSMutex> NewLSMutex();
AUKN_SYM AuSPtr<ILSMutex> NewLSMutexSlow(); // interop-ready (usable with DbgLoopSourceToReadFd)
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent(bool bTriggered = false, bool bAtomicRelease = true, bool bPermitMultipleTriggers = false);
AUKN_SYM AuSPtr<ILSEvent> NewLSEventSlow(bool bTriggered = false, bool bAtomicRelease = true, bool bPermitMultipleTriggers = false); // interop-ready (usable with DbgLoopSourceToReadFd)
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 uInitialCount = 0);
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphoreSlow(AuUInt32 uInitialCount = 0); // interop-ready (usable with DbgLoopSourceToReadFd)
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphoreEx(AuUInt32 uInitialCount = 0, AuUInt32 uMaxCount = 0); // warn: no IPC counterpart
AUKN_SYM AuSPtr<ILoopSource> NewLSOSHandle(AuUInt);
AUKN_SYM AuSPtr<ILoopSource> NewLSAsync(Aurora::Async::WorkerPId_t workerPid);
AUKN_SYM AuSPtr<ILoopSource> NewLSFile(const AuSPtr<IO::IAsyncTransaction> &fileTransaction);
AUKN_SYM AuSPtr<ILoopSource> NewLSAsync(Aurora::Async::WorkerPId_t workerPid); // warn: no IPC counterpart
AUKN_SYM AuSPtr<ILoopSource> NewLSFile(const AuSPtr<IO::IAsyncTransaction> &fileTransaction); // warn: no IPC counterpart
AUKN_SYM AuSPtr<ILoopSource> NewStdIn();
AUKN_SYM AuSPtr<ILoopSource> NewLSWin32Source(bool dispatchMessages);
AUKN_SYM AuSPtr<ILoopSource> NewLSAppleSource();
AUKN_SYM AuSPtr<ILoopSource> NewLSIOHandle(const AuSPtr<IIOHandle> &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.

View File

@ -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<ILSSemaphore> NewLSSemaphore(AuUInt32 initialCount)
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 uInitialCount)
{
auto pMutex = AuMakeShared<LSLocalSemaphore>();
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<ILSSemaphore> NewLSSemaphoreEx(AuUInt32 uInitialCount, AuUInt32 uMaxCount)
{
auto pMutex = AuMakeShared<LSLocalSemaphore>();
if (!pMutex)
{
SysPushErrorGeneric();
return {};
}
if (!pMutex->TryInit(uInitialCount, uMaxCount))
{
SysPushErrorNested();
return {};

View File

@ -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 {};
};
}