mirror of
https://github.com/XRPLF/clio.git
synced 2026-06-03 08:46:42 +00:00
chore: Repeat-based tests TSAN fixes (#2810)
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "util/Repeat.hpp"
|
||||
|
||||
#include <boost/asio/post.hpp>
|
||||
|
||||
namespace util {
|
||||
|
||||
void
|
||||
@@ -27,8 +29,11 @@ Repeat::stop()
|
||||
if (control_->stopping)
|
||||
return;
|
||||
|
||||
control_->stopping = true;
|
||||
control_->timer.cancel();
|
||||
boost::asio::post(control_->strand, [control = control_] {
|
||||
control->stopping = true;
|
||||
control->timer.cancel();
|
||||
});
|
||||
|
||||
control_->semaphore.acquire();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
|
||||
#include "util/Assert.hpp"
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
@@ -41,10 +43,11 @@ namespace util {
|
||||
class Repeat {
|
||||
struct Control {
|
||||
boost::asio::steady_timer timer;
|
||||
boost::asio::strand<boost::asio::any_io_executor> strand;
|
||||
std::atomic_bool stopping{true};
|
||||
std::binary_semaphore semaphore{0};
|
||||
|
||||
Control(auto& ctx) : timer(ctx)
|
||||
Control(auto& ctx) : timer(ctx), strand(boost::asio::make_strand(ctx))
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -98,15 +101,24 @@ private:
|
||||
static void
|
||||
startImpl(std::shared_ptr<Control> control, std::chrono::steady_clock::duration interval, Action&& action)
|
||||
{
|
||||
control->timer.expires_after(interval);
|
||||
control->timer.async_wait([control, interval, action = std::forward<Action>(action)](auto const& ec) mutable {
|
||||
if (ec or control->stopping) {
|
||||
boost::asio::post(control->strand, [control, interval, action = std::forward<Action>(action)]() mutable {
|
||||
if (control->stopping) {
|
||||
control->semaphore.release();
|
||||
return;
|
||||
}
|
||||
action();
|
||||
|
||||
startImpl(std::move(control), interval, std::forward<Action>(action));
|
||||
control->timer.expires_after(interval);
|
||||
control->timer.async_wait(
|
||||
[control, interval, action = std::forward<Action>(action)](auto const& ec) mutable {
|
||||
if (ec or control->stopping) {
|
||||
control->semaphore.release();
|
||||
return;
|
||||
}
|
||||
action();
|
||||
|
||||
startImpl(std::move(control), interval, std::forward<Action>(action));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -53,16 +53,16 @@ struct RepeatTests : SyncAsioContextTest {
|
||||
|
||||
TEST_F(RepeatTests, CallsHandler)
|
||||
{
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
EXPECT_CALL(handlerMock, Call).Times(testing::AtMost(22));
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
runContextFor(std::chrono::milliseconds{20});
|
||||
}
|
||||
|
||||
TEST_F(RepeatTests, StopsOnStop)
|
||||
{
|
||||
withRunningContext([this]() {
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
EXPECT_CALL(handlerMock, Call).Times(AtLeast(1));
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{10});
|
||||
repeat.stop();
|
||||
});
|
||||
@@ -72,8 +72,8 @@ TEST_F(RepeatTests, RunsAfterStop)
|
||||
{
|
||||
withRunningContext([this]() {
|
||||
for ([[maybe_unused]] auto i : std::ranges::iota_view(0, 2)) {
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
EXPECT_CALL(handlerMock, Call).Times(AtLeast(1));
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{10});
|
||||
repeat.stop();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user