[*] LSLocalSemaphore bug fix for scriptability. (TODO: reimpl like the event?)

[*] Fix: IO objects not using the explicit slow sync primitives.
Dunno how these werent refactored; then again, i never properly got around to finishing the factories for fast/slow io objects. In addition, some of these arent even accessed by the ILoopSource interface, so it's not as critical of a failure.
This commit is contained in:
Reece Wilson 2024-07-30 17:30:19 +01:00
parent 9956f1c153
commit 5cafefae5d
6 changed files with 106 additions and 6 deletions

View File

@ -92,7 +92,7 @@ namespace Aurora::IO::IPC
{ {
if (serverHandle != INVALID_HANDLE_VALUE) if (serverHandle != INVALID_HANDLE_VALUE)
{ {
this->hasClient_ = Loop::NewLSEvent(false, false, true); this->hasClient_ = Loop::NewLSEventSlow(false, false, true);
if (!this->hasClient_) if (!this->hasClient_)
{ {
this->bDead = true; this->bDead = true;

View File

@ -34,6 +34,15 @@ namespace Aurora::IO::Loop
return true; return true;
} }
void LSLocalSemaphore::DoParanoia()
{
if (auto uCount = AuAtomicLoad(&this->uAtomicSemaphore))
{
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount);
LSSemaphore::AddMany(uCount);
}
}
bool LSLocalSemaphore::OnTrigger(AuUInt handle) bool LSLocalSemaphore::OnTrigger(AuUInt handle)
{ {
auto bRet = this->TryTakeNoSpin(); auto bRet = this->TryTakeNoSpin();
@ -41,10 +50,11 @@ namespace Aurora::IO::Loop
while (true) while (true)
{ {
auto uOld = this->uAtomicKernelSemaphore; auto uOld = AuAtomicLoad(&this->uAtomicKernelSemaphore);
if (uOld == 0) if (uOld == 0)
{ {
DoParanoia();
break; break;
} }
@ -54,11 +64,25 @@ namespace Aurora::IO::Loop
if (uOld - 1 == 0) if (uOld - 1 == 0)
{ {
#if defined(AURORA_PLATFORM_LINUX)
if (uCount == 1)
{
// Don't acknowledge?
// Don't write into?
// saves two syscalls for nothang
}
else if (uCount)
{
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount - 1);
LSSemaphore::AddMany(uCount - 1);
}
#else
if (uCount) if (uCount)
{ {
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount); AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount);
LSSemaphore::AddMany(uCount); LSSemaphore::AddMany(uCount);
} }
#endif
else else
{ {
(void)LSSemaphore::OnTrigger(0); (void)LSSemaphore::OnTrigger(0);
@ -89,26 +113,100 @@ namespace Aurora::IO::Loop
{ {
auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u);
#if 0
if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext)
{ {
return true; return true;
} }
AuAtomicAdd(&this->uAtomicKernelSemaphore, 1u); AuAtomicAdd(&this->uAtomicKernelSemaphore, 1u);
#else
while (true)
{
auto uCurrentValue = AuAtomicLoad(&this->uAtomicKernelSemaphore);
auto uNextValue = uCurrentValue;
bool bCanReturn = false;
if (uCurrentValue < uNext)
{
uNextValue = uNext;
}
else
{
bCanReturn = true;
}
if (AuAtomicCompareExchange(&this->uAtomicKernelSemaphore, uNextValue, uCurrentValue) == uCurrentValue)
{
if (bCanReturn)
{
return true;
}
else
{
break;
}
}
}
#endif
LSSemaphore::AddOne(); LSSemaphore::AddOne();
return true; return true;
} }
bool LSLocalSemaphore::AddMany(AuUInt32 uCount) bool LSLocalSemaphore::AddMany(AuUInt32 uCount)
{ {
auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, uCount);
#if 0
if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext)
{ {
return true; return true;
} }
else
{
/* if AddMany add/load/kernel-wake race condition, it's the next AddMany persons problem. */
/* uAtomicKernelSemaphore cannot be lower than uAtomicSemaphore, at the epilogue of the last unlock/adds tick. */
/* If it somehow is, ::OnTrigger will check that the final kernel negative increment does not occur just before (linux) after (win32) (bool(this->uAtomicSemaphore)). */
/* Remember: this->uAtomicKernelSemaphore should only be decremented after uAtomicSemaphore and uAtomicKernelSemaphore have already been incremented together... */
/* ...therefore, the last kernel waker should always see bool(this->uAtomicSemaphore), unless stolen by another thread. */
/* if stolen, it's a race condition we dont care about; we avoided the kernel object and state entirely. We have to wait for another AddMany to wake us up. */
/* if not stolen, uAtomicSemaphore is read as non-zero, and is readded to the kernel semaphore */
/* Most users just use the IO event objects LSAsync and LSLocalEvent. These are known good. */
}
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount); AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount);
#else
while (true)
{
auto uCurrentValue = AuAtomicLoad(&this->uAtomicKernelSemaphore);
auto uNextValue = uCurrentValue;
bool bCanReturn = false;
if (uCurrentValue < uNext)
{
uNextValue = uNext;
}
else
{
bCanReturn = true;
}
if (AuAtomicCompareExchange(&this->uAtomicKernelSemaphore, uNextValue, uCurrentValue) == uCurrentValue)
{
if (bCanReturn)
{
return true;
}
else
{
uCount = uNext - uCurrentValue;
break;
}
}
}
#endif
LSSemaphore::AddMany(uCount); LSSemaphore::AddMany(uCount);
return true; return true;
} }

View File

@ -36,6 +36,8 @@ namespace Aurora::IO::Loop
void OnPresleep() override; void OnPresleep() override;
void OnFinishSleep() override; void OnFinishSleep() override;
void DoParanoia();
AuAUInt32 uAtomicSemaphore {}; AuAUInt32 uAtomicSemaphore {};
AuAUInt32 uAtomicKernelSemaphore {}; AuAUInt32 uAtomicKernelSemaphore {};
}; };

View File

@ -17,7 +17,7 @@ namespace Aurora::IO::Net
SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) : SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) :
bMultipleTrigger(bMultipleTrigger) bMultipleTrigger(bMultipleTrigger)
{ {
this->pEvent = AuLoop::NewLSEvent(false, true); this->pEvent = AuLoop::NewLSEventSlow(false, true);
if (!this->pEvent) if (!this->pEvent)
{ {
return; return;

View File

@ -17,7 +17,7 @@ namespace Aurora::IO::Net
SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) : SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) :
bMultipleTrigger(bMultipleTrigger) bMultipleTrigger(bMultipleTrigger)
{ {
this->pEvent = AuLoop::NewLSEvent(false, true); this->pEvent = AuLoop::NewLSEventSlow(false, true);
if (!this->pEvent) if (!this->pEvent)
{ {
return; return;

View File

@ -508,7 +508,7 @@ namespace Aurora::IO::Net
void NtAsyncNetworkTransaction::MakeSyncable() void NtAsyncNetworkTransaction::MakeSyncable()
{ {
this->pWaitable = AuLoop::NewLSEvent(false, true); this->pWaitable = AuLoop::NewLSEventSlow(false, true);
SysAssert(this->pWaitable); SysAssert(this->pWaitable);
this->overlap.hEvent = (HANDLE)AuStaticCast<Loop::LSEvent>(this->pWaitable)->GetHandle(); this->overlap.hEvent = (HANDLE)AuStaticCast<Loop::LSEvent>(this->pWaitable)->GetHandle();
} }