watchdog: add

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2023-10-01 23:05:54 +02:00
parent 06a896ccf6
commit 67d328a550
6 changed files with 132 additions and 1 deletions

View File

@ -128,6 +128,7 @@
<ClCompile Include="sgml.cpp" />
<ClCompile Include="stream.cpp" />
<ClCompile Include="unicode.cpp" />
<ClCompile Include="watchdog.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="compat.hpp" />

View File

@ -39,6 +39,9 @@
<ClCompile Include="hash.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="watchdog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.hpp">

View File

@ -11,6 +11,7 @@
#include "sgml.cpp"
#include "stream.cpp"
#include "unicode.cpp"
#include "watchdog.cpp"
#include <iostream>
int main(int argc, const char * argv[])
@ -34,6 +35,7 @@ int main(int argc, const char * argv[])
UnitTests::unicode::str2wstr();
UnitTests::unicode::wstr2str();
UnitTests::unicode::charset_encoder();
UnitTests::watchdog::test();
std::cout << "PASS\n";
return 0;
}

View File

@ -1,4 +1,4 @@
/*
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
@ -23,6 +23,7 @@
#include <stdex/system.hpp>
#include <stdex/unicode.hpp>
#include <stdex/vector_queue.hpp>
#include <stdex/watchdog.hpp>
#include "compat.hpp"

32
UnitTests/watchdog.cpp Normal file
View File

@ -0,0 +1,32 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
#include "pch.hpp"
using namespace std;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests
{
TEST_CLASS(watchdog)
{
public:
TEST_METHOD(test)
{
volatile bool wd_called = false;
stdex::watchdog<std::chrono::steady_clock> wd(
std::chrono::milliseconds(100), [&] { wd_called = true; });
for (int i = 0; i < 100; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
Assert::IsFalse(wd_called);
wd.reset();
}
std::this_thread::sleep_for(std::chrono::milliseconds(300));
Assert::IsTrue(wd_called);
}
};
}

View File

@ -0,0 +1,92 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
#pragma once
#include "compat.hpp"
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
namespace stdex
{
///
/// Triggers callback if not reset frequently enough
///
template <class _Clock, class _Duration = typename _Clock::duration>
class watchdog
{
public:
///
/// Starts the watchdog
///
/// \param[in] timeout How long the watchdog is waiting for a reset
/// \param[in] callback The function watchdog calls on timeout
///
watchdog(_In_ _Duration timeout, _In_ std::function<void()> callback) :
m_phase(0),
m_quit(false),
m_timeout(timeout),
m_callback(callback),
m_thread(run, std::ref(*this))
{}
///
/// Stops the watchdog
///
~watchdog()
{
{
const std::lock_guard<std::mutex> lk(m_mutex);
m_quit = true;
}
m_cv.notify_one();
if (m_thread.joinable())
m_thread.join();
}
///
/// Resets the watchdog
///
/// Must be called frequently enough not to timeout the watchdog
///
void reset()
{
{
const std::lock_guard<std::mutex> lk(m_mutex);
m_phase++;
}
m_cv.notify_one();
}
protected:
static void run(_Inout_ watchdog& wd)
{
for (;;) {
std::unique_lock<std::mutex> lk(wd.m_mutex);
auto phase = wd.m_phase;
if (wd.m_cv.wait_for(lk, wd.m_timeout, [&] {return wd.m_quit || phase != wd.m_phase; })) {
if (wd.m_quit)
break;
}
else {
wd.m_callback();
break;
}
}
}
protected:
size_t m_phase; ///< A counter we are incrementing to keep the watchdog happy
bool m_quit; ///< Quit the watchdog
_Duration m_timeout; ///< How long the watchdog is waiting for a reset
std::function<void()> m_callback; ///< The function watchdog calls on timeout
std::mutex m_mutex;
std::condition_variable m_cv;
std::thread m_thread;
};
}