AuroraRuntime/Source/Async/AuAsyncTimer.cpp

154 lines
4.1 KiB
C++

/***
Copyright (C) 2021-2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuAsyncTimer.cpp
Date: 2023-12-06
Date: 2021-11-2
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "IAsyncRunnable.hpp"
#include "AuAsyncTimer.hpp"
#include "ThreadPool.hpp"
namespace Aurora::Async
{
AsyncFuncTimer::AsyncFuncTimer(IThreadPoolInternal *owner,
const AuSPtr<IAsyncTimerCallback> &pCallback,
const WorkerPId_t &worker,
AuUInt64 uNextTickTime,
AuUInt64 uInterval) :
WorkItem(owner, worker, {}),
uNextTickTime(uNextTickTime),
uInterval(uInterval),
pCallback(pCallback)
{
}
void AsyncFuncTimer::CancelTimer()
{
AU_LOCK_GUARD(this->mutex);
this->Cancel();
AuResetMember(this->pCallback);
}
AuUInt64 AsyncFuncTimer::GetLastTime()
{
return this->uLastTickTime;
}
AuUInt64 AsyncFuncTimer::GetTicks()
{
return this->uTickCount;
}
bool AsyncFuncTimer::IsCatchUp()
{
return this->bCatchUp;
}
void AsyncFuncTimer::SetCatchUp(bool bCatchUp)
{
this->bCatchUp = bCatchUp;
}
void AsyncFuncTimer::DispatchTask(IWorkItemHandler::ProcessInfo &info)
{
AU_LOCK_GUARD(this->mutex);
info.type = ETickType::eRerun;
auto uTickCount = ++this->uTickCount;
this->uLastTickTime = AuTime::SteadyClockNS();
auto uDelta = this->uLastTickTime - this->uNextTickTime;
this->uNextTickTime += this->uInterval;
if (!this->bCatchUp)
{
this->uNextTickTime = AuMax(this->uNextTickTime, this->uLastTickTime);
}
info.reschedSteadyClockAbsNs = this->uNextTickTime;
if (!this->pCallback)
{
return;
}
try
{
if (this->pCallback->OnTick(uTickCount, uDelta, this->uLastTickTime))
{
info.type = ETickType::eSchedule;
}
else
{
info.type = ETickType::eFinished;
}
}
catch (...)
{
info.type = ETickType::eSchedule;
SysPushErrorCatch();
}
}
void AsyncFuncTimer::Cleanup()
{
AuResetMember(this->pCallback);
}
AUKN_SYM AuSPtr<IAsyncTimer> NewTimer(AuUInt64 uPeriodNS,
const AuSPtr<IAsyncTimerCallback> &pCallback,
AuOptional<WorkerPId_t> workerPid,
AuOptional<AuUInt64> uStartTime)
{
if (!pCallback)
{
SysPushErrorArg();
return {};
}
if (!workerPid)
{
workerPid = AuAsync::GetCurrentWorkerPId();
}
if (uPeriodNS < 100)
{
SysPushErrorArg();
return {};
}
if (!uStartTime)
{
uStartTime = AuTime::SteadyClockNS() + uPeriodNS;
}
auto pThreadPool = AuStaticPointerCast<ThreadPool>(workerPid.value().GetPool()).get();
auto pRet = AuMakeShared<AsyncFuncTimer>(pThreadPool,
pCallback,
workerPid.value(),
uStartTime.value(),
uPeriodNS);
if (!pRet)
{
return {};
}
pRet->Dispatch();
return pRet;
}
AUKN_SYM AuSPtr<IAsyncTimer> NewTimer(AuUInt64 uPeriodNS,
const AuSupplierConsumer<bool, AuUInt64, AuUInt64, AuUInt64> &callback,
AuOptional<WorkerPId_t> workerPid,
AuOptional<AuUInt64> uStartTime)
{
return NewTimer(uPeriodNS,
AuMakeSharedThrow<IAsyncTimerCallbackFunctional>(callback),
workerPid,
uStartTime);
}
}