AuroraRuntime/Source/IO/Loop/LSLocalSemaphore.cpp

206 lines
4.4 KiB
C++
Raw Normal View History

/***
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(1))
{
return false;
}
this->uAtomicSemaphore = initialCount;
2023-10-21 17:12:23 +00:00
this->uAtomicWord = 1;
return true;
}
bool LSLocalSemaphore::OnTrigger(AuUInt handle)
{
2023-10-21 17:12:23 +00:00
auto bRet = this->TryTakeNoSpin();
while (true)
{
2023-10-21 17:12:23 +00:00
auto uOld = this->uAtomicWord;
if (uOld == 0)
{
break;
}
if (AuAtomicCompareExchange(&this->uAtomicWord, uOld - 1, uOld) == uOld)
{
auto uCount = AuAtomicLoad(&this->uAtomicSemaphore);
if (uOld - 1 == 0 &&
uCount)
{
AuAtomicAdd(&this->uAtomicWord, uCount);
for (AU_ITERATE_N(i, uCount))
{
LSSemaphore::AddOne();
}
}
break;
}
}
2023-10-21 17:12:23 +00:00
return bRet;
}
bool LSLocalSemaphore::AddOne()
{
2023-10-21 17:12:23 +00:00
auto uNext = AuAtomicAdd(&this->uAtomicSemaphore, 1u);
2023-10-21 17:12:23 +00:00
if (AuAtomicLoad(&this->uAtomicWord) >= uNext)
{
2023-10-21 17:12:23 +00:00
return true;
}
2023-10-21 17:12:23 +00:00
AuAtomicAdd(&this->uAtomicWord, 1u);
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::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;
}
2023-10-21 17:12:23 +00:00
void LSLocalSemaphore::OnPresleep()
{
#if 0
while (auto uActiveSemaphore = AuAtomicLoad(&this->uAtomicSemaphore))
{
if (AuAtomicLoad(&this->uAtomicWord) >= uActiveSemaphore)
{
return;
}
AuAtomicAdd(&this->uAtomicWord, uActiveSemaphore);
for (AU_ITERATE_N(i, uActiveSemaphore))
{
LSSemaphore::AddOne();
}
}
#endif
}
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;
}
}