File indexing completed on 2025-07-01 08:08:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019 #include <cstddef>
0020 #include <boost/asio/associated_cancellation_slot.hpp>
0021 #include <boost/asio/cancellation_type.hpp>
0022 #include <boost/asio/error.hpp>
0023 #include <boost/asio/execution_context.hpp>
0024 #include <boost/asio/detail/bind_handler.hpp>
0025 #include <boost/asio/detail/fenced_block.hpp>
0026 #include <boost/asio/detail/memory.hpp>
0027 #include <boost/asio/detail/noncopyable.hpp>
0028 #include <boost/asio/detail/socket_ops.hpp>
0029 #include <boost/asio/detail/socket_types.hpp>
0030 #include <boost/asio/detail/timer_queue.hpp>
0031 #include <boost/asio/detail/timer_queue_ptime.hpp>
0032 #include <boost/asio/detail/timer_scheduler.hpp>
0033 #include <boost/asio/detail/wait_handler.hpp>
0034 #include <boost/asio/detail/wait_op.hpp>
0035
0036 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0037 # include <chrono>
0038 # include <thread>
0039 #endif
0040
0041 #include <boost/asio/detail/push_options.hpp>
0042
0043 namespace boost {
0044 namespace asio {
0045 namespace detail {
0046
0047 template <typename Time_Traits>
0048 class deadline_timer_service
0049 : public execution_context_service_base<deadline_timer_service<Time_Traits>>
0050 {
0051 public:
0052
0053 typedef typename Time_Traits::time_type time_type;
0054
0055
0056 typedef typename Time_Traits::duration_type duration_type;
0057
0058
0059
0060 struct implementation_type
0061 : private boost::asio::detail::noncopyable
0062 {
0063 time_type expiry;
0064 bool might_have_pending_waits;
0065 typename timer_queue<Time_Traits>::per_timer_data timer_data;
0066 };
0067
0068
0069 deadline_timer_service(execution_context& context)
0070 : execution_context_service_base<
0071 deadline_timer_service<Time_Traits>>(context),
0072 scheduler_(boost::asio::use_service<timer_scheduler>(context))
0073 {
0074 scheduler_.init_task();
0075 scheduler_.add_timer_queue(timer_queue_);
0076 }
0077
0078
0079 ~deadline_timer_service()
0080 {
0081 scheduler_.remove_timer_queue(timer_queue_);
0082 }
0083
0084
0085 void shutdown()
0086 {
0087 }
0088
0089
0090 void construct(implementation_type& impl)
0091 {
0092 impl.expiry = time_type();
0093 impl.might_have_pending_waits = false;
0094 }
0095
0096
0097 void destroy(implementation_type& impl)
0098 {
0099 boost::system::error_code ec;
0100 cancel(impl, ec);
0101 }
0102
0103
0104 void move_construct(implementation_type& impl,
0105 implementation_type& other_impl)
0106 {
0107 if (other_impl.might_have_pending_waits)
0108 {
0109 scheduler_.move_timer(timer_queue_,
0110 impl.timer_data, other_impl.timer_data);
0111 }
0112
0113 impl.expiry = other_impl.expiry;
0114 other_impl.expiry = time_type();
0115
0116 impl.might_have_pending_waits = other_impl.might_have_pending_waits;
0117 other_impl.might_have_pending_waits = false;
0118 }
0119
0120
0121 void move_assign(implementation_type& impl,
0122 deadline_timer_service& other_service,
0123 implementation_type& other_impl)
0124 {
0125 if (this != &other_service)
0126 if (impl.might_have_pending_waits)
0127 scheduler_.cancel_timer(timer_queue_, impl.timer_data);
0128
0129 other_service.scheduler_.move_timer(other_service.timer_queue_,
0130 impl.timer_data, other_impl.timer_data);
0131
0132 impl.expiry = other_impl.expiry;
0133 other_impl.expiry = time_type();
0134
0135 impl.might_have_pending_waits = other_impl.might_have_pending_waits;
0136 other_impl.might_have_pending_waits = false;
0137 }
0138
0139
0140 void converting_move_construct(implementation_type& impl,
0141 deadline_timer_service&, implementation_type& other_impl)
0142 {
0143 move_construct(impl, other_impl);
0144 }
0145
0146
0147 void converting_move_assign(implementation_type& impl,
0148 deadline_timer_service& other_service,
0149 implementation_type& other_impl)
0150 {
0151 move_assign(impl, other_service, other_impl);
0152 }
0153
0154
0155 std::size_t cancel(implementation_type& impl, boost::system::error_code& ec)
0156 {
0157 if (!impl.might_have_pending_waits)
0158 {
0159 ec = boost::system::error_code();
0160 return 0;
0161 }
0162
0163 BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(),
0164 "deadline_timer", &impl, 0, "cancel"));
0165
0166 std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
0167 impl.might_have_pending_waits = false;
0168 ec = boost::system::error_code();
0169 return count;
0170 }
0171
0172
0173 std::size_t cancel_one(implementation_type& impl,
0174 boost::system::error_code& ec)
0175 {
0176 if (!impl.might_have_pending_waits)
0177 {
0178 ec = boost::system::error_code();
0179 return 0;
0180 }
0181
0182 BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(),
0183 "deadline_timer", &impl, 0, "cancel_one"));
0184
0185 std::size_t count = scheduler_.cancel_timer(
0186 timer_queue_, impl.timer_data, 1);
0187 if (count == 0)
0188 impl.might_have_pending_waits = false;
0189 ec = boost::system::error_code();
0190 return count;
0191 }
0192
0193
0194 time_type expiry(const implementation_type& impl) const
0195 {
0196 return impl.expiry;
0197 }
0198
0199
0200 time_type expires_at(const implementation_type& impl) const
0201 {
0202 return impl.expiry;
0203 }
0204
0205
0206 duration_type expires_from_now(const implementation_type& impl) const
0207 {
0208 return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());
0209 }
0210
0211
0212 std::size_t expires_at(implementation_type& impl,
0213 const time_type& expiry_time, boost::system::error_code& ec)
0214 {
0215 std::size_t count = cancel(impl, ec);
0216 impl.expiry = expiry_time;
0217 ec = boost::system::error_code();
0218 return count;
0219 }
0220
0221
0222 std::size_t expires_after(implementation_type& impl,
0223 const duration_type& expiry_time, boost::system::error_code& ec)
0224 {
0225 return expires_at(impl,
0226 Time_Traits::add(Time_Traits::now(), expiry_time), ec);
0227 }
0228
0229
0230 std::size_t expires_from_now(implementation_type& impl,
0231 const duration_type& expiry_time, boost::system::error_code& ec)
0232 {
0233 return expires_at(impl,
0234 Time_Traits::add(Time_Traits::now(), expiry_time), ec);
0235 }
0236
0237
0238 void wait(implementation_type& impl, boost::system::error_code& ec)
0239 {
0240 time_type now = Time_Traits::now();
0241 ec = boost::system::error_code();
0242 while (Time_Traits::less_than(now, impl.expiry) && !ec)
0243 {
0244 this->do_wait(Time_Traits::to_posix_duration(
0245 Time_Traits::subtract(impl.expiry, now)), ec);
0246 now = Time_Traits::now();
0247 }
0248 }
0249
0250
0251 template <typename Handler, typename IoExecutor>
0252 void async_wait(implementation_type& impl,
0253 Handler& handler, const IoExecutor& io_ex)
0254 {
0255 associated_cancellation_slot_t<Handler> slot
0256 = boost::asio::get_associated_cancellation_slot(handler);
0257
0258
0259 typedef wait_handler<Handler, IoExecutor> op;
0260 typename op::ptr p = { boost::asio::detail::addressof(handler),
0261 op::ptr::allocate(handler), 0 };
0262 p.p = new (p.v) op(handler, io_ex);
0263
0264
0265 if (slot.is_connected())
0266 {
0267 p.p->cancellation_key_ =
0268 &slot.template emplace<op_cancellation>(this, &impl.timer_data);
0269 }
0270
0271 impl.might_have_pending_waits = true;
0272
0273 BOOST_ASIO_HANDLER_CREATION((scheduler_.context(),
0274 *p.p, "deadline_timer", &impl, 0, "async_wait"));
0275
0276 scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
0277 p.v = p.p = 0;
0278 }
0279
0280 private:
0281
0282
0283
0284 template <typename Duration>
0285 void do_wait(const Duration& timeout, boost::system::error_code& ec)
0286 {
0287 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0288 std::this_thread::sleep_for(
0289 std::chrono::seconds(timeout.total_seconds())
0290 + std::chrono::microseconds(timeout.total_microseconds()));
0291 ec = boost::system::error_code();
0292 #else
0293 ::timeval tv;
0294 tv.tv_sec = timeout.total_seconds();
0295 tv.tv_usec = timeout.total_microseconds() % 1000000;
0296 socket_ops::select(0, 0, 0, 0, &tv, ec);
0297 #endif
0298 }
0299
0300
0301 class op_cancellation
0302 {
0303 public:
0304 op_cancellation(deadline_timer_service* s,
0305 typename timer_queue<Time_Traits>::per_timer_data* p)
0306 : service_(s),
0307 timer_data_(p)
0308 {
0309 }
0310
0311 void operator()(cancellation_type_t type)
0312 {
0313 if (!!(type &
0314 (cancellation_type::terminal
0315 | cancellation_type::partial
0316 | cancellation_type::total)))
0317 {
0318 service_->scheduler_.cancel_timer_by_key(
0319 service_->timer_queue_, timer_data_, this);
0320 }
0321 }
0322
0323 private:
0324 deadline_timer_service* service_;
0325 typename timer_queue<Time_Traits>::per_timer_data* timer_data_;
0326 };
0327
0328
0329 timer_queue<Time_Traits> timer_queue_;
0330
0331
0332 timer_scheduler& scheduler_;
0333 };
0334
0335 }
0336 }
0337 }
0338
0339 #include <boost/asio/detail/pop_options.hpp>
0340
0341 #endif