From 186444853d1b1ed331bda3910fa020332259bb63 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Sat, 21 Oct 2023 04:57:25 +0100 Subject: [PATCH] [+] LSLocalSemaphore (faster io semaphore) --- Source/IO/Loop/LSLocalSemaphore.cpp | 172 +++++++++++++++++++++++++++ Source/IO/Loop/LSLocalSemaphore.hpp | 37 ++++++ Source/IO/Loop/LSSemaphore.Linux.cpp | 4 +- Source/IO/Loop/LSSemaphore.NT.cpp | 2 + 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 Source/IO/Loop/LSLocalSemaphore.cpp create mode 100644 Source/IO/Loop/LSLocalSemaphore.hpp diff --git a/Source/IO/Loop/LSLocalSemaphore.cpp b/Source/IO/Loop/LSLocalSemaphore.cpp new file mode 100644 index 00000000..89b6f9aa --- /dev/null +++ b/Source/IO/Loop/LSLocalSemaphore.cpp @@ -0,0 +1,172 @@ +/*** + Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: LSLocalSemaphore.cpp + Date: 2023-10-21 + Author: Reece +***/ +#include +#include "LSLocalSemaphore.hpp" +#include + +namespace Aurora::IO::Loop +{ + static auto const kFutexBitWake = 256u; + + LSLocalSemaphore::LSLocalSemaphore() + { + + } + + LSLocalSemaphore::~LSLocalSemaphore() + { + + } + + bool LSLocalSemaphore::TryInit(AuUInt32 initialCount) + { + if (!LSSemaphore::TryInit(1)) + { + return false; + } + + this->uAtomicSemaphore = initialCount; + + return true; + } + + bool LSLocalSemaphore::OnTrigger(AuUInt handle) + { + if (AuAtomicLoad(&this->uAtomicWord) & kFutexBitWake) + { + AuAtomicSub(&this->uAtomicWord, kFutexBitWake); + } + + return this->TryTakeNoSpin(); + } + + bool LSLocalSemaphore::AddOne() + { + AuAtomicAdd(&this->uAtomicSemaphore, 1u); + + while (true) + { + auto uState = AuAtomicLoad(&this->uAtomicWord); + + if (uState & kFutexBitWake) + { + if (AuAtomicCompareExchange(&this->uAtomicWord, uState, uState) == uState) + { + return true; + } + else + { + continue; + } + } + + if (AuAtomicCompareExchange(&this->uAtomicWord, uState + kFutexBitWake, uState) == uState) + { + LSSemaphore::AddOne(); + return true; + } + } + } + + bool LSLocalSemaphore::IsSignaled() + { + return this->TryTake(); + } + + bool LSLocalSemaphore::WaitOn(AuUInt32 timeout) + { + return this->TryTakeWaitMS(timeout); + } + + ELoopSource LSLocalSemaphore::GetType() + { + return ELoopSource::eSourceSemaphore; + } + + bool LSLocalSemaphore::TryTakeNoSpin() + { + AuUInt32 uOld {}; + + while ((uOld = this->uAtomicSemaphore)) + { + if (AuAtomicCompareExchange(&this->uAtomicSemaphore, uOld - 1, uOld) == uOld) + { + return true; + } + } + + return false; + } + + bool LSLocalSemaphore::TryTakeSpin() + { + return Threading::Primitives::DoTryIf([&] + { + return this->TryTakeNoSpin(); + }); + } + + bool LSLocalSemaphore::TryTake() + { + return this->TryTakeNoSpin(); + } + + bool LSLocalSemaphore::TryTakeWaitMS(AuUInt32 timeout) + { + auto uEndTime = AuTime::SteadyClockMS() + timeout; + + if (this->TryTakeSpin()) + { + return true; + } + + while (!this->TryTakeNoSpin()) + { + if (!timeout) + { + if (LSSemaphore::WaitOn(0)) + { + return true; + } + } + else + { + auto uStartTime = Time::SteadyClockNS(); + if (uStartTime >= uEndTime) + { + return false; + } + + if (LSSemaphore::WaitOn(AuNSToMS(uEndTime - uStartTime))) + { + return true; + } + } + } + + return true; + } + + AUKN_SYM AuSPtr NewLSSemaphore(AuUInt32 initialCount) + { + auto pMutex = AuMakeShared(); + if (!pMutex) + { + SysPushErrorGeneric(); + return {}; + } + + if (!pMutex->TryInit(initialCount)) + { + SysPushErrorNested(); + return {}; + } + + return pMutex; + } +} \ No newline at end of file diff --git a/Source/IO/Loop/LSLocalSemaphore.hpp b/Source/IO/Loop/LSLocalSemaphore.hpp new file mode 100644 index 00000000..66884233 --- /dev/null +++ b/Source/IO/Loop/LSLocalSemaphore.hpp @@ -0,0 +1,37 @@ +/*** + Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: LSLocalMutex.hpp + Date: 2023-10-21 + Author: Reece +***/ +#pragma once + +#include "LSSemaphore.hpp" + +namespace Aurora::IO::Loop +{ + struct LSLocalSemaphore : LSSemaphore + { + LSLocalSemaphore(); + ~LSLocalSemaphore(); + + bool TryInit(AuUInt32 initialCount); + + bool IsSignaled() override; + bool WaitOn(AuUInt32 timeout) override; + ELoopSource GetType() override; + + bool AddOne() override; + + virtual bool OnTrigger(AuUInt handle) override; + + bool TryTakeNoSpin(); + bool TryTakeSpin(); + bool TryTake(); + bool TryTakeWaitMS(AuUInt32 timeout); + + AuAUInt32 uAtomicWord {}; + AuAUInt32 uAtomicSemaphore {}; + }; +} \ No newline at end of file diff --git a/Source/IO/Loop/LSSemaphore.Linux.cpp b/Source/IO/Loop/LSSemaphore.Linux.cpp index 981fc451..6e098d84 100644 --- a/Source/IO/Loop/LSSemaphore.Linux.cpp +++ b/Source/IO/Loop/LSSemaphore.Linux.cpp @@ -43,7 +43,7 @@ namespace Aurora::IO::Loop bool LSSemaphore::TryInit(AuUInt32 initialCount) { this->Init(initialCount); - return this->handle != -1; + return this->HasValidHandle(); } bool LSSemaphore::IsSignaledNonblocking() @@ -85,6 +85,7 @@ namespace Aurora::IO::Loop return ELoopSource::eSourceSemaphore; } +#if 0 AUKN_SYM AuSPtr NewLSSemaphore(AuUInt32 initialCount) { auto pSemaphore = AuMakeShared(initialCount); @@ -100,4 +101,5 @@ namespace Aurora::IO::Loop return pSemaphore; } +#endif } \ No newline at end of file diff --git a/Source/IO/Loop/LSSemaphore.NT.cpp b/Source/IO/Loop/LSSemaphore.NT.cpp index 44cbd4f1..ae8475f5 100644 --- a/Source/IO/Loop/LSSemaphore.NT.cpp +++ b/Source/IO/Loop/LSSemaphore.NT.cpp @@ -57,6 +57,7 @@ namespace Aurora::IO::Loop return true; } +#if 0 AUKN_SYM AuSPtr NewLSSemaphore(AuUInt32 initialCount) { AuSPtr ret; @@ -70,4 +71,5 @@ namespace Aurora::IO::Loop return AuMakeShared(semaphore); } +#endif } \ No newline at end of file