1 | // |
2 | // detail/deadline_timer_service.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 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 BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP |
12 | #define BOOST_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 <boost/asio/detail/config.hpp> |
19 | #include <cstddef> |
20 | #include <boost/asio/error.hpp> |
21 | #include <boost/asio/io_service.hpp> |
22 | #include <boost/asio/detail/addressof.hpp> |
23 | #include <boost/asio/detail/bind_handler.hpp> |
24 | #include <boost/asio/detail/fenced_block.hpp> |
25 | #include <boost/asio/detail/noncopyable.hpp> |
26 | #include <boost/asio/detail/socket_ops.hpp> |
27 | #include <boost/asio/detail/socket_types.hpp> |
28 | #include <boost/asio/detail/timer_queue.hpp> |
29 | #include <boost/asio/detail/timer_scheduler.hpp> |
30 | #include <boost/asio/detail/wait_handler.hpp> |
31 | #include <boost/asio/detail/wait_op.hpp> |
32 | |
33 | #if defined(BOOST_ASIO_WINDOWS_RUNTIME) |
34 | # include <chrono> |
35 | # include <thread> |
36 | #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) |
37 | |
38 | #include <boost/asio/detail/push_options.hpp> |
39 | |
40 | namespace boost { |
41 | namespace asio { |
42 | namespace detail { |
43 | |
44 | template <typename Time_Traits> |
45 | class deadline_timer_service |
46 | { |
47 | public: |
48 | // The time type. |
49 | typedef typename Time_Traits::time_type time_type; |
50 | |
51 | // The duration type. |
52 | typedef typename Time_Traits::duration_type duration_type; |
53 | |
54 | // The implementation type of the timer. This type is dependent on the |
55 | // underlying implementation of the timer service. |
56 | struct implementation_type |
57 | : private boost::asio::detail::noncopyable |
58 | { |
59 | time_type expiry; |
60 | bool might_have_pending_waits; |
61 | typename timer_queue<Time_Traits>::per_timer_data timer_data; |
62 | }; |
63 | |
64 | // Constructor. |
65 | deadline_timer_service(boost::asio::io_service& io_service) |
66 | : scheduler_(boost::asio::use_service<timer_scheduler>(ios&: io_service)) |
67 | { |
68 | scheduler_.init_task(); |
69 | scheduler_.add_timer_queue(timer_queue_); |
70 | } |
71 | |
72 | // Destructor. |
73 | ~deadline_timer_service() |
74 | { |
75 | scheduler_.remove_timer_queue(timer_queue_); |
76 | } |
77 | |
78 | // Destroy all user-defined handler objects owned by the service. |
79 | void shutdown_service() |
80 | { |
81 | } |
82 | |
83 | // Construct a new timer implementation. |
84 | void construct(implementation_type& impl) |
85 | { |
86 | impl.expiry = time_type(); |
87 | impl.might_have_pending_waits = false; |
88 | } |
89 | |
90 | // Destroy a timer implementation. |
91 | void destroy(implementation_type& impl) |
92 | { |
93 | boost::system::error_code ec; |
94 | cancel(impl, ec); |
95 | } |
96 | |
97 | // Cancel any asynchronous wait operations associated with the timer. |
98 | std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) |
99 | { |
100 | if (!impl.might_have_pending_waits) |
101 | { |
102 | ec = boost::system::error_code(); |
103 | return 0; |
104 | } |
105 | |
106 | BOOST_ASIO_HANDLER_OPERATION(("deadline_timer" , &impl, "cancel" )); |
107 | |
108 | std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); |
109 | impl.might_have_pending_waits = false; |
110 | ec = boost::system::error_code(); |
111 | return count; |
112 | } |
113 | |
114 | // Cancels one asynchronous wait operation associated with the timer. |
115 | std::size_t cancel_one(implementation_type& impl, |
116 | boost::system::error_code& ec) |
117 | { |
118 | if (!impl.might_have_pending_waits) |
119 | { |
120 | ec = boost::system::error_code(); |
121 | return 0; |
122 | } |
123 | |
124 | BOOST_ASIO_HANDLER_OPERATION(("deadline_timer" , &impl, "cancel_one" )); |
125 | |
126 | std::size_t count = scheduler_.cancel_timer( |
127 | timer_queue_, impl.timer_data, 1); |
128 | if (count == 0) |
129 | impl.might_have_pending_waits = false; |
130 | ec = boost::system::error_code(); |
131 | return count; |
132 | } |
133 | |
134 | // Get the expiry time for the timer as an absolute time. |
135 | time_type expires_at(const implementation_type& impl) const |
136 | { |
137 | return impl.expiry; |
138 | } |
139 | |
140 | // Set the expiry time for the timer as an absolute time. |
141 | std::size_t expires_at(implementation_type& impl, |
142 | const time_type& expiry_time, boost::system::error_code& ec) |
143 | { |
144 | std::size_t count = cancel(impl, ec); |
145 | impl.expiry = expiry_time; |
146 | ec = boost::system::error_code(); |
147 | return count; |
148 | } |
149 | |
150 | // Get the expiry time for the timer relative to now. |
151 | duration_type expires_from_now(const implementation_type& impl) const |
152 | { |
153 | return Time_Traits::subtract(expires_at(impl), Time_Traits::now()); |
154 | } |
155 | |
156 | // Set the expiry time for the timer relative to now. |
157 | std::size_t expires_from_now(implementation_type& impl, |
158 | const duration_type& expiry_time, boost::system::error_code& ec) |
159 | { |
160 | return expires_at(impl, |
161 | Time_Traits::add(Time_Traits::now(), expiry_time), ec); |
162 | } |
163 | |
164 | // Perform a blocking wait on the timer. |
165 | void wait(implementation_type& impl, boost::system::error_code& ec) |
166 | { |
167 | time_type now = Time_Traits::now(); |
168 | ec = boost::system::error_code(); |
169 | while (Time_Traits::less_than(now, impl.expiry) && !ec) |
170 | { |
171 | this->do_wait(Time_Traits::to_posix_duration( |
172 | Time_Traits::subtract(impl.expiry, now)), ec); |
173 | now = Time_Traits::now(); |
174 | } |
175 | } |
176 | |
177 | // Start an asynchronous wait on the timer. |
178 | template <typename Handler> |
179 | void async_wait(implementation_type& impl, Handler& handler) |
180 | { |
181 | // Allocate and construct an operation to wrap the handler. |
182 | typedef wait_handler<Handler> op; |
183 | typename op::ptr p = { boost::asio::detail::addressof(handler), |
184 | boost_asio_handler_alloc_helpers::allocate( |
185 | sizeof(op), handler), 0 }; |
186 | p.p = new (p.v) op(handler); |
187 | |
188 | impl.might_have_pending_waits = true; |
189 | |
190 | BOOST_ASIO_HANDLER_CREATION((p.p, "deadline_timer" , &impl, "async_wait" )); |
191 | |
192 | scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); |
193 | p.v = p.p = 0; |
194 | } |
195 | |
196 | private: |
197 | // Helper function to wait given a duration type. The duration type should |
198 | // either be of type boost::posix_time::time_duration, or implement the |
199 | // required subset of its interface. |
200 | template <typename Duration> |
201 | void do_wait(const Duration& timeout, boost::system::error_code& ec) |
202 | { |
203 | #if defined(BOOST_ASIO_WINDOWS_RUNTIME) |
204 | std::this_thread::sleep_for( |
205 | std::chrono::seconds(timeout.total_seconds()) |
206 | + std::chrono::microseconds(timeout.total_microseconds())); |
207 | ec = boost::system::error_code(); |
208 | #else // defined(BOOST_ASIO_WINDOWS_RUNTIME) |
209 | ::timeval tv; |
210 | tv.tv_sec = timeout.total_seconds(); |
211 | tv.tv_usec = timeout.total_microseconds() % 1000000; |
212 | socket_ops::select(nfds: 0, readfds: 0, writefds: 0, exceptfds: 0, timeout: &tv, ec); |
213 | #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) |
214 | } |
215 | |
216 | // The queue of timers. |
217 | timer_queue<Time_Traits> timer_queue_; |
218 | |
219 | // The object that schedules and executes timers. Usually a reactor. |
220 | timer_scheduler& scheduler_; |
221 | }; |
222 | |
223 | } // namespace detail |
224 | } // namespace asio |
225 | } // namespace boost |
226 | |
227 | #include <boost/asio/detail/pop_options.hpp> |
228 | |
229 | #endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP |
230 | |