125 lines
2.7 KiB
C++
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();
|
|
}
|
|
}
|