Clementine
deadline_timer_service.hpp
1 //
2 // detail/deadline_timer_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
12 #define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include "asio/detail/config.hpp"
19 #include <cstddef>
20 #include "asio/error.hpp"
21 #include "asio/execution_context.hpp"
22 #include "asio/detail/bind_handler.hpp"
23 #include "asio/detail/fenced_block.hpp"
24 #include "asio/detail/memory.hpp"
25 #include "asio/detail/noncopyable.hpp"
26 #include "asio/detail/socket_ops.hpp"
27 #include "asio/detail/socket_types.hpp"
28 #include "asio/detail/timer_queue.hpp"
29 #include "asio/detail/timer_queue_ptime.hpp"
30 #include "asio/detail/timer_scheduler.hpp"
31 #include "asio/detail/wait_handler.hpp"
32 #include "asio/detail/wait_op.hpp"
33 
34 #if defined(ASIO_WINDOWS_RUNTIME)
35 # include <chrono>
36 # include <thread>
37 #endif // defined(ASIO_WINDOWS_RUNTIME)
38 
39 #include "asio/detail/push_options.hpp"
40 
41 namespace asio {
42 namespace detail {
43 
44 template <typename Time_Traits>
46  : public execution_context_service_base<deadline_timer_service<Time_Traits> >
47 {
48 public:
49  // The time type.
50  typedef typename Time_Traits::time_type time_type;
51 
52  // The duration type.
53  typedef typename Time_Traits::duration_type duration_type;
54 
55  // The implementation type of the timer. This type is dependent on the
56  // underlying implementation of the timer service.
59  {
60  time_type expiry;
61  bool might_have_pending_waits;
62  typename timer_queue<Time_Traits>::per_timer_data timer_data;
63  };
64 
65  // Constructor.
69  scheduler_(asio::use_service<timer_scheduler>(context))
70  {
71  scheduler_.init_task();
72  scheduler_.add_timer_queue(timer_queue_);
73  }
74 
75  // Destructor.
77  {
78  scheduler_.remove_timer_queue(timer_queue_);
79  }
80 
81  // Destroy all user-defined handler objects owned by the service.
82  void shutdown()
83  {
84  }
85 
86  // Construct a new timer implementation.
87  void construct(implementation_type& impl)
88  {
89  impl.expiry = time_type();
90  impl.might_have_pending_waits = false;
91  }
92 
93  // Destroy a timer implementation.
94  void destroy(implementation_type& impl)
95  {
97  cancel(impl, ec);
98  }
99 
100  // Move-construct a new timer implementation.
101  void move_construct(implementation_type& impl,
102  implementation_type& other_impl)
103  {
104  scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data);
105 
106  impl.expiry = other_impl.expiry;
107  other_impl.expiry = time_type();
108 
109  impl.might_have_pending_waits = other_impl.might_have_pending_waits;
110  other_impl.might_have_pending_waits = false;
111  }
112 
113  // Move-assign from another timer implementation.
114  void move_assign(implementation_type& impl,
115  deadline_timer_service& other_service,
116  implementation_type& other_impl)
117  {
118  if (this != &other_service)
119  if (impl.might_have_pending_waits)
120  scheduler_.cancel_timer(timer_queue_, impl.timer_data);
121 
122  other_service.scheduler_.move_timer(other_service.timer_queue_,
123  impl.timer_data, other_impl.timer_data);
124 
125  impl.expiry = other_impl.expiry;
126  other_impl.expiry = time_type();
127 
128  impl.might_have_pending_waits = other_impl.might_have_pending_waits;
129  other_impl.might_have_pending_waits = false;
130  }
131 
132  // Move-construct a new timer implementation.
133  void converting_move_construct(implementation_type& impl,
135  {
136  move_construct(impl, other_impl);
137  }
138 
139  // Move-assign from another timer implementation.
140  void converting_move_assign(implementation_type& impl,
141  deadline_timer_service& other_service,
142  implementation_type& other_impl)
143  {
144  move_assign(impl, other_service, other_impl);
145  }
146 
147  // Cancel any asynchronous wait operations associated with the timer.
148  std::size_t cancel(implementation_type& impl, asio::error_code& ec)
149  {
150  if (!impl.might_have_pending_waits)
151  {
152  ec = asio::error_code();
153  return 0;
154  }
155 
156  ASIO_HANDLER_OPERATION((scheduler_.context(),
157  "deadline_timer", &impl, 0, "cancel"));
158 
159  std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
160  impl.might_have_pending_waits = false;
161  ec = asio::error_code();
162  return count;
163  }
164 
165  // Cancels one asynchronous wait operation associated with the timer.
166  std::size_t cancel_one(implementation_type& impl,
167  asio::error_code& ec)
168  {
169  if (!impl.might_have_pending_waits)
170  {
171  ec = asio::error_code();
172  return 0;
173  }
174 
175  ASIO_HANDLER_OPERATION((scheduler_.context(),
176  "deadline_timer", &impl, 0, "cancel_one"));
177 
178  std::size_t count = scheduler_.cancel_timer(
179  timer_queue_, impl.timer_data, 1);
180  if (count == 0)
181  impl.might_have_pending_waits = false;
182  ec = asio::error_code();
183  return count;
184  }
185 
186  // Get the expiry time for the timer as an absolute time.
187  time_type expiry(const implementation_type& impl) const
188  {
189  return impl.expiry;
190  }
191 
192  // Get the expiry time for the timer as an absolute time.
193  time_type expires_at(const implementation_type& impl) const
194  {
195  return impl.expiry;
196  }
197 
198  // Get the expiry time for the timer relative to now.
199  duration_type expires_from_now(const implementation_type& impl) const
200  {
201  return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());
202  }
203 
204  // Set the expiry time for the timer as an absolute time.
205  std::size_t expires_at(implementation_type& impl,
206  const time_type& expiry_time, asio::error_code& ec)
207  {
208  std::size_t count = cancel(impl, ec);
209  impl.expiry = expiry_time;
210  ec = asio::error_code();
211  return count;
212  }
213 
214  // Set the expiry time for the timer relative to now.
215  std::size_t expires_after(implementation_type& impl,
216  const duration_type& expiry_time, asio::error_code& ec)
217  {
218  return expires_at(impl,
219  Time_Traits::add(Time_Traits::now(), expiry_time), ec);
220  }
221 
222  // Set the expiry time for the timer relative to now.
223  std::size_t expires_from_now(implementation_type& impl,
224  const duration_type& expiry_time, asio::error_code& ec)
225  {
226  return expires_at(impl,
227  Time_Traits::add(Time_Traits::now(), expiry_time), ec);
228  }
229 
230  // Perform a blocking wait on the timer.
231  void wait(implementation_type& impl, asio::error_code& ec)
232  {
233  time_type now = Time_Traits::now();
234  ec = asio::error_code();
235  while (Time_Traits::less_than(now, impl.expiry) && !ec)
236  {
237  this->do_wait(Time_Traits::to_posix_duration(
238  Time_Traits::subtract(impl.expiry, now)), ec);
239  now = Time_Traits::now();
240  }
241  }
242 
243  // Start an asynchronous wait on the timer.
244  template <typename Handler, typename IoExecutor>
245  void async_wait(implementation_type& impl,
246  Handler& handler, const IoExecutor& io_ex)
247  {
248  // Allocate and construct an operation to wrap the handler.
250  typename op::ptr p = { asio::detail::addressof(handler),
251  op::ptr::allocate(handler), 0 };
252  p.p = new (p.v) op(handler, io_ex);
253 
254  impl.might_have_pending_waits = true;
255 
256  ASIO_HANDLER_CREATION((scheduler_.context(),
257  *p.p, "deadline_timer", &impl, 0, "async_wait"));
258 
259  scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
260  p.v = p.p = 0;
261  }
262 
263 private:
264  // Helper function to wait given a duration type. The duration type should
265  // either be of type boost::posix_time::time_duration, or implement the
266  // required subset of its interface.
267  template <typename Duration>
268  void do_wait(const Duration& timeout, asio::error_code& ec)
269  {
270 #if defined(ASIO_WINDOWS_RUNTIME)
271  std::this_thread::sleep_for(
272  std::chrono::seconds(timeout.total_seconds())
273  + std::chrono::microseconds(timeout.total_microseconds()));
274  ec = asio::error_code();
275 #else // defined(ASIO_WINDOWS_RUNTIME)
276  ::timeval tv;
277  tv.tv_sec = timeout.total_seconds();
278  tv.tv_usec = timeout.total_microseconds() % 1000000;
279  socket_ops::select(0, 0, 0, 0, &tv, ec);
280 #endif // defined(ASIO_WINDOWS_RUNTIME)
281  }
282 
283  // The queue of timers.
284  timer_queue<Time_Traits> timer_queue_;
285 
286  // The object that schedules and executes timers. Usually a reactor.
287  timer_scheduler& scheduler_;
288 };
289 
290 } // namespace detail
291 } // namespace asio
292 
293 #include "asio/detail/pop_options.hpp"
294 
295 #endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
Definition: deadline_timer_service.hpp:45
Definition: wait_handler.hpp:32
Definition: noncopyable.hpp:25
Definition: execution_context.hpp:386
A context for function object execution.
Definition: execution_context.hpp:105
Definition: chrono.h:284
Definition: deadline_timer_service.hpp:57
Definition: timer_queue.hpp:35
Class to represent an error code value.
Definition: error_code.hpp:80
execution_context & context()
Get the context object that owns the service.
Definition: execution_context.hpp:100
Definition: timer_queue.hpp:46
void shutdown()
Destroy all user-defined handler objects owned by the service.
Definition: deadline_timer_service.hpp:82
Definition: any_io_executor.hpp:28