[*] Begin enforcing steady time
[+] IOProcessor::WakeupThread [+] NT: Begin hacking in timeBeginPeriod (must spam it in some places) [+] ConsoleTTY (more specifically the win32 calls) are too slow to run on the mainthread. Delegate to worker. [*] AuTime.CurrentClockSteady [*] AuTime.CurrentClockSteadyMS [*] AuTime.CurrentClockSteadyNS
This commit is contained in:
parent
bb9c383aee
commit
72dc0d715e
@ -61,7 +61,8 @@
|
||||
"ws2_32.lib",
|
||||
"Ntdll.lib",
|
||||
"Wer.lib",
|
||||
"wintrust.lib"
|
||||
"wintrust.lib",
|
||||
"Winmm.lib"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -41,6 +41,8 @@ namespace Aurora::IO
|
||||
|
||||
virtual bool SubmitIOWorkItem (const AuSPtr<IIOProcessorWorkUnit> &work) = 0;
|
||||
|
||||
virtual void WakeupThread () = 0;
|
||||
|
||||
// Inter-frame callbacks indicating point of execution throughout the [START](optional [yield])[IO][IO TICK][WORK ITEMS][EPILOGUE][END OF FRAME] frame
|
||||
virtual bool AddEventListener (const AuSPtr<IIOProcessorEventListener> &eventListener) = 0;
|
||||
virtual void RemoveEventListener (const AuSPtr<IIOProcessorEventListener> &eventListener) = 0;
|
||||
|
@ -44,6 +44,12 @@ namespace Aurora::Time
|
||||
*/
|
||||
AUKN_SYM AuUInt64 CurrentClockNS();
|
||||
|
||||
AUKN_SYM AuUInt64 CurrentClockSteady();
|
||||
|
||||
AUKN_SYM AuUInt64 CurrentClockSteadyMS();
|
||||
|
||||
AUKN_SYM AuUInt64 CurrentClockSteadyNS();
|
||||
|
||||
/**
|
||||
Translates the Aurora epoch to the standard unix epoch
|
||||
*/
|
||||
|
@ -317,7 +317,7 @@ namespace Aurora::Async
|
||||
}
|
||||
else
|
||||
{
|
||||
success |= PollInternal(block);
|
||||
success |= PollInternal(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -445,7 +445,7 @@ namespace Aurora::Async
|
||||
return false;
|
||||
}
|
||||
|
||||
} while (state->pendingWorkItems.empty());
|
||||
} while (state->pendingWorkItems.empty() && block);
|
||||
|
||||
if (group->workQueue.empty())
|
||||
{
|
||||
@ -537,6 +537,7 @@ namespace Aurora::Async
|
||||
|
||||
tlsCallStack++;
|
||||
|
||||
//SysBenchmark(fmt::format("RunAsync: {}", block));
|
||||
// Dispatch
|
||||
oops->RunAsync();
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "SWInfo/AuSWInfo.hpp"
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#include "Extensions/Win32/DarkTheme.hpp"
|
||||
#include <timeapi.h>
|
||||
#endif
|
||||
#include "Process/Process.hpp"
|
||||
#include "Exit/AuExit.hpp"
|
||||
@ -49,6 +50,8 @@ static void Init()
|
||||
gRuntimeRunLevel = 1;
|
||||
tlsHackIsMainThread = true;
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
::timeBeginPeriod(1);
|
||||
|
||||
Aurora::Extensions::Win32::InitDarkMode();
|
||||
#endif
|
||||
|
||||
@ -85,6 +88,10 @@ static void Pump()
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
::LinuxSuperSecretIOTick();
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
::timeBeginPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void RuntimeLateClean();
|
||||
|
@ -97,15 +97,26 @@ namespace Aurora::Console
|
||||
Logging::InitLoggers();
|
||||
}
|
||||
|
||||
void Pump()
|
||||
void PumpOnMain()
|
||||
{
|
||||
Commands::PumpCommands();
|
||||
ConsoleStd::Pump();
|
||||
}
|
||||
|
||||
// dumb
|
||||
void PumpOffMain()
|
||||
{
|
||||
ConsoleWxWidgets::Pump();
|
||||
ConsoleFIO::Pump();
|
||||
ConsoleTTY::Pump();
|
||||
}
|
||||
|
||||
void Pump()
|
||||
{
|
||||
PumpOnMain();
|
||||
PumpOffMain();
|
||||
}
|
||||
|
||||
void Exit()
|
||||
{
|
||||
gDefaultSinks.clear();
|
||||
|
@ -17,4 +17,7 @@ namespace Aurora::Console
|
||||
void Init2();
|
||||
void Pump();
|
||||
void Exit();
|
||||
|
||||
void PumpOffMain();
|
||||
void PumpOnMain();
|
||||
}
|
@ -21,6 +21,9 @@
|
||||
|
||||
namespace Aurora::Console::ConsoleTTY
|
||||
{
|
||||
static AuThreads::ThreadUnique_t gConsoleTTYThread;
|
||||
static bool gMultiThreadTTY { true };
|
||||
static bool gBuggyFastAppend { false };
|
||||
|
||||
#if 1
|
||||
|
||||
@ -715,6 +718,7 @@ namespace Aurora::Console::ConsoleTTY
|
||||
|
||||
void TTYConsole::Pump()
|
||||
{
|
||||
//SysBenchmark("Console TTY pump");
|
||||
if (!gTTYConsoleEnabled)
|
||||
{
|
||||
return;
|
||||
@ -722,13 +726,20 @@ namespace Aurora::Console::ConsoleTTY
|
||||
|
||||
if (NoncanonicalMode())
|
||||
{
|
||||
//SysBenchmark("NoncanonicalTick");
|
||||
NoncanonicalTick();
|
||||
}
|
||||
|
||||
{
|
||||
//SysBenchmark("flush (redraw)");
|
||||
Flush();
|
||||
}
|
||||
|
||||
{
|
||||
//SysBenchmark("history");
|
||||
PumpHistory();
|
||||
}
|
||||
}
|
||||
|
||||
void TTYConsole::OnEnter()
|
||||
{
|
||||
@ -862,6 +873,10 @@ namespace Aurora::Console::ConsoleTTY
|
||||
if (iScrollPos == -1)
|
||||
{
|
||||
if (this->screenBuffer.size() > maxLines)
|
||||
{
|
||||
// TODO (Reece): Removing optimization bc it was broken. This is a nightmare.
|
||||
|
||||
if (!gBuggyFastAppend)
|
||||
{
|
||||
static bool bSingleShot {};
|
||||
if (!AuExchange(bSingleShot, true))
|
||||
@ -869,7 +884,6 @@ namespace Aurora::Console::ConsoleTTY
|
||||
EnterScrollMode();
|
||||
}
|
||||
|
||||
// TODO (Reece): Removing optimization bc it was broken. This is a nightmare.
|
||||
auto indexBeforePadding = (this->GetBannerFootBorder() ? 1 + this->topLogPadding : 0) + this->topLogPaddingExtra;
|
||||
auto startIndex = this->GetTopBorder() + this->GetBannerLines() + indexBeforePadding;
|
||||
|
||||
@ -883,6 +897,26 @@ namespace Aurora::Console::ConsoleTTY
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is still buggy as shit but we NEEEEED it
|
||||
// youll notice whitespace appear as soon as we start overflowing but eh
|
||||
for (int i = startIndex + maxLines; i < this->currentHeight; i++)
|
||||
{
|
||||
this->BlankLine(i);
|
||||
}
|
||||
|
||||
TTYScrollBuffer(delta);
|
||||
|
||||
for (int i = indexBeforePadding; i < startIndex; i++)
|
||||
{
|
||||
this->BlankLine(i);
|
||||
}
|
||||
|
||||
forceRedrawIfFalse = true;
|
||||
drawPos = startIndex + maxLines - delta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drawPos = startIndex + oldSize;
|
||||
}
|
||||
@ -1044,12 +1078,14 @@ namespace Aurora::Console::ConsoleTTY
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Account for race conditions of size-change during draw
|
||||
if (PermitDoubleBuffering())
|
||||
{
|
||||
bTryAgain = !EndBuffering();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->bTriggerRedraw = false;
|
||||
}
|
||||
@ -1981,9 +2017,37 @@ namespace Aurora::Console::ConsoleTTY
|
||||
return this->topLogPaddingExtra;
|
||||
}
|
||||
|
||||
static void MainTTY()
|
||||
{
|
||||
while (AuIsThreadRunning())
|
||||
{
|
||||
AuThreading::Sleep(1000 / 20);
|
||||
gTTYConsole.Pump();
|
||||
}
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
gTTYConsole.Init();
|
||||
|
||||
if (gMultiThreadTTY)
|
||||
{
|
||||
gConsoleTTYThread = AuThreads::ThreadUnique(AuThreads::ThreadInfo(
|
||||
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(MainTTY)),
|
||||
AuThreads::IThreadVectorsFunctional::OnExit_t {}),
|
||||
"ConsoleTTY pumper (win32 is slow as shit ok?)"
|
||||
));
|
||||
|
||||
if (!gConsoleTTYThread)
|
||||
{
|
||||
gMultiThreadTTY = false;
|
||||
return;
|
||||
}
|
||||
|
||||
gConsoleTTYThread->SetThrottle(AuThreads::EThreadThrottle::eEfficient);
|
||||
gConsoleTTYThread->SetPriority(AuThreads::EThreadPriority::ePrioHigh);
|
||||
gConsoleTTYThread->Run();
|
||||
}
|
||||
}
|
||||
|
||||
void Exit()
|
||||
@ -1997,9 +2061,13 @@ namespace Aurora::Console::ConsoleTTY
|
||||
}
|
||||
|
||||
void Pump()
|
||||
{
|
||||
// :(
|
||||
if (!gMultiThreadTTY)
|
||||
{
|
||||
gTTYConsole.Pump();
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM AuSPtr<ITTYConsole> GetTTYConsole()
|
||||
{
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <Source/Console/ConsoleFIO/ConsoleFIO.hpp>
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include <Source/Console/Flusher.hpp>
|
||||
#include <Source/Console/Console.hpp>
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
void LinuxSuperSecretIOTick();
|
||||
@ -118,7 +119,7 @@ namespace Aurora::Grug
|
||||
return;
|
||||
}
|
||||
|
||||
// he's a lazy bastard (ira type insult)
|
||||
// he's a lazy bastard
|
||||
gGrugsBigWorld->SetThrottle(AuThreads::EThreadThrottle::eEfficient);
|
||||
gGrugsBigWorld->SetPriority(AuThreads::EThreadPriority::ePrioLow);
|
||||
gGrugsBigWorld->Run();
|
||||
@ -200,6 +201,7 @@ namespace Aurora::Grug
|
||||
void GrugFlushFlushs()
|
||||
{
|
||||
Logging::ForceFlushFlush();
|
||||
Console::ForceFlush();
|
||||
Aurora::Console::PumpOffMain();
|
||||
//Console::ForceFlush();
|
||||
}
|
||||
}
|
@ -478,9 +478,12 @@ namespace Aurora::IO
|
||||
{
|
||||
AU_LOCK_GUARD(this->items.mutex); // < critical section / reentrant | can nest submission
|
||||
this->items.cvEvent->Set();
|
||||
auto bRet = AuTryInsert(this->workUnits, work);
|
||||
//this->pLoopQueue->Commit(); // required to wake up async threads
|
||||
return bRet;
|
||||
return AuTryInsert(this->workUnits, work);
|
||||
}
|
||||
|
||||
void IOProcessor::WakeupThread()
|
||||
{
|
||||
this->items.cvEvent->Set();
|
||||
}
|
||||
|
||||
bool IOProcessor::AddEventListener(const AuSPtr<IIOProcessorEventListener> &eventListener)
|
||||
|
@ -81,6 +81,8 @@ namespace Aurora::IO
|
||||
|
||||
bool HasItems() override;
|
||||
|
||||
void WakeupThread();
|
||||
|
||||
bool CheckThread();
|
||||
|
||||
bool RequestRemovalForItemFromAnyThread(const AuSPtr<IIOProcessorItem> &processor);
|
||||
|
@ -220,7 +220,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
if (ms)
|
||||
{
|
||||
src->timeoutAbs = (AuUInt64)ms + AuTime::CurrentClockMS();
|
||||
src->timeoutAbs = (AuUInt64)ms + AuTime::CurrentClockSteadyMS();
|
||||
}
|
||||
|
||||
if (!AuTryInsert(this->sources_, src))
|
||||
@ -426,7 +426,7 @@ namespace Aurora::IO::Loop
|
||||
AuUInt64 timeout {timeoutIn};
|
||||
if (timeout)
|
||||
{
|
||||
timeout += AuTime::CurrentClockMS();
|
||||
timeout += AuTime::CurrentClockSteadyMS();
|
||||
}
|
||||
|
||||
{
|
||||
@ -461,7 +461,7 @@ namespace Aurora::IO::Loop
|
||||
// but this hack should apply to wait any as well, so i'm moving it to the DoTick function
|
||||
|
||||
anythingLeft = epollReference.startingWorkRead.size() || epollReference.startingWorkWrite.size();
|
||||
bTimeout = timeout ? AuTime::CurrentClockMS() >= timeout : false;
|
||||
bTimeout = timeout ? AuTime::CurrentClockSteadyMS() >= timeout : false;
|
||||
} while (anythingLeft && !bTimeout);
|
||||
|
||||
{
|
||||
@ -478,7 +478,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
timeout += AuTime::CurrentClockMS();
|
||||
timeout += AuTime::CurrentClockSteadyMS();
|
||||
}
|
||||
|
||||
AuUInt32 cTicked {};
|
||||
@ -532,7 +532,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
timeout += AuTime::CurrentClockMS();
|
||||
timeout += AuTime::CurrentClockSteadyMS();
|
||||
}
|
||||
|
||||
bool bTryAgain {};
|
||||
@ -671,28 +671,10 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
// syscall epoll_pwait2 is fucking broken and the dipshits who wrote the test used relative values
|
||||
//
|
||||
// Nothing I tried worked.
|
||||
//
|
||||
// Am I stupid? Probably, but...
|
||||
// (1) no one as far as i can tell has ever written anything using this syscall, per a github search
|
||||
// (2) i found one reference that the that are the linux kernel developers used MONO time for this
|
||||
// one timespec API unlike everything else; using an abs value rel to that clock didn't change
|
||||
// anything.
|
||||
// (3) i found a test that would indicate its relative despite the fact UNIX/Linux sync APIs
|
||||
// tend to use abs time
|
||||
//
|
||||
// What does my experience working on xenus tell me?
|
||||
// Because the gOOOOglers in the form of linux kernel developers were faced with an issue that
|
||||
// couldn't be solved by involve copy/pasting memory map code, making a mess of public headers,
|
||||
// or taking credit for third party driver code as their own kernel code; they indeed are to
|
||||
// blame for making my life miserable once again. Something about this aint adding up.
|
||||
|
||||
AuInt64 deltaMS = 0;
|
||||
if (time)
|
||||
{
|
||||
deltaMS = AuMin(AuInt64(4), (AuInt64)time - (AuInt64)AuTime::CurrentClockMS());
|
||||
deltaMS = AuMin(AuInt64(4), (AuInt64)time - (AuInt64)AuTime::CurrentClockSteadyMS());
|
||||
if (deltaMS < 0)
|
||||
{
|
||||
deltaMS = 0;
|
||||
@ -771,7 +753,7 @@ namespace Aurora::IO::Loop
|
||||
}
|
||||
}
|
||||
|
||||
now = AuTime::CurrentClockMS();
|
||||
now = AuTime::CurrentClockSteadyMS();
|
||||
|
||||
if (!bTicked)
|
||||
{
|
||||
@ -786,7 +768,7 @@ namespace Aurora::IO::Loop
|
||||
|
||||
if (!now)
|
||||
{
|
||||
now = AuTime::CurrentClockMS();
|
||||
now = AuTime::CurrentClockSteadyMS();
|
||||
}
|
||||
|
||||
for (auto itr = this->sources_.begin(); itr != this->sources_.end(); )
|
||||
|
@ -43,7 +43,7 @@ namespace Aurora::IO::Loop
|
||||
return false;
|
||||
}
|
||||
|
||||
if (time < timeoutAbs)
|
||||
if (time < this->timeoutAbs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -240,7 +240,7 @@ namespace Aurora::IO::Loop
|
||||
{
|
||||
AU_LOCK_GUARD(this->sourceMutex_);
|
||||
|
||||
if (!AuTryInsert(this->addedSources_, AuMakeTuple(source, AuTime::CurrentInternalClockMS() + maxTimeout, SourceCallbacks {})))
|
||||
if (!AuTryInsert(this->addedSources_, AuMakeTuple(source, AuTime::CurrentClockSteadyMS() + maxTimeout, SourceCallbacks {})))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -657,7 +657,7 @@ namespace Aurora::IO::Loop
|
||||
// Le great iterate
|
||||
Iterator queueIterator(this);
|
||||
AuSInt indexOffset {};
|
||||
auto now = AuTime::CurrentInternalClockMS();
|
||||
auto now = AuTime::CurrentClockSteadyMS();
|
||||
for (queueIterator.Start(); queueIterator.End() != queueIterator.itr; )
|
||||
{
|
||||
auto &source = *queueIterator.itr;
|
||||
|
@ -512,9 +512,12 @@ namespace Aurora::IO::UNIX
|
||||
return false;
|
||||
}
|
||||
|
||||
AuInt64 iStartTime {};
|
||||
AuInt64 iTargetTime {};
|
||||
if (timeout)
|
||||
{
|
||||
AuTime::ms2tsabs(&targetTime, timeout);
|
||||
iStartTime = AuTime::CurrentClockSteadyMS();
|
||||
iTargetTime = iStartTime + timeout;
|
||||
}
|
||||
|
||||
if (!LinuxOverlappedTrySubmitWork())
|
||||
@ -526,6 +529,17 @@ namespace Aurora::IO::UNIX
|
||||
|
||||
do
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
auto delta = iTargetTime - AuTime::CurrentClockSteadyMS();
|
||||
if (delta <= 0)
|
||||
{
|
||||
return dwApcsSent;
|
||||
}
|
||||
|
||||
AuTime::ns2ts(&targetTime, delta);
|
||||
}
|
||||
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, timeout ? &targetTime : nullptr);
|
||||
|
||||
if (temp >= 0)
|
||||
@ -600,9 +614,12 @@ namespace Aurora::IO::UNIX
|
||||
return epoll_wait(epfd, events, maxevents, timeout);
|
||||
}
|
||||
|
||||
AuInt64 iStartTime {};
|
||||
AuInt64 iTargetTime {};
|
||||
if (timeout)
|
||||
{
|
||||
AuTime::ms2tsabs(&targetTime, timeout);
|
||||
iStartTime = AuTime::CurrentClockSteadyMS();
|
||||
iTargetTime = iStartTime + timeout;
|
||||
}
|
||||
|
||||
if (!LinuxOverlappedTrySubmitWork())
|
||||
@ -640,6 +657,17 @@ namespace Aurora::IO::UNIX
|
||||
|
||||
do
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
auto delta = iTargetTime - AuTime::CurrentClockSteadyMS();
|
||||
if (delta <= 0)
|
||||
{
|
||||
return dwApcsSent;
|
||||
}
|
||||
|
||||
AuTime::ns2ts(&targetTime, delta);
|
||||
}
|
||||
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, timeout ? &targetTime : nullptr);
|
||||
|
||||
if (temp >= 0)
|
||||
@ -739,9 +767,12 @@ namespace Aurora::IO::UNIX
|
||||
return false;
|
||||
}
|
||||
|
||||
AuInt64 iStartTime {};
|
||||
AuInt64 iTargetTime {};
|
||||
if (timeout)
|
||||
{
|
||||
AuTime::ms2tsabs(&targetTime, timeout);
|
||||
iStartTime = AuTime::CurrentClockSteadyMS();
|
||||
iTargetTime = iStartTime + timeout;
|
||||
}
|
||||
|
||||
if (!LinuxOverlappedTrySubmitWork())
|
||||
@ -794,6 +825,17 @@ namespace Aurora::IO::UNIX
|
||||
|
||||
do
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
auto delta = iTargetTime - AuTime::CurrentClockSteadyMS();
|
||||
if (delta <= 0)
|
||||
{
|
||||
return dwApcsSent;
|
||||
}
|
||||
|
||||
AuTime::ns2ts(&targetTime, delta);
|
||||
}
|
||||
|
||||
temp = io_getevents(io->context, 1, 512, ioEvents, timeout ? &targetTime : nullptr);
|
||||
|
||||
if (temp >= 0)
|
||||
|
@ -15,23 +15,28 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
ConditionVariableImpl::ConditionVariableImpl(const AuSPtr<IConditionMutex> &mutex) : mutex_(std::dynamic_pointer_cast<IConditionMutexEx>(mutex))
|
||||
{
|
||||
auto ret = pthread_cond_init(&pthreadCv_, NULL);
|
||||
pthread_condattr_t attr;
|
||||
|
||||
::pthread_condattr_init(&attr);
|
||||
::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
|
||||
auto ret = ::pthread_cond_init(&this->pthreadCv_, &attr);
|
||||
SysAssert(ret == 0, "Couldn't initialize CV");
|
||||
}
|
||||
|
||||
ConditionVariableImpl::~ConditionVariableImpl()
|
||||
{
|
||||
pthread_cond_destroy(&pthreadCv_);
|
||||
::pthread_cond_destroy(&this->pthreadCv_);
|
||||
}
|
||||
|
||||
AuSPtr<IConditionMutex> ConditionVariableImpl::GetMutex()
|
||||
{
|
||||
return mutex_;
|
||||
return this->mutex_;
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::WaitForSignal(AuUInt32 timeout)
|
||||
{
|
||||
auto mutex = reinterpret_cast<pthread_mutex_t*>(mutex_->GetOSHandle());
|
||||
auto mutex = reinterpret_cast<pthread_mutex_t*>(this->mutex_->GetOSHandle());
|
||||
|
||||
if (gRuntimeRunLevel >= 5)
|
||||
{
|
||||
@ -43,7 +48,7 @@ namespace Aurora::Threading::Primitives
|
||||
int ret {};
|
||||
do
|
||||
{
|
||||
if ((ret = pthread_cond_wait(&pthreadCv_, mutex)) == 0)
|
||||
if ((ret = ::pthread_cond_wait(&this->pthreadCv_, mutex)) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -61,7 +66,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
do
|
||||
{
|
||||
ret = pthread_cond_timedwait(&pthreadCv_, mutex, &tspec);
|
||||
ret = ::pthread_cond_timedwait(&this->pthreadCv_, mutex, &tspec);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -82,13 +87,13 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
void ConditionVariableImpl::Signal()
|
||||
{
|
||||
auto ret = pthread_cond_signal(&pthreadCv_);
|
||||
auto ret = ::pthread_cond_signal(&this->pthreadCv_);
|
||||
SysAssert(ret == 0, "Couldn't wake any CV waiters");
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Broadcast()
|
||||
{
|
||||
auto ret = pthread_cond_broadcast(&pthreadCv_);
|
||||
auto ret = ::pthread_cond_broadcast(&this->pthreadCv_);
|
||||
SysAssert(ret == 0, "Couldn't wake any CV waiters");
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
|
||||
AuInt64 startTime = Time::CurrentClockMS();
|
||||
AuInt64 startTime = Time::CurrentClockSteadyMS();
|
||||
AuInt64 endTime = startTime + timeout;
|
||||
|
||||
while (!AtomicIsEventSet())
|
||||
@ -42,7 +42,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
timeoutMs = endTime - static_cast<AuInt64>(Time::CurrentClockMS());
|
||||
timeoutMs = endTime - static_cast<AuInt64>(Time::CurrentClockSteadyMS());
|
||||
if (timeoutMs < 0)
|
||||
{
|
||||
return false;
|
||||
|
@ -15,9 +15,9 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
Mutex::Mutex()
|
||||
{
|
||||
InitializeSRWLock(&atomicHolder_);
|
||||
InitializeConditionVariable(&wakeup_);
|
||||
state_ = 0;
|
||||
InitializeSRWLock(&this->atomicHolder_);
|
||||
InitializeConditionVariable(&this->wakeup_);
|
||||
this->state_ = 0;
|
||||
}
|
||||
|
||||
Mutex::~Mutex()
|
||||
@ -32,7 +32,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
bool Mutex::TryLock()
|
||||
{
|
||||
return _interlockedbittestandset(&state_, 0) == 0;
|
||||
return _interlockedbittestandset(&this->state_, 0) == 0;
|
||||
}
|
||||
|
||||
bool Mutex::HasLockImplementation()
|
||||
@ -50,9 +50,9 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
bool returnValue = false;
|
||||
|
||||
AcquireSRWLockShared(&atomicHolder_);
|
||||
AcquireSRWLockShared(&this->atomicHolder_);
|
||||
|
||||
AuInt64 startTime = Time::CurrentClockMS();
|
||||
AuInt64 startTime = Time::CurrentClockSteadyMS();
|
||||
AuInt64 endTime = startTime + timeout;
|
||||
|
||||
BOOL status = false;
|
||||
@ -62,7 +62,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (timeout != 0)
|
||||
{
|
||||
startTime = Time::CurrentClockMS();
|
||||
startTime = Time::CurrentClockSteadyMS();
|
||||
if (startTime >= endTime)
|
||||
{
|
||||
goto exitWin32;
|
||||
@ -71,7 +71,7 @@ namespace Aurora::Threading::Primitives
|
||||
timeoutMs = endTime - startTime;
|
||||
}
|
||||
|
||||
status = SleepConditionVariableSRW(&wakeup_, &atomicHolder_, timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED);
|
||||
status = SleepConditionVariableSRW(&this->wakeup_, &this->atomicHolder_, timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED);
|
||||
if (!status)
|
||||
{
|
||||
SysAssertExp(GetLastError() == ERROR_TIMEOUT);
|
||||
@ -82,16 +82,16 @@ namespace Aurora::Threading::Primitives
|
||||
returnValue = true;
|
||||
|
||||
exitWin32:
|
||||
ReleaseSRWLockShared(&atomicHolder_);
|
||||
ReleaseSRWLockShared(&this->atomicHolder_);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void Mutex::Unlock()
|
||||
{
|
||||
AcquireSRWLockExclusive(&atomicHolder_);
|
||||
state_ = 0;
|
||||
ReleaseSRWLockExclusive(&atomicHolder_);
|
||||
WakeAllConditionVariable(&wakeup_);
|
||||
AcquireSRWLockExclusive(&this->atomicHolder_);
|
||||
this->state_ = 0;
|
||||
ReleaseSRWLockExclusive(&this->atomicHolder_);
|
||||
WakeAllConditionVariable(&this->wakeup_);
|
||||
}
|
||||
|
||||
AUKN_SYM IWaitable *MutexNew()
|
||||
|
@ -68,7 +68,7 @@ namespace Aurora::Threading::Primitives
|
||||
else
|
||||
{
|
||||
struct timespec tspec;
|
||||
Time::ms2tsabs(&tspec, timeout);
|
||||
Time::ms2tsabsRealtime(&tspec, timeout);
|
||||
|
||||
int ret {};
|
||||
|
||||
|
@ -42,7 +42,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
bool Semaphore::Lock(AuUInt64 timeout)
|
||||
{
|
||||
AuUInt64 start = AuTime::CurrentInternalClockMS();
|
||||
AuUInt64 start = AuTime::CurrentClockSteadyMS();
|
||||
AuUInt64 end = start + timeout;
|
||||
|
||||
AcquireSRWLockShared(&lock_); // we use atomics. using shared is fine, let's not get congested early
|
||||
@ -52,7 +52,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (timeout != 0)
|
||||
{
|
||||
start = Time::CurrentClockMS();
|
||||
start = Time::CurrentClockSteadyMS();
|
||||
if (start >= end)
|
||||
{
|
||||
ReleaseSRWLockShared(&this->lock_);
|
||||
|
@ -63,8 +63,9 @@ namespace Aurora::Threading::Primitives
|
||||
else
|
||||
{
|
||||
struct timespec tspec;
|
||||
Time::ms2tsabs(&tspec, timeout);
|
||||
Time::ms2tsabsRealtime(&tspec, timeout);
|
||||
|
||||
//
|
||||
int ret {};
|
||||
|
||||
do
|
||||
|
@ -4,12 +4,15 @@
|
||||
File: Clock.cpp
|
||||
Date: 2021-6-13
|
||||
Author: Reece
|
||||
Note: Screw it, std::chrono has been widly shilled at C++11s answer to all these painful macros, asm linkage, and other shit youd have to do to pull clock
|
||||
Semantics have changed over time. I remember when, in 2016 or something like this, msvcs implementation of chrono kept breaking things.
|
||||
Every platform that remotely pretends to support a C++ toolchain has a chrono high performance clock. Any PC-like platform that uses clang and C++ more than likely uses a vendor hacked libc++ stl.
|
||||
Seems portable enough. Worst case scenario, you're on a platform with a platform-specific high res clock function you could hack into here alongside portable timezone-unaware timegm/mktime functions somewhere else.
|
||||
There is so much quirky shit one has to deal with when relying on instruction cycle counters and other such instructions, plus cycle to ~time pred, plus forced + direction only, atop non-standard [sometimes inline]
|
||||
assembly, it's just not worth it to implement a CNTVCT_EL0 / RDSC / related userland client-app attempt of a high res clock.
|
||||
Note: Screw it, std::chrono has been widly shilled at C++11s answer to all these painful macros, asm linkage, and all the other bullshit that pulling clock counters entails.
|
||||
Semantics can and will continue to change over time. I remember when, in 2016 or something like that, msvcs implementation of chrono kept changing in minor ways.
|
||||
|
||||
However, every platform that remotely pretends to support a C++ toolchain has a chrono high performance clock, and any PC-like platform that uses clang and C++ more than likely uses a vendor hacked liblibc++ stl.
|
||||
The following should be portable enough. Worst case scenario, you're on a platform with a platform-specific high res clock function you could hack into here alongside portable timezone-unaware timegm/mktime functions linked somewhere else.
|
||||
|
||||
There is so much quirky shit one has to deal with when relying on timestamp/cycle counters (cycle to ~time pred, plus positive delta, sometimes inlined assembly), it's just not worth it to
|
||||
implement a CNTVCT_EL0 / RDSC / related interface ourselves.
|
||||
|
||||
I'll wave the white flag and use the STL in here for.now
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
@ -70,6 +73,7 @@ using high_res_clock = std::chrono::high_resolution_clock;
|
||||
#endif
|
||||
|
||||
using sys_clock = std::chrono::system_clock;
|
||||
using steady_clock = std::chrono::steady_clock;
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#define timegm _mkgmtime
|
||||
@ -155,6 +159,45 @@ namespace Aurora::Time
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(NormalizeEpoch(sys_clock::now().time_since_epoch())).count();
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 CurrentClockSteady()
|
||||
{
|
||||
return CurrentClockSteadyNS();
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 CurrentClockSteadyMS()
|
||||
{
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_getclock(CLOCK_MONOTONIC, &spec) == 0)
|
||||
{
|
||||
return AuSToMS<AuUInt64>(spec.tv_sec) + AuNSToMS<AuUInt64>(spec.tv_nsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(high_res_clock::now().time_since_epoch()).count();
|
||||
#endif
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 CurrentClockSteadyNS()
|
||||
{
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_getclock(CLOCK_MONOTONIC, &spec) == 0)
|
||||
{
|
||||
return AuMSToNS<AuUInt64>(AuSToMS<AuUInt64>(spec.tv_sec)) + (AuUInt64)spec.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(high_res_clock::now().time_since_epoch()).count();
|
||||
#endif
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
AUKN_SYM AuInt64 CTimeToMS(time_t time)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(NormalizeEpoch(sys_clock::from_time_t(time).time_since_epoch())).count();
|
||||
@ -246,6 +289,22 @@ namespace Aurora::Time
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
|
||||
#if defined(AURORA_COMPILER_MSVC)
|
||||
return frequency = _Query_perf_frequency();
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_getres(CLOCK_MONOTONIC, &spec) == 0)
|
||||
{
|
||||
if (spec.tv_nsec && !spec.tv_sec)
|
||||
{
|
||||
return frequency = 1000000000ull / spec.tv_nsec;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return frequency = static_cast<double>(high_res_clock::period::den) / static_cast<double>(high_res_clock::period::num);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,18 @@ namespace Aurora::Time
|
||||
|
||||
static void ms2tsabs(struct timespec *ts, unsigned long ms)
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, ts);
|
||||
::clock_gettime(CLOCK_MONOTONIC, ts);
|
||||
|
||||
auto baseNS = ((AuUInt64)ms * (AuUInt64)1'000'000) + (AuUInt64)ts->tv_nsec;
|
||||
auto remainderNS = (AuUInt64)baseNS % (AuUInt64)1'000'000'000;
|
||||
|
||||
ts->tv_sec += baseNS / 1'000'000'000ull;
|
||||
ts->tv_nsec = remainderNS;
|
||||
}
|
||||
|
||||
static void ms2tsabsRealtime(struct timespec *ts, unsigned long ms)
|
||||
{
|
||||
::clock_gettime(CLOCK_REALTIME, ts);
|
||||
|
||||
auto baseNS = ((AuUInt64)ms * (AuUInt64)1'000'000) + (AuUInt64)ts->tv_nsec;
|
||||
auto remainderNS = (AuUInt64)baseNS % (AuUInt64)1'000'000'000;
|
||||
@ -80,7 +91,7 @@ namespace Aurora::Time
|
||||
static void ms2tvabs(struct timeval *tv, unsigned long ms)
|
||||
{
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
::clock_gettime(CLOCK_REALTIME, &ts);
|
||||
|
||||
auto baseNS = ((AuUInt64)ms * (AuUInt64)1'000'000) + (AuUInt64)ts.tv_nsec;
|
||||
auto remainderNS = (AuUInt64)baseNS % (AuUInt64)1'000'000'000;
|
||||
|
Loading…
Reference in New Issue
Block a user