AuroraRuntime/Source/Threading/AuWaitFor.cpp

190 lines
4.7 KiB
C++
Raw Normal View History

2021-06-27 21:25:29 +00:00
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
2022-11-17 07:46:07 +00:00
File: AuWaitFor.cpp
2021-06-27 21:25:29 +00:00
Date: 2021-6-12
Author: Reece
***/
2021-09-30 14:57:41 +00:00
#include <Source/RuntimeInternal.hpp>
2022-11-17 07:46:07 +00:00
#include "AuWaitFor.hpp"
#include "Primitives/SMTYield.hpp"
2022-11-17 07:46:07 +00:00
#if defined(AURORA_IS_POSIX_DERIVED)
2022-11-17 07:46:07 +00:00
#include <sched.h>
2021-06-27 21:25:29 +00:00
#endif
namespace Aurora::Threading
{
static void YieldToSharedCore(long uSpin)
2021-06-27 21:25:29 +00:00
{
#if (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
auto loops = __rdtsc() + (1ull << uSpin);
while (loops > __rdtsc())
2021-06-27 21:25:29 +00:00
{
_mm_pause(); _mm_pause(); _mm_pause(); _mm_pause();
_mm_pause(); _mm_pause(); _mm_pause(); _mm_pause();
_mm_pause(); _mm_pause(); _mm_pause(); _mm_pause();
_mm_pause(); _mm_pause(); _mm_pause(); _mm_pause();
2021-06-27 21:25:29 +00:00
}
#else
auto uRemainingTicks = (1ull << uSpin);
while (uRemainingTicks > 0)
2021-06-27 21:25:29 +00:00
{
Primitives::SMPPause();
uRemainingTicks -= 1;
2021-06-27 21:25:29 +00:00
}
#endif
2021-06-27 21:25:29 +00:00
}
AUKN_SYM void ContextYield()
2021-06-27 21:25:29 +00:00
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
::SwitchToThread();
#elif defined(AURORA_IS_POSIX_DERIVED)
::sched_yield();
2021-06-27 21:25:29 +00:00
#else
YieldToSharedCore(12);
2021-06-27 21:25:29 +00:00
#endif
}
AUKN_SYM bool YieldPollNs(bool bPermitMultipleContextSwitches, AuUInt64 qwAbsTimeoutNs, const PollCallback_cb &cb)
2021-06-27 21:25:29 +00:00
{
while (!Primitives::DoTryIf(cb))
2021-06-27 21:25:29 +00:00
{
2024-05-27 15:02:54 +00:00
if (qwAbsTimeoutNs &&
Time::SteadyClockNS() >= qwAbsTimeoutNs)
2021-06-27 21:25:29 +00:00
{
return false;
2021-06-27 21:25:29 +00:00
}
if (bPermitMultipleContextSwitches)
2021-06-27 21:25:29 +00:00
{
ContextYield();
2021-06-27 21:25:29 +00:00
}
}
return true;
}
AUKN_SYM bool YieldPoll(bool bPermitMultipleContextSwitches, AuUInt64 qwTimeoutMs, const PollCallback_cb &cb)
2021-06-27 21:25:29 +00:00
{
return YieldPollNs(bPermitMultipleContextSwitches,
qwTimeoutMs ? Time::SteadyClockNS() + AuMSToNS<AuUInt64>(qwTimeoutMs) : 0,
cb);
2021-06-27 21:25:29 +00:00
}
AUKN_SYM bool WaitForAbsNS(IWaitable *pWaitable, AuUInt64 qwAbsTimeout)
2021-06-27 21:25:29 +00:00
{
SysCheckArgNotNull(pWaitable, false);
if (pWaitable->HasLockImplementation())
2021-06-27 21:25:29 +00:00
{
return pWaitable->LockAbsNS(qwAbsTimeout);
2021-06-27 21:25:29 +00:00
}
return YieldPollNs(true, qwAbsTimeout, [=]()
2021-06-27 21:25:29 +00:00
{
return pWaitable->TryLock();
2021-06-27 21:25:29 +00:00
});
}
2023-09-12 17:47:25 +00:00
AUKN_SYM bool TryWait(IWaitable *pWaitable)
{
SysCheckArgNotNull(pWaitable, false);
2023-09-12 17:47:25 +00:00
if (pWaitable->HasLockImplementation())
{
return pWaitable->TryLock();
}
return Primitives::DoTryIf([=]()
{
return pWaitable->TryLock();
});
}
AUKN_SYM bool WaitFor(const AuList<IWaitable *> &waitables, AuUInt32 uFlags, AuUInt64 uTimeout, AuUInt32 *pIndexAwoken)
2021-06-27 21:25:29 +00:00
{
AU_DEBUG_MEMCRUNCH;
AuUInt64 qwTimeoutAbs {};
AuList<bool> releasedObjects(waitables.size());
2021-06-27 21:25:29 +00:00
if (uFlags & kWaitForFlagTimeoutIsNanoseconds)
2021-06-27 21:25:29 +00:00
{
qwTimeoutAbs = uTimeout;
2021-06-27 21:25:29 +00:00
}
else
{
qwTimeoutAbs = AuMSToNS<AuUInt64>(uTimeout);
2021-06-27 21:25:29 +00:00
}
if ((!(uFlags & kWaitForFlagTimeoutIsAbsolute)) &&
(uTimeout))
2021-06-27 21:25:29 +00:00
{
qwTimeoutAbs += AuTime::SteadyClockNS();
2021-06-27 21:25:29 +00:00
}
auto bIsAnd = !(uFlags & kWaitForFlagTimeoutIsOr);
2021-06-27 21:25:29 +00:00
auto bStatus = YieldPollNs(true, qwTimeoutAbs, [&]()
2021-06-27 21:25:29 +00:00
{
bool bStatus { !waitables.size() };
2021-06-27 21:25:29 +00:00
for (AU_ITERATE_N(i, waitables.size()))
2021-06-27 21:25:29 +00:00
{
if (releasedObjects[i])
2021-06-27 21:25:29 +00:00
{
continue;
}
bool bLocked {};
if (bIsAnd)
{
bLocked = WaitForAbsNS(waitables[i], qwTimeoutAbs);
}
else
{
bLocked = waitables[i]->TryLock();
if (pIndexAwoken)
{
*pIndexAwoken = i;
}
}
if (bLocked)
{
releasedObjects[i] = true;
bStatus = true;
}
else
{
if (bIsAnd)
2021-06-27 21:25:29 +00:00
{
return false;
}
}
}
return bStatus;
2021-06-27 21:25:29 +00:00
});
if (!bStatus)
2021-06-27 21:25:29 +00:00
{
for (AU_ITERATE_N(i, waitables.size()))
2021-06-27 21:25:29 +00:00
{
if (releasedObjects[i])
{
waitables[i]->Unlock();
}
}
}
return bStatus;
2021-06-27 21:25:29 +00:00
}
}