diff --git a/Source/IO/IPC/AuIPCPipe.NT.cpp b/Source/IO/IPC/AuIPCPipe.NT.cpp index e91b8002..487ab5ae 100644 --- a/Source/IO/IPC/AuIPCPipe.NT.cpp +++ b/Source/IO/IPC/AuIPCPipe.NT.cpp @@ -92,7 +92,7 @@ namespace Aurora::IO::IPC { if (serverHandle != INVALID_HANDLE_VALUE) { - this->hasClient_ = Loop::NewLSEvent(false, false, true); + this->hasClient_ = Loop::NewLSEventSlow(false, false, true); if (!this->hasClient_) { this->bDead = true; diff --git a/Source/IO/Loop/LSLocalSemaphore.cpp b/Source/IO/Loop/LSLocalSemaphore.cpp index 968cfaa0..b223b693 100644 --- a/Source/IO/Loop/LSLocalSemaphore.cpp +++ b/Source/IO/Loop/LSLocalSemaphore.cpp @@ -34,6 +34,15 @@ namespace Aurora::IO::Loop return true; } + void LSLocalSemaphore::DoParanoia() + { + if (auto uCount = AuAtomicLoad(&this->uAtomicSemaphore)) + { + AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount); + LSSemaphore::AddMany(uCount); + } + } + bool LSLocalSemaphore::OnTrigger(AuUInt handle) { auto bRet = this->TryTakeNoSpin(); @@ -41,10 +50,11 @@ namespace Aurora::IO::Loop while (true) { - auto uOld = this->uAtomicKernelSemaphore; + auto uOld = AuAtomicLoad(&this->uAtomicKernelSemaphore); if (uOld == 0) { + DoParanoia(); break; } @@ -54,11 +64,25 @@ namespace Aurora::IO::Loop 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) { AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount); LSSemaphore::AddMany(uCount); } + #endif else { (void)LSSemaphore::OnTrigger(0); @@ -89,26 +113,100 @@ namespace Aurora::IO::Loop { auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); + #if 0 if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) { return true; } 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(); return true; } bool LSLocalSemaphore::AddMany(AuUInt32 uCount) { - auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u); + auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, uCount); + #if 0 if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext) { 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); + #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); return true; } diff --git a/Source/IO/Loop/LSLocalSemaphore.hpp b/Source/IO/Loop/LSLocalSemaphore.hpp index 7553b794..229957f3 100644 --- a/Source/IO/Loop/LSLocalSemaphore.hpp +++ b/Source/IO/Loop/LSLocalSemaphore.hpp @@ -36,6 +36,8 @@ namespace Aurora::IO::Loop void OnPresleep() override; void OnFinishSleep() override; + void DoParanoia(); + AuAUInt32 uAtomicSemaphore {}; AuAUInt32 uAtomicKernelSemaphore {}; }; diff --git a/Source/IO/Net/AuNetSocketOverlappedOperation.NT.cpp b/Source/IO/Net/AuNetSocketOverlappedOperation.NT.cpp index 368de1f7..8f250e34 100644 --- a/Source/IO/Net/AuNetSocketOverlappedOperation.NT.cpp +++ b/Source/IO/Net/AuNetSocketOverlappedOperation.NT.cpp @@ -17,7 +17,7 @@ namespace Aurora::IO::Net SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) : bMultipleTrigger(bMultipleTrigger) { - this->pEvent = AuLoop::NewLSEvent(false, true); + this->pEvent = AuLoop::NewLSEventSlow(false, true); if (!this->pEvent) { return; diff --git a/Source/IO/Net/AuNetSocketOverlappedOperation.Unix.cpp b/Source/IO/Net/AuNetSocketOverlappedOperation.Unix.cpp index 510dbd0b..a9766a19 100644 --- a/Source/IO/Net/AuNetSocketOverlappedOperation.Unix.cpp +++ b/Source/IO/Net/AuNetSocketOverlappedOperation.Unix.cpp @@ -17,7 +17,7 @@ namespace Aurora::IO::Net SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) : bMultipleTrigger(bMultipleTrigger) { - this->pEvent = AuLoop::NewLSEvent(false, true); + this->pEvent = AuLoop::NewLSEventSlow(false, true); if (!this->pEvent) { return; diff --git a/Source/IO/Net/AuNetStream.NT.cpp b/Source/IO/Net/AuNetStream.NT.cpp index adcd8288..a0a29341 100644 --- a/Source/IO/Net/AuNetStream.NT.cpp +++ b/Source/IO/Net/AuNetStream.NT.cpp @@ -508,7 +508,7 @@ namespace Aurora::IO::Net void NtAsyncNetworkTransaction::MakeSyncable() { - this->pWaitable = AuLoop::NewLSEvent(false, true); + this->pWaitable = AuLoop::NewLSEventSlow(false, true); SysAssert(this->pWaitable); this->overlap.hEvent = (HANDLE)AuStaticCast(this->pWaitable)->GetHandle(); }