Skip to content

Commit 6bb30f0

Browse files
committed
UnitTest & ThreadLoop: Fix deadlock
1 parent b6dc344 commit 6bb30f0

4 files changed

Lines changed: 25 additions & 9 deletions

File tree

modules/Execution/EventQueue.mpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import CppUtils.Execution.EventDispatcher;
66
import CppUtils.Execution.ScopeGuard;
77
import CppUtils.Thread.ThreadLoop;
88
import CppUtils.Thread.UniqueLocker;
9+
import CppUtils.Chrono.Concept;
910

1011
export namespace CppUtils::Execution
1112
{
@@ -51,10 +52,17 @@ export namespace CppUtils::Execution
5152
m_dispatcher.subscribe<eventName>(std::forward<decltype(function)>(function));
5253
}
5354

54-
inline auto waitUntilFinished() -> void
55+
template<Chrono::Duration Duration = std::chrono::milliseconds>
56+
inline auto waitUntilFinished(Duration timeout = Duration::zero()) -> bool
5557
{
5658
auto accessor = m_queue.access();
57-
m_condition.wait(accessor.getLockGuard(), [this, &accessor] { return accessor.value().empty() and not m_isTaskRunning; });
59+
auto predicate = [this, &accessor] { return std::empty(accessor.value()) and not m_isTaskRunning; };
60+
if (timeout == Duration::zero())
61+
{
62+
m_condition.wait(accessor.getLockGuard(), predicate);
63+
return true;
64+
}
65+
return m_condition.wait_for(accessor.getLockGuard(), timeout, predicate);
5866
}
5967

6068
private:
@@ -73,10 +81,10 @@ export namespace CppUtils::Execution
7381
{
7482
auto accessor = m_queue.access();
7583
m_condition.wait(accessor.getLockGuard(), [this, &accessor] {
76-
return not accessor.value().empty() or m_worker.isStopRequested();
84+
return not std::empty(accessor.value()) or m_worker.isStopRequested();
7785
});
7886

79-
if (accessor.value().empty())
87+
if (std::empty(accessor.value()))
8088
return;
8189

8290
m_isTaskRunning = true;

modules/Log/Logger.mpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import CppUtils.Pattern.Multiton;
1111
import CppUtils.Terminal.Size;
1212
import CppUtils.Terminal.TextColor;
1313
import CppUtils.Terminal.TextModifier;
14+
import CppUtils.Chrono.Concept;
1415

1516
// Todo: log le datetime
1617
// Todo: log le stacktrace ( https://en.cppreference.com/w/cpp/utility/stacktrace_entry )
@@ -59,9 +60,10 @@ export namespace CppUtils
5960
eventQueue().template subscribe<logType>(std::forward<decltype(function)>(function));
6061
}
6162

62-
static inline auto waitUntilFinished() -> void
63+
template<Chrono::Duration Duration = std::chrono::milliseconds>
64+
static inline auto waitUntilFinished(Duration timeout = Duration::zero()) -> bool
6365
{
64-
eventQueue().waitUntilFinished();
66+
return eventQueue().waitUntilFinished(timeout);
6567
}
6668
};
6769

modules/Thread/ThreadLoop.mpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export namespace CppUtils::Thread
7575
return;
7676

7777
m_thread = std::jthread{[function = m_function, interruptFunction = m_interruptFunction, onError = m_onError](std::stop_token stopToken) mutable -> void {
78+
using namespace std::chrono_literals;
7879
while (not stopToken.stop_requested())
7980
{
8081
try
@@ -93,15 +94,18 @@ export namespace CppUtils::Thread
9394
catch (const std::exception& exception)
9495
{
9596
std::println(stderr, "ThreadLoop: onError threw an exception: {}", exception.what());
97+
std::this_thread::sleep_for(100ms);
9698
}
9799
catch (...)
98100
{
99101
std::println(stderr, "ThreadLoop: onError threw a non-std exception");
102+
std::this_thread::sleep_for(100ms);
100103
}
101104
}
102105
else
103106
{
104-
std::println(stderr, "ThreadLoop: Unhandled exception");
107+
std::println(stderr, "ThreadLoop: Unhandled exception, cooling down...");
108+
std::this_thread::sleep_for(100ms);
105109
}
106110
}
107111
}

modules/UnitTest/UnitTest.mpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ namespace CppUtils::UnitTest
6363

6464
inline auto executeTest(const Test& test, const TestSettings& settings) const -> bool
6565
{
66+
using namespace std::chrono_literals;
6667
if (settings.verbose)
6768
{
6869
Logger::emit<"separator">();
@@ -116,12 +117,13 @@ namespace CppUtils::UnitTest
116117
}
117118
if (settings.verbose)
118119
Logger::print<"success">("Passed");
119-
Logger::waitUntilFinished();
120+
Logger::waitUntilFinished(10s);
120121
return true;
121122
}
122123

123124
inline auto executeTests(TestSettings settings) -> int
124125
{
126+
using namespace std::chrono_literals;
125127
auto testSuiteIsSuccess = std::unordered_map<std::string, bool>{};
126128

127129
const auto nbTests = std::ranges::fold_left(
@@ -209,7 +211,7 @@ namespace CppUtils::UnitTest
209211
Logger::emit<"color">(Terminal::TextColor::TextColorEnum::Yellow, std::format(" - {}", skippedTestSuite));
210212
}
211213

212-
Logger::waitUntilFinished();
214+
Logger::waitUntilFinished(10s);
213215
return nbFail == 0 ? exitSuccess : exitFailure;
214216
}
215217

0 commit comments

Comments
 (0)