204 lines
4.3 KiB
C++
204 lines
4.3 KiB
C++
/***
|
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: LSLocalSemaphore.cpp
|
|
Date: 2023-10-21
|
|
Author: Reece
|
|
***/
|
|
#include <RuntimeInternal.hpp>
|
|
#include "LSLocalSemaphore.hpp"
|
|
#include <Source/Threading/Primitives/SMTYield.hpp>
|
|
|
|
namespace Aurora::IO::Loop
|
|
{
|
|
LSLocalSemaphore::LSLocalSemaphore()
|
|
{
|
|
|
|
}
|
|
|
|
LSLocalSemaphore::~LSLocalSemaphore()
|
|
{
|
|
|
|
}
|
|
|
|
bool LSLocalSemaphore::TryInit(AuUInt32 initialCount)
|
|
{
|
|
if (!LSSemaphore::TryInit(initialCount))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this->uAtomicSemaphore = initialCount;
|
|
this->uAtomicKernelSemaphore = initialCount;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LSLocalSemaphore::OnTrigger(AuUInt handle)
|
|
{
|
|
auto bRet = this->TryTakeNoSpin();
|
|
|
|
while (true)
|
|
{
|
|
auto uOld = this->uAtomicKernelSemaphore;
|
|
|
|
if (uOld == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (AuAtomicCompareExchange(&this->uAtomicKernelSemaphore, uOld - 1, uOld) == uOld)
|
|
{
|
|
auto uCount = AuAtomicLoad(&this->uAtomicSemaphore);
|
|
|
|
if (uOld - 1 == 0 &&
|
|
uCount)
|
|
{
|
|
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount);
|
|
LSSemaphore::AddMany(uCount);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
bool LSLocalSemaphore::AddOne()
|
|
{
|
|
auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u);
|
|
|
|
if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
AuAtomicAdd(&this->uAtomicKernelSemaphore, 1u);
|
|
LSSemaphore::AddOne();
|
|
return true;
|
|
}
|
|
|
|
bool LSLocalSemaphore::AddMany(AuUInt32 uCount)
|
|
{
|
|
auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u);
|
|
|
|
if (AuAtomicLoad(&this->uAtomicKernelSemaphore) >= uNext)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
AuAtomicAdd(&this->uAtomicKernelSemaphore, uCount);
|
|
LSSemaphore::AddMany(uCount);
|
|
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::SteadyClockNS() + AuMSToNS<AuUInt64>(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;
|
|
}
|
|
|
|
auto uDeltaMs = AuNSToMS<AuInt64>(uEndTime - uStartTime);
|
|
if (uDeltaMs &&
|
|
LSSemaphore::WaitOn(uDeltaMs))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void LSLocalSemaphore::OnPresleep()
|
|
{
|
|
|
|
}
|
|
|
|
void LSLocalSemaphore::OnFinishSleep()
|
|
{
|
|
|
|
}
|
|
|
|
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 initialCount)
|
|
{
|
|
auto pMutex = AuMakeShared<LSLocalSemaphore>();
|
|
if (!pMutex)
|
|
{
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
}
|
|
|
|
if (!pMutex->TryInit(initialCount))
|
|
{
|
|
SysPushErrorNested();
|
|
return {};
|
|
}
|
|
|
|
return pMutex;
|
|
}
|
|
} |