Timeout#~Timeout(), #Cancel(): support boost::asio::io_context running on multiple threads

This commit is contained in:
Alexander A. Klimov 2024-11-29 14:16:08 +01:00
parent cb51649363
commit 959b162913
3 changed files with 33 additions and 5 deletions

View File

@ -148,6 +148,8 @@ void AsioConditionVariable::Wait(boost::asio::yield_context yc)
void Timeout::Cancel()
{
m_Cancelled->store(true);
boost::system::error_code ec;
m_Timer.cancel(ec);
}

View File

@ -3,10 +3,12 @@
#ifndef IO_ENGINE_H
#define IO_ENGINE_H
#include "base/atomic.hpp"
#include "base/debug.hpp"
#include "base/exception.hpp"
#include "base/lazy-init.hpp"
#include "base/logger.hpp"
#include "base/shared.hpp"
#include "base/shared-object.hpp"
#include <atomic>
#include <exception>
@ -174,21 +176,29 @@ public:
template<class OnTimeout>
Timeout(boost::asio::io_context::strand& strand, const Timer::duration_type& timeoutFromNow, OnTimeout onTimeout)
: m_Timer(strand.context(), timeoutFromNow)
: m_Timer(strand.context(), timeoutFromNow), m_Cancelled(Shared<Atomic<bool>>::Make(false))
{
VERIFY(strand.running_in_this_thread());
m_Timer.async_wait(boost::asio::bind_executor(strand, [onTimeout = std::move(onTimeout)](boost::system::error_code ec) {
if (!ec) {
onTimeout();
m_Timer.async_wait(boost::asio::bind_executor(
strand, [cancelled = m_Cancelled, onTimeout = std::move(onTimeout)](boost::system::error_code ec) {
if (!ec && !cancelled->load()) {
onTimeout();
}
}
}));
));
}
~Timeout() override
{
Cancel();
}
void Cancel();
private:
Timer m_Timer;
Shared<Atomic<bool>>::Ptr m_Cancelled;
};
}

View File

@ -5,6 +5,7 @@
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <BoostTestTargetConfig.h>
#include <thread>
using namespace icinga;
@ -30,7 +31,10 @@ BOOST_AUTO_TEST_CASE(timeout_run)
timer.async_wait(yc);
});
std::thread eventLoop ([&io] { io.run(); });
io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 1);
}
@ -54,7 +58,10 @@ BOOST_AUTO_TEST_CASE(timeout_cancelled)
timer.async_wait(yc);
});
std::thread eventLoop ([&io] { io.run(); });
io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0);
}
@ -80,7 +87,10 @@ BOOST_AUTO_TEST_CASE(timeout_scope)
timer.async_wait(yc);
});
std::thread eventLoop ([&io] { io.run(); });
io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0);
}
@ -108,7 +118,10 @@ BOOST_AUTO_TEST_CASE(timeout_due_cancelled)
timer.async_wait(yc);
});
std::thread eventLoop ([&io] { io.run(); });
io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0);
}
@ -136,7 +149,10 @@ BOOST_AUTO_TEST_CASE(timeout_due_scope)
timer.async_wait(yc);
});
std::thread eventLoop ([&io] { io.run(); });
io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0);
}