123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- #ifndef BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_RUN_WITH_TIMEOUT_HPP
- #define BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_RUN_WITH_TIMEOUT_HPP
- #include <boost/mysql/client_errc.hpp>
- #include <boost/mysql/error_code.hpp>
- #include <boost/asio/any_io_executor.hpp>
- #include <boost/asio/associated_allocator.hpp>
- #include <boost/asio/bind_executor.hpp>
- #include <boost/asio/cancellation_signal.hpp>
- #include <chrono>
- #include <cstddef>
- #include <memory>
- #include <type_traits>
- #include <utility>
- namespace boost {
- namespace mysql {
- namespace detail {
- template <class Timer, class Handler>
- struct run_with_timeout_state
- {
- using this_type = run_with_timeout_state<Timer, Handler>;
-
- asio::cancellation_signal op_signal;
-
- std::size_t remaining;
-
- error_code final_ec;
-
- Handler handler;
-
- Timer& timer;
- run_with_timeout_state(Handler&& handler, Timer& timer)
- : remaining(2), handler(std::move(handler)), timer(timer)
- {
- }
-
- static void complete_one_op(std::shared_ptr<this_type>&& ptr)
- {
-
- if (ptr->remaining == 0u)
- {
-
- auto h = std::move(ptr->handler);
- error_code ec = ptr->final_ec;
-
- ptr.reset();
-
- std::move(h)(ec);
- }
- }
-
- struct timer_handler
- {
- std::shared_ptr<this_type> st;
- void operator()(error_code ec)
- {
-
-
- if (st->remaining-- == 2u)
- {
- st->final_ec = ec ? client_errc::cancelled : client_errc::timeout;
- st->op_signal.emit(asio::cancellation_type::terminal);
- }
-
- complete_one_op(std::move(st));
- }
- };
-
-
- struct op_handler
- {
- std::shared_ptr<this_type> st;
- void operator()(error_code ec)
- {
-
- if (st->remaining-- == 2u)
- {
- st->final_ec = ec;
- st->timer.cancel();
- }
-
- complete_one_op(std::move(st));
- }
-
- using executor_type = asio::any_io_executor;
- executor_type get_executor() const { return st->timer.get_executor(); }
-
- using cancellation_slot_type = asio::cancellation_slot;
- cancellation_slot_type get_cancellation_slot() const noexcept { return st->op_signal.slot(); }
- };
- };
- template <class Op, class Timer, class Handler>
- void run_with_timeout(Op&& op, Timer& timer, std::chrono::steady_clock::duration timeout, Handler&& handler)
- {
- if (timeout.count() > 0)
- {
- using state_t = run_with_timeout_state<Timer, typename std::decay<Handler>::type>;
-
- auto alloc = asio::get_associated_allocator(handler);
- using alloc_t = typename std::allocator_traits<decltype(alloc)>::template rebind_alloc<state_t>;
- auto st = std::allocate_shared<state_t>(alloc_t(alloc), std::move(handler), timer);
-
- timer.expires_after(timeout);
- timer.async_wait(typename state_t::timer_handler{st});
-
- std::move(op)(typename state_t::op_handler{std::move(st)});
- }
- else
- {
- std::forward<Op>(op)(asio::bind_executor(timer.get_executor(), std::move(handler)));
- }
- }
- }
- }
- }
- #endif
|