Commit 57d9e752 authored by Dominik Charousset's avatar Dominik Charousset

Abort watchdog properly via condition variable

parent 39aed93e
#include <mutex>
#include <atomic>
#include <thread>
#include <condition_variable>
#include "test.hpp"
#include "caf/all.hpp"
......@@ -8,9 +11,45 @@ using namespace std;
using namespace caf;
namespace {
atomic<size_t> s_error_count{0};
std::mutex s_stdout_mtx;
}
class watchdog {
public:
watchdog() {
m_thread = thread([&] {
auto tp = chrono::high_resolution_clock::now() + chrono::seconds(10);
unique_lock<mutex> guard{m_mtx};
while (!m_canceled
&& m_cv.wait_until(guard, tp) != cv_status::timeout) {
// spin
}
if (!m_canceled) {
std::lock_guard<std::mutex> io_guard{s_stdout_mtx};
cerr << "WATCHDOG: unit test did finish within 10s, abort" << endl;
abort();
}
});
}
~watchdog() {
{ // lifetime scope of guard
std::lock_guard<std::mutex> guard{m_mtx};
m_canceled = true;
m_cv.notify_all();
}
m_thread.join();
}
volatile bool m_canceled = false;
std::mutex m_mtx;
std::condition_variable m_cv;
std::thread m_thread;
};
watchdog* s_watchdog;
} // namespace <anonymous>
std::mutex& caf_stdout_mtx() {
return s_stdout_mtx;
......@@ -24,6 +63,14 @@ void caf_inc_error_count() {
++s_error_count;
}
void caf_launch_watchdog() {
s_watchdog = new watchdog;
}
void caf_cancel_watchdog() {
delete s_watchdog;
}
string caf_fill4(size_t value) {
string result = to_string(value);
while (result.size() < 4) result.insert(result.begin(), '0');
......
......@@ -147,19 +147,16 @@ inline void caf_check_value(V1 v1, V2 v2, const char* fname, size_t line,
#define CAF_VERBOSE_EVAL(LineOfCode) \
CAF_PRINT(#LineOfCode << " = " << (LineOfCode));
void caf_launch_watchdog();
void caf_cancel_watchdog();
#define CAF_TEST(testname) \
::std::thread([] { \
::std::this_thread::sleep_for(std::chrono::seconds(10)); \
::std::cerr << "WATCHDOG: unit test did finish within 10s, abort\n"; \
::abort(); \
}).detach(); \
auto caf_test_scope_guard = ::caf::detail::make_scope_guard([] { \
std::cout << caf_error_count() << " error(s) detected" << std::endl; \
}); \
caf_launch_watchdog(); \
set_default_test_settings(); \
CAF_LOGF_INFO("run unit test " << #testname)
#define CAF_TEST_RESULT() ((caf_error_count() == 0) ? 0 : -1)
#define CAF_TEST_RESULT() \
caf_cancel_watchdog(), ((caf_error_count() == 0) ? 0 : -1)
#define CAF_CHECK_VERBOSE(line_of_code, err_stream) \
if (!(line_of_code)) { \
......
......@@ -79,7 +79,7 @@ behavior tester(event_based_actor* self, const actor& aut) {
};
}
#define BREAK_ON_ERROR() if (CAF_TEST_RESULT() > 0) return
#define BREAK_ON_ERROR() if (caf_error_count() > 0) return
template <spawn_options O1, spawn_options O2>
void run() {
......
......@@ -100,7 +100,7 @@ void test_message_lifetime_in_scoped_actor() {
template <spawn_options Os>
void test_message_lifetime() {
test_message_lifetime_in_scoped_actor();
if (CAF_TEST_RESULT() != 0) {
if (caf_error_count() != 0) {
return;
}
// put some preassure on the scheduler (check for thread safety)
......
......@@ -8,6 +8,7 @@ using namespace std;
using namespace caf;
int main() {
CAF_TEST(test_optional);
{
optional<int> i,j;
CAF_CHECK(i == j);
......
......@@ -73,6 +73,7 @@ uint16_t run_server() {
}
int main(int argc, char** argv) {
CAF_TEST(test_typed_remote_actor)
announce<ping>("ping", &ping::value);
announce<pong>("pong", &pong::value);
message_builder{argv + 1, argv + argc}.apply({
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment