AuroraRuntime/Source/Threading/Primitives/AuMutex.Generic.cpp

184 lines
3.9 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Mutex.Generic.cpp
Date: 2021-6-12
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuMutex.Generic.hpp"
#include "../AuWakeInternal.hpp"
#include "SMTYield.hpp"
#if defined(_AURUNTIME_GENERIC_MUTEX)
namespace Aurora::Threading::Primitives
{
MutexGenericImpl::MutexGenericImpl()
{
this->state_ = 0;
}
MutexGenericImpl::~MutexGenericImpl()
{
}
bool MutexGenericImpl::HasOSHandle(AuMach &mach)
{
return false;
}
bool MutexGenericImpl::HasLockImplementation()
{
return true;
}
bool MutexGenericImpl::TryLock()
{
if (ThrdCfg::gPreferUnixPrimitivesNoSpin)
{
return this->TryLockNoSpin();
}
else
{
return this->TryLockHeavy();
}
}
bool MutexGenericImpl::TryLockNoSpin()
{
return AuAtomicTestAndSet(&this->state_, 0) == 0;
}
bool MutexGenericImpl::TryLockHeavy()
{
return DoTryIf([=]()
{
return this->TryLockNoSpin();
});
}
bool MutexGenericImpl::LockMS(AuUInt64 uTimeout)
{
return this->LockNS(AuMSToNS<AuUInt64>(uTimeout));
}
bool MutexGenericImpl::LockNS(AuUInt64 uTimeout)
{
AuUInt64 uStart {};
AuUInt64 uEnd {};
bool bStatus { true };
if (this->TryLockNoSpin())
{
return true;
}
if (uTimeout != 0)
{
uStart = AuTime::SteadyClockNS();
uEnd = uStart + uTimeout;
}
if (this->TryLock())
{
return true;
}
AuAtomicAdd(&this->dwSleeping_, 1u);
while (!this->TryLockNoSpin())
{
static const AuUInt32 kRef { 1 };
if (uTimeout != 0)
{
if (!InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEnd))
{
bStatus = false;
break;
}
}
else
{
(void)InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEnd);
}
}
AuAtomicSub(&this->dwSleeping_, 1u);
return bStatus;
}
bool MutexGenericImpl::LockAbsNS(AuUInt64 uEndTime)
{
bool bStatus { true };
if (ThrdCfg::gPreferUnixPrimitivesNoSpin)
{
if (this->TryLockNoSpin())
{
return true;
}
}
else
{
if (this->TryLockHeavy())
{
return true;
}
}
AuAtomicAdd(&this->dwSleeping_, 1u);
while (!this->TryLockNoSpin())
{
static const AuUInt32 kRef { 1 };
if (uEndTime != 0)
{
if (!InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEndTime))
{
bStatus = false;
break;
}
}
else
{
(void)InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEndTime);
}
}
AuAtomicSub(&this->dwSleeping_, 1u);
return true;
}
void MutexGenericImpl::SlowLock()
{
(void)this->LockAbsNS(0);
}
void MutexGenericImpl::Unlock()
{
AuAtomicClearU8Lock(&this->state_);
if (AuAtomicLoad(&this->dwSleeping_))
{
InternalLTSWakeOne((void *)&this->state_);
}
}
AUKN_SYM IHyperWaitable *MutexNew()
{
return _new MutexGenericImpl();
}
AUKN_SYM void MutexRelease(IHyperWaitable *pMutex)
{
AuSafeDelete<MutexGenericImpl *>(pMutex);
}
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, Mutex, MutexGenericImpl)
}
#endif