Files
UnrealEngine/Engine/Plugins/Runtime/nDisplay/Source/DisplayCluster/Private/Misc/DisplayClusterWatchdogTimer.cpp
2025-05-18 13:04:45 +08:00

125 lines
2.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Misc/DisplayClusterWatchdogTimer.h"
#include "Misc/DisplayClusterLog.h"
#include "Misc/ScopeLock.h"
#include "HAL/RunnableThread.h"
FDisplayClusterWatchdogTimer::FDisplayClusterWatchdogTimer(const FString& InTimerName)
: TimerName(InTimerName)
{
ThreadObj.Reset(FRunnableThread::Create(this, *(TimerName + FString("_thread")), 128 * 1024, TPri_Normal));
}
FDisplayClusterWatchdogTimer::~FDisplayClusterWatchdogTimer()
{
// Stop working thread
Stop();
}
bool FDisplayClusterWatchdogTimer::SetTimer(const uint32 InTimeout)
{
FScopeLock Lock(&InternalsCS);
// Check if timer was set already
if (bIsTimerSet)
{
return false;
}
// Update timer internals
bIsTimerSet = true;
Timeout = InTimeout;
// Start timer
EvtStartTimer->Trigger();
return true;
}
void FDisplayClusterWatchdogTimer::ResetTimer()
{
FScopeLock Lock(&InternalsCS);
// Check if timer was set previously
if (bIsTimerSet)
{
// Set 'reset' flag to let the working thread know we're reseting the timer
bTimerWasReset = true;
// Release waitable object
EvtWaitableObject->Trigger();
}
}
uint32 FDisplayClusterWatchdogTimer::Run()
{
UE_LOG(LogDisplayClusterNetwork, Log, TEXT("Watchdog %s: working thread started"), *TimerName);
while (!bThreadExitRequested)
{
// Wait for timer start command
EvtStartTimer->Wait();
// Check if need to stop the thread
if (bThreadExitRequested)
{
break;
}
UE_LOG(LogDisplayClusterNetwork, Verbose, TEXT("Watchdog %s: timer set - %u ms"), *TimerName, Timeout);
// Wait for specified amount of time
EvtWaitableObject->Wait(Timeout);
// Check again if need to stop the thread
if (bThreadExitRequested)
{
break;
}
{
FScopeLock Lock(&InternalsCS);
// If the timer was not reset manually, we need to notify the listeners about timeout
if (!bTimerWasReset)
{
UE_LOG(LogDisplayClusterNetwork, Log, TEXT("Watchdog %s: timeout!"), *TimerName);
OnWatchdogTimeOut().Broadcast();
}
else
{
UE_LOG(LogDisplayClusterNetwork, Verbose, TEXT("Watchdog %s: timer reset"), *TimerName);
}
// Reset internal state so the timer is ready for new start
bIsTimerSet = false;
bTimerWasReset = false;
EvtStartTimer->Reset();
EvtWaitableObject->Reset();
}
}
UE_LOG(LogDisplayClusterNetwork, Log, TEXT("Watchdog %s: working thread finished"), *TimerName);
return 0;
}
void FDisplayClusterWatchdogTimer::Stop()
{
// Let the working thread know it has to stop
bThreadExitRequested = true;
// Release sync objects to unblock the working thread
EvtStartTimer->Trigger();
EvtWaitableObject->Trigger();
// Wait unless working thread is finished
if (ThreadObj)
{
ThreadObj->WaitForCompletion();
}
}