ranczo-io/include/boost/asio/basic_repeating_timer.hpp
2024-11-05 10:41:40 +01:00

179 lines
6.5 KiB
C++

#ifndef BOOST_ASIO_REPEATING_TIMER_H_INCLUDED
#define BOOST_ASIO_REPEATING_TIMER_H_INCLUDED
// Adapted from the original, developed 2007 by David C. Wyles (http:///www.codegorilla.co.uk)
// released for public consumption under the same
// licensing policy as the boost library http://www.boost.org/LICENSE_1_0.txt
//
// most people will use the repeating_timer typedef for working with posix time
//
// Is is based on the basic_deadline_timer
//
// Updated 2021 by Michael Haben, for compatibility with Boost 1.77 / ASIO 1.18.2
// - uses an executor instead of an io_service or io_context.
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/weak_ptr.hpp>
namespace boost {
namespace asio {
// basic repeating timer with start/stop semantics.
template < typename Time, typename TimeTraits = boost::asio::time_traits< Time >, typename Executor = boost::asio::any_io_executor >
class basic_repeating_timer {
public:
typedef boost::asio::basic_deadline_timer< Time > timer_type;
explicit basic_repeating_timer(Executor ex) : ex_(ex) {}
~basic_repeating_timer() {
stop();
}
template < typename WaitHandler >
void start(typename timer_type::duration_type const & repeat_interval, WaitHandler handler) {
boost::recursive_mutex::scoped_lock guard(lock_);
{
// cleanup code, cancel any existing timer
handler_.reset();
if(timer_) {
timer_->cancel();
}
timer_.reset();
}
// create new handler.
handler_.reset(new handler_impl< WaitHandler >(handler));
// create new timer
timer_ = internal_timer::create(this->ex_, repeat_interval, handler_);
}
void stop() {
boost::recursive_mutex::scoped_lock guard(lock_);
{
// cleanup code.
handler_.reset();
if(timer_) {
timer_->cancel();
}
timer_.reset();
}
}
void cancel() {
stop();
}
// changes the interval the next time the timer is fired.
void change_interval(typename timer_type::duration_type const & repeat_interval) {
boost::recursive_mutex::scoped_lock guard(lock_);
if(timer_) {
timer_->change_interval(repeat_interval);
}
}
private:
const Executor & ex_;
boost::recursive_mutex lock_;
class internal_timer;
typedef boost::shared_ptr< internal_timer > internal_timer_ptr;
typedef boost::asio::executor executor_type;
internal_timer_ptr timer_;
class handler_base;
boost::shared_ptr< handler_base > handler_;
class handler_base {
public:
virtual ~handler_base() {}
virtual void handler(boost::system::error_code const &) = 0;
};
template < typename HandlerFunc >
class handler_impl : public handler_base {
public:
handler_impl(HandlerFunc func) : handler_func_(func) {}
virtual void handler(boost::system::error_code const & result) {
handler_func_(result);
}
HandlerFunc handler_func_;
};
class internal_timer : public boost::enable_shared_from_this< internal_timer > {
public:
static internal_timer_ptr create(const Executor & ex,
typename timer_type::duration_type const & repeat_interval,
boost::shared_ptr< handler_base > const & handler) {
internal_timer_ptr timer(new internal_timer(ex));
timer->start(repeat_interval, handler);
return timer;
}
void cancel() {
boost::recursive_mutex::scoped_lock guard(lock_);
timer_.cancel();
}
void change_interval(typename timer_type::duration_type const & repeat_interval) {
boost::recursive_mutex::scoped_lock guard(lock_);
interval_ = repeat_interval;
}
private:
timer_type timer_;
boost::weak_ptr< handler_base > handler_;
typename timer_type::duration_type interval_;
boost::recursive_mutex lock_;
internal_timer(boost::asio::any_io_executor ex) : timer_(ex) {}
void start(typename timer_type::duration_type const & repeat_interval, boost::shared_ptr< handler_base > const & handler) {
// only EVER called once, via create
interval_ = repeat_interval;
handler_ = handler;
timer_.expires_from_now(interval_);
timer_.async_wait(boost::bind(&internal_timer::handle_timeout, this->shared_from_this(), boost::asio::placeholders::error));
}
void handle_timeout(boost::system::error_code const & error) {
// we lock in the timeout to block the cancel operation until this timeout completes
boost::recursive_mutex::scoped_lock guard(lock_);
{
// do the fire.
boost::shared_ptr< handler_base > Handler = handler_.lock();
if(Handler) {
try {
Handler->handler(error);
} catch(std::exception const & e) {
// consume for now, no much else we can do, we don't want to damage the
// io_context thread
( void ) e;
}
}
}
if(!error) {
// check if we need to reschedule.
boost::shared_ptr< handler_base > Handler = handler_.lock();
if(Handler) {
timer_.expires_from_now(interval_);
timer_.async_wait(
boost::bind(&internal_timer::handle_timeout, this->shared_from_this(), boost::asio::placeholders::error));
}
}
}
};
};
typedef basic_repeating_timer< boost::posix_time::ptime > repeating_timer;
} // namespace asio
} // namespace boost
#endif