[+] LSLocalMutex (faster io mutex)
This commit is contained in:
parent
bd69ad6739
commit
1589079ead
169
Source/IO/Loop/LSLocalMutex.cpp
Normal file
169
Source/IO/Loop/LSLocalMutex.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: LSLocalMutex.cpp
|
||||
Date: 2023-10-21
|
||||
Author: Reece
|
||||
***/
|
||||
#include <RuntimeInternal.hpp>
|
||||
#include "LSLocalMutex.hpp"
|
||||
#include <Source/Threading/Primitives/SMTYield.hpp>
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
static auto const kFutexBitWake = 256u;
|
||||
|
||||
LSLocalMutex::LSLocalMutex()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LSLocalMutex::~LSLocalMutex()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool LSLocalMutex::TryInit()
|
||||
{
|
||||
if (!LSSemaphore::TryInit(1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LSLocalMutex::OnTrigger(AuUInt handle)
|
||||
{
|
||||
if (AuAtomicLoad(&this->uAtomicWord) & kFutexBitWake)
|
||||
{
|
||||
AuAtomicSub(&this->uAtomicWord, kFutexBitWake);
|
||||
}
|
||||
|
||||
return this->TryTakeNoSpin();
|
||||
}
|
||||
|
||||
bool LSLocalMutex::Unlock()
|
||||
{
|
||||
if (!(AuAtomicLoad(&this->uAtomicWord) & 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AuAtomicClearU8Lock(&this->uAtomicWord);
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto uState = AuAtomicLoad(&this->uAtomicWord);
|
||||
if (uState & 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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 LSLocalMutex::IsSignaled()
|
||||
{
|
||||
return this->TryTake();
|
||||
}
|
||||
|
||||
bool LSLocalMutex::WaitOn(AuUInt32 timeout)
|
||||
{
|
||||
return this->TryTakeWaitMS(timeout);
|
||||
}
|
||||
|
||||
ELoopSource LSLocalMutex::GetType()
|
||||
{
|
||||
return ELoopSource::eSourceMutex;
|
||||
}
|
||||
|
||||
bool LSLocalMutex::TryTakeNoSpin()
|
||||
{
|
||||
return AuAtomicTestAndSet(&this->uAtomicWord, 0) == 0;
|
||||
}
|
||||
|
||||
bool LSLocalMutex::TryTakeSpin()
|
||||
{
|
||||
return Threading::Primitives::DoTryIf([&]
|
||||
{
|
||||
return this->TryTakeNoSpin();
|
||||
});
|
||||
}
|
||||
|
||||
bool LSLocalMutex::TryTake()
|
||||
{
|
||||
return TryTakeNoSpin();
|
||||
}
|
||||
|
||||
bool LSLocalMutex::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<AuInt64>(uEndTime - uStartTime)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM AuSPtr<ILSMutex> NewLSMutex()
|
||||
{
|
||||
auto pMutex = AuMakeShared<LSLocalMutex>();
|
||||
if (!pMutex)
|
||||
{
|
||||
SysPushErrorGeneric();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!pMutex->TryInit())
|
||||
{
|
||||
SysPushErrorNested();
|
||||
return {};
|
||||
}
|
||||
|
||||
return pMutex;
|
||||
}
|
||||
}
|
36
Source/IO/Loop/LSLocalMutex.hpp
Normal file
36
Source/IO/Loop/LSLocalMutex.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
/***
|
||||
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 LSLocalMutex : LSSemaphore, ILSMutex
|
||||
{
|
||||
LSLocalMutex();
|
||||
~LSLocalMutex();
|
||||
|
||||
bool TryInit();
|
||||
|
||||
bool IsSignaled() override;
|
||||
bool WaitOn(AuUInt32 timeout) override;
|
||||
ELoopSource GetType() override;
|
||||
|
||||
bool Unlock() override;
|
||||
|
||||
virtual bool OnTrigger(AuUInt handle) override;
|
||||
|
||||
bool TryTakeNoSpin();
|
||||
bool TryTakeSpin();
|
||||
bool TryTake();
|
||||
bool TryTakeWaitMS(AuUInt32 timeout);
|
||||
|
||||
AuAUInt32 uAtomicWord {};
|
||||
};
|
||||
}
|
@ -91,6 +91,7 @@ namespace Aurora::IO::Loop
|
||||
return ELoopSource::eSourceMutex;
|
||||
}
|
||||
|
||||
#if 0
|
||||
AUKN_SYM AuSPtr<ILSMutex> NewLSMutex()
|
||||
{
|
||||
auto pMutex = AuMakeShared<LSMutex>();
|
||||
@ -106,4 +107,5 @@ namespace Aurora::IO::Loop
|
||||
|
||||
return pMutex;
|
||||
}
|
||||
#endif
|
||||
}
|
@ -40,6 +40,7 @@ namespace Aurora::IO::Loop
|
||||
return ELoopSource::eSourceMutex;
|
||||
}
|
||||
|
||||
#if 0
|
||||
AUKN_SYM AuSPtr<ILSMutex> NewLSMutex()
|
||||
{
|
||||
AuSPtr<ILSMutex> ret;
|
||||
@ -53,4 +54,5 @@ namespace Aurora::IO::Loop
|
||||
|
||||
return AuMakeShared<LSMutex>(mutex);
|
||||
}
|
||||
#endif
|
||||
}
|
@ -11,6 +11,11 @@
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
LSSemaphore::LSSemaphore()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LSSemaphore::LSSemaphore(AuUInt32 initialCount)
|
||||
{
|
||||
Init(initialCount);
|
||||
@ -35,6 +40,12 @@ namespace Aurora::IO::Loop
|
||||
handle = ::eventfd(initialCount, EFD_SEMAPHORE | EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
}
|
||||
|
||||
bool LSSemaphore::TryInit(AuUInt32 initialCount)
|
||||
{
|
||||
this->Init(initialCount);
|
||||
return this->handle != -1;
|
||||
}
|
||||
|
||||
bool LSSemaphore::IsSignaledNonblocking()
|
||||
{
|
||||
AuUInt64 oldSemaphoreValue {};
|
||||
|
@ -12,10 +12,13 @@ namespace Aurora::IO::Loop
|
||||
{
|
||||
struct LSSemaphore : ILSSemaphore, virtual LSHandle
|
||||
{
|
||||
LSSemaphore();
|
||||
LSSemaphore(AuUInt32 initialCount);
|
||||
LSSemaphore(int handle, int tag);
|
||||
~LSSemaphore();
|
||||
|
||||
bool TryInit(AuUInt32 initialCount = 0);
|
||||
|
||||
bool AddOne() override;
|
||||
|
||||
virtual bool OnTrigger(AuUInt handle) override;
|
||||
|
@ -10,6 +10,9 @@
|
||||
|
||||
namespace Aurora::IO::Loop
|
||||
{
|
||||
LSSemaphore::LSSemaphore()
|
||||
{}
|
||||
|
||||
LSSemaphore::LSSemaphore(HANDLE handle) : LSHandle(AuReinterpretCast<AuUInt>(handle))
|
||||
{}
|
||||
|
||||
@ -41,6 +44,19 @@ namespace Aurora::IO::Loop
|
||||
return ELoopSource::eSourceSemaphore;
|
||||
}
|
||||
|
||||
bool LSSemaphore::TryInit(AuUInt32 initialCount)
|
||||
{
|
||||
auto semaphore = ::CreateSemaphoreA(NULL, initialCount, AuNumericLimits<LONG>::max(), NULL);
|
||||
if (!semaphore)
|
||||
{
|
||||
SysPushErrorGen("Out of OS resources?");
|
||||
return {};
|
||||
}
|
||||
|
||||
this->handle = (AuUInt)semaphore;
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 initialCount)
|
||||
{
|
||||
AuSPtr<LSSemaphore> ret;
|
||||
|
@ -12,9 +12,12 @@ namespace Aurora::IO::Loop
|
||||
{
|
||||
struct LSSemaphore : ILSSemaphore, virtual LSHandle
|
||||
{
|
||||
LSSemaphore();
|
||||
LSSemaphore(HANDLE handle);
|
||||
~LSSemaphore();
|
||||
|
||||
bool TryInit(AuUInt32 initialCount = 0);
|
||||
|
||||
bool AddOne() override;
|
||||
|
||||
bool ILSSemaphore::IsSignaled() override;
|
||||
|
Loading…
Reference in New Issue
Block a user