summaryrefslogtreecommitdiff
path: root/boost/beast/experimental/core/detail/impl/timeout_service.ipp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/experimental/core/detail/impl/timeout_service.ipp')
-rw-r--r--boost/beast/experimental/core/detail/impl/timeout_service.ipp181
1 files changed, 181 insertions, 0 deletions
diff --git a/boost/beast/experimental/core/detail/impl/timeout_service.ipp b/boost/beast/experimental/core/detail/impl/timeout_service.ipp
new file mode 100644
index 0000000000..fd1427bda7
--- /dev/null
+++ b/boost/beast/experimental/core/detail/impl/timeout_service.ipp
@@ -0,0 +1,181 @@
+//
+// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_CORE_DETAIL_IMPL_TIMEOUT_SERVICE_IPP
+#define BOOST_BEAST_CORE_DETAIL_IMPL_TIMEOUT_SERVICE_IPP
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+//------------------------------------------------------------------------------
+
+inline
+timeout_object::
+timeout_object(boost::asio::io_context& ioc)
+ : svc_(boost::asio::use_service<timeout_service>(ioc))
+{
+}
+
+//------------------------------------------------------------------------------
+
+inline
+timeout_service::
+timeout_service(boost::asio::io_context& ctx)
+ : service_base(ctx)
+ , strand_(ctx.get_executor())
+ , timer_(ctx)
+{
+}
+
+inline
+void
+timeout_service::
+on_work_started(timeout_object& obj)
+{
+ std::lock_guard<std::mutex> lock(m_);
+ BOOST_VERIFY(++obj.outstanding_work_ == 1);
+ insert(obj, *fresh_);
+ if(++count_ == 1)
+ do_async_wait();
+}
+
+inline
+void
+timeout_service::
+on_work_complete(timeout_object& obj)
+{
+ std::lock_guard<std::mutex> lock(m_);
+ remove(obj);
+}
+
+inline
+void
+timeout_service::
+on_work_stopped(timeout_object& obj)
+{
+ std::lock_guard<std::mutex> lock(m_);
+ BOOST_ASSERT(count_ > 0);
+ BOOST_VERIFY(--obj.outstanding_work_ == 0);
+ if(obj.list_ != nullptr)
+ remove(obj);
+ if(--count_ == 0)
+ timer_.cancel();
+}
+
+inline
+void
+timeout_service::
+set_option(std::chrono::seconds n)
+{
+ interval_ = n;
+}
+
+//------------------------------------------------------------------------------
+
+// Precondition: caller holds the mutex
+inline
+void
+timeout_service::
+insert(timeout_object& obj, list_type& list)
+{
+ BOOST_ASSERT(obj.list_ == nullptr);
+ list.push_back(&obj); // can throw
+ obj.list_ = &list;
+ obj.pos_ = list.size();
+}
+
+// Precondition: caller holds the mutex
+inline
+void
+timeout_service::
+remove(timeout_object& obj)
+{
+ BOOST_ASSERT(obj.list_ != nullptr);
+ BOOST_ASSERT(
+ obj.list_ == stale_ ||
+ obj.list_ == fresh_);
+ BOOST_ASSERT(obj.list_->size() > 0);
+ auto& list = *obj.list_;
+ auto const n = list.size() - 1;
+ if(obj.pos_ != n)
+ {
+ auto other = list[n];
+ list[obj.pos_] = other;
+ other->pos_ = obj.pos_;
+ }
+ obj.list_ = nullptr;
+ list.resize(n);
+}
+
+inline
+void
+timeout_service::
+do_async_wait()
+{
+ timer_.expires_after(interval_);
+ timer_.async_wait(
+ boost::asio::bind_executor(
+ strand_,
+ [this](error_code ec)
+ {
+ this->on_timer(ec);
+ }));
+}
+
+inline
+void
+timeout_service::
+on_timer(error_code ec)
+{
+ if(ec == boost::asio::error::operation_aborted)
+ {
+ BOOST_ASSERT(fresh_->empty());
+ BOOST_ASSERT(stale_->empty());
+ return;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(m_);
+ if(! stale_->empty())
+ {
+ for(auto obj : *stale_)
+ {
+ obj->list_ = nullptr;
+ obj->on_timeout();
+ }
+ stale_->clear();
+ }
+ std::swap(fresh_, stale_);
+ }
+
+ do_async_wait();
+}
+
+//------------------------------------------------------------------------------
+
+inline
+void
+timeout_service::
+shutdown() noexcept
+{
+ boost::asio::post(
+ boost::asio::bind_executor(
+ strand_,
+ [this]()
+ {
+ timer_.cancel();
+ }));
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif