[+] 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; virtual bool Unlock() = 0;
}; };
struct IConditionVar : virtual ILoopSource
{
virtual bool Signal() = 0;
virtual bool Broadcast() = 0;
};
struct ITimer : virtual ILoopSource struct ITimer : virtual ILoopSource
{ {
/* Warning: IO timers use wall time (CurrentClock[M/NS), not SteadyClock[M/N]S()). /* 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; 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> NewLSMutex();
AUKN_SYM AuSPtr<ILSMutex> NewLSMutexSlow(); // interop-ready (usable with DbgLoopSourceToReadFd) 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> 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<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> 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> NewLSOSHandle(AuUInt);
AUKN_SYM AuSPtr<ILoopSource> NewLSAsync(Aurora::Async::WorkerPId_t workerPid); AUKN_SYM AuSPtr<ILoopSource> NewLSAsync(Aurora::Async::WorkerPId_t workerPid); // warn: no IPC counterpart
AUKN_SYM AuSPtr<ILoopSource> NewLSFile(const AuSPtr<IO::IAsyncTransaction> &fileTransaction); AUKN_SYM AuSPtr<ILoopSource> NewLSFile(const AuSPtr<IO::IAsyncTransaction> &fileTransaction); // warn: no IPC counterpart
AUKN_SYM AuSPtr<ILoopSource> NewStdIn(); AUKN_SYM AuSPtr<ILoopSource> NewStdIn();
AUKN_SYM AuSPtr<ILoopSource> NewLSWin32Source(bool dispatchMessages); AUKN_SYM AuSPtr<ILoopSource> NewLSWin32Source(bool dispatchMessages);
AUKN_SYM AuSPtr<ILoopSource> NewLSAppleSource(); AUKN_SYM AuSPtr<ILoopSource> NewLSAppleSource();
AUKN_SYM AuSPtr<ILoopSource> NewLSIOHandle(const AuSPtr<IIOHandle> &pHandle); 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: Only works on singular loop sources
// warn: You should only use trust the interop-ready sources to serve the HANDLE/fd you expect. // 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. // 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)) if (!LSSemaphore::TryInit(initialCount))
{ {
@ -30,7 +30,7 @@ namespace Aurora::IO::Loop
this->uAtomicSemaphore = initialCount; this->uAtomicSemaphore = initialCount;
this->uAtomicKernelSemaphore = initialCount; this->uAtomicKernelSemaphore = initialCount;
this->uMaxCount = uMaxCount;
return true; return true;
} }
@ -81,6 +81,9 @@ namespace Aurora::IO::Loop
{ {
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount); AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount);
LSSemaphore::AddMany(uCount); LSSemaphore::AddMany(uCount);
#if !defined(AURORA_IS_MODERNNT_DERIVED)
(void)LSSemaphore::OnTrigger(0);
#endif
} }
#endif #endif
else else
@ -102,16 +105,31 @@ namespace Aurora::IO::Loop
bool LSLocalSemaphore::AddOne() bool LSLocalSemaphore::AddOne()
{ {
auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); AuUInt32 uNext {};
#if 0 if (auto uMaxValue = this->uMaxCount)
if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext)
{ {
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) while (true)
{ {
auto uCurrentValue = AuAtomicLoad(&this->uAtomicKernelSemaphore); auto uCurrentValue = AuAtomicLoad(&this->uAtomicKernelSemaphore);
@ -139,15 +157,36 @@ namespace Aurora::IO::Loop
} }
} }
} }
#endif
LSSemaphore::AddOne(); return LSSemaphore::AddOne();
return true;
} }
bool LSLocalSemaphore::AddMany(AuUInt32 uCount) 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 0
if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext)
@ -198,8 +237,8 @@ namespace Aurora::IO::Loop
} }
} }
#endif #endif
LSSemaphore::AddMany(uCount);
return true; return LSSemaphore::AddMany(uCount);
} }
bool LSLocalSemaphore::IsSignaled() 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>(); auto pMutex = AuMakeShared<LSLocalSemaphore>();
if (!pMutex) if (!pMutex)
@ -316,7 +355,25 @@ namespace Aurora::IO::Loop
return {}; 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(); SysPushErrorNested();
return {}; return {};

View File

@ -16,7 +16,7 @@ namespace Aurora::IO::Loop
LSLocalSemaphore(); LSLocalSemaphore();
~LSLocalSemaphore(); ~LSLocalSemaphore();
bool TryInit(AuUInt32 initialCount); bool TryInit(AuUInt32 initialCount, AuUInt32 uMaxCount = 0);
bool IsSignaled() override; bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override; bool WaitOn(AuUInt32 timeout) override;
@ -40,5 +40,6 @@ namespace Aurora::IO::Loop
AuAUInt32 uAtomicSemaphore {}; AuAUInt32 uAtomicSemaphore {};
AuAUInt32 uAtomicKernelSemaphore {}; AuAUInt32 uAtomicKernelSemaphore {};
AuUInt32 uMaxCount {};
}; };
} }