]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // detail/epoll_reactor.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
11fdf7f2 | 5 | // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
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_EPOLL_REACTOR_HPP | |
12 | #define BOOST_ASIO_DETAIL_EPOLL_REACTOR_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 | ||
20 | #if defined(BOOST_ASIO_HAS_EPOLL) | |
21 | ||
7c673cae | 22 | #include <boost/asio/detail/atomic_count.hpp> |
b32b8144 | 23 | #include <boost/asio/detail/conditionally_enabled_mutex.hpp> |
7c673cae | 24 | #include <boost/asio/detail/limits.hpp> |
7c673cae FG |
25 | #include <boost/asio/detail/object_pool.hpp> |
26 | #include <boost/asio/detail/op_queue.hpp> | |
27 | #include <boost/asio/detail/reactor_op.hpp> | |
28 | #include <boost/asio/detail/select_interrupter.hpp> | |
29 | #include <boost/asio/detail/socket_types.hpp> | |
30 | #include <boost/asio/detail/timer_queue_base.hpp> | |
31 | #include <boost/asio/detail/timer_queue_set.hpp> | |
32 | #include <boost/asio/detail/wait_op.hpp> | |
b32b8144 | 33 | #include <boost/asio/execution_context.hpp> |
7c673cae | 34 | |
11fdf7f2 TL |
35 | #if defined(BOOST_ASIO_HAS_TIMERFD) |
36 | # include <sys/timerfd.h> | |
37 | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | |
38 | ||
7c673cae FG |
39 | #include <boost/asio/detail/push_options.hpp> |
40 | ||
41 | namespace boost { | |
42 | namespace asio { | |
43 | namespace detail { | |
44 | ||
45 | class epoll_reactor | |
b32b8144 | 46 | : public execution_context_service_base<epoll_reactor> |
7c673cae | 47 | { |
b32b8144 FG |
48 | private: |
49 | // The mutex type used by this reactor. | |
50 | typedef conditionally_enabled_mutex mutex; | |
51 | ||
7c673cae FG |
52 | public: |
53 | enum op_types { read_op = 0, write_op = 1, | |
54 | connect_op = 1, except_op = 2, max_ops = 3 }; | |
55 | ||
56 | // Per-descriptor queues. | |
57 | class descriptor_state : operation | |
58 | { | |
59 | friend class epoll_reactor; | |
60 | friend class object_pool_access; | |
61 | ||
62 | descriptor_state* next_; | |
63 | descriptor_state* prev_; | |
64 | ||
65 | mutex mutex_; | |
66 | epoll_reactor* reactor_; | |
67 | int descriptor_; | |
68 | uint32_t registered_events_; | |
69 | op_queue<reactor_op> op_queue_[max_ops]; | |
b32b8144 | 70 | bool try_speculative_[max_ops]; |
7c673cae FG |
71 | bool shutdown_; |
72 | ||
b32b8144 | 73 | BOOST_ASIO_DECL descriptor_state(bool locking); |
7c673cae | 74 | void set_ready_events(uint32_t events) { task_result_ = events; } |
b32b8144 | 75 | void add_ready_events(uint32_t events) { task_result_ |= events; } |
7c673cae FG |
76 | BOOST_ASIO_DECL operation* perform_io(uint32_t events); |
77 | BOOST_ASIO_DECL static void do_complete( | |
b32b8144 | 78 | void* owner, operation* base, |
7c673cae FG |
79 | const boost::system::error_code& ec, std::size_t bytes_transferred); |
80 | }; | |
81 | ||
82 | // Per-descriptor data. | |
83 | typedef descriptor_state* per_descriptor_data; | |
84 | ||
85 | // Constructor. | |
b32b8144 | 86 | BOOST_ASIO_DECL epoll_reactor(boost::asio::execution_context& ctx); |
7c673cae FG |
87 | |
88 | // Destructor. | |
89 | BOOST_ASIO_DECL ~epoll_reactor(); | |
90 | ||
91 | // Destroy all user-defined handler objects owned by the service. | |
b32b8144 | 92 | BOOST_ASIO_DECL void shutdown(); |
7c673cae FG |
93 | |
94 | // Recreate internal descriptors following a fork. | |
b32b8144 FG |
95 | BOOST_ASIO_DECL void notify_fork( |
96 | boost::asio::execution_context::fork_event fork_ev); | |
7c673cae FG |
97 | |
98 | // Initialise the task. | |
99 | BOOST_ASIO_DECL void init_task(); | |
100 | ||
101 | // Register a socket with the reactor. Returns 0 on success, system error | |
102 | // code on failure. | |
103 | BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, | |
104 | per_descriptor_data& descriptor_data); | |
105 | ||
106 | // Register a descriptor with an associated single operation. Returns 0 on | |
107 | // success, system error code on failure. | |
108 | BOOST_ASIO_DECL int register_internal_descriptor( | |
109 | int op_type, socket_type descriptor, | |
110 | per_descriptor_data& descriptor_data, reactor_op* op); | |
111 | ||
112 | // Move descriptor registration from one descriptor_data object to another. | |
113 | BOOST_ASIO_DECL void move_descriptor(socket_type descriptor, | |
114 | per_descriptor_data& target_descriptor_data, | |
115 | per_descriptor_data& source_descriptor_data); | |
116 | ||
117 | // Post a reactor operation for immediate completion. | |
118 | void post_immediate_completion(reactor_op* op, bool is_continuation) | |
119 | { | |
b32b8144 | 120 | scheduler_.post_immediate_completion(op, is_continuation); |
7c673cae FG |
121 | } |
122 | ||
123 | // Start a new operation. The reactor operation will be performed when the | |
124 | // given descriptor is flagged as ready, or an error has occurred. | |
125 | BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, | |
126 | per_descriptor_data& descriptor_data, reactor_op* op, | |
127 | bool is_continuation, bool allow_speculative); | |
128 | ||
129 | // Cancel all operations associated with the given descriptor. The | |
130 | // handlers associated with the descriptor will be invoked with the | |
131 | // operation_aborted error. | |
132 | BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, | |
133 | per_descriptor_data& descriptor_data); | |
134 | ||
135 | // Cancel any operations that are running against the descriptor and remove | |
b32b8144 FG |
136 | // its registration from the reactor. The reactor resources associated with |
137 | // the descriptor must be released by calling cleanup_descriptor_data. | |
7c673cae FG |
138 | BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor, |
139 | per_descriptor_data& descriptor_data, bool closing); | |
140 | ||
b32b8144 FG |
141 | // Remove the descriptor's registration from the reactor. The reactor |
142 | // resources associated with the descriptor must be released by calling | |
143 | // cleanup_descriptor_data. | |
7c673cae FG |
144 | BOOST_ASIO_DECL void deregister_internal_descriptor( |
145 | socket_type descriptor, per_descriptor_data& descriptor_data); | |
146 | ||
b32b8144 FG |
147 | // Perform any post-deregistration cleanup tasks associated with the |
148 | // descriptor data. | |
149 | BOOST_ASIO_DECL void cleanup_descriptor_data( | |
150 | per_descriptor_data& descriptor_data); | |
151 | ||
7c673cae FG |
152 | // Add a new timer queue to the reactor. |
153 | template <typename Time_Traits> | |
154 | void add_timer_queue(timer_queue<Time_Traits>& timer_queue); | |
155 | ||
156 | // Remove a timer queue from the reactor. | |
157 | template <typename Time_Traits> | |
158 | void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); | |
159 | ||
160 | // Schedule a new operation in the given timer queue to expire at the | |
161 | // specified absolute time. | |
162 | template <typename Time_Traits> | |
163 | void schedule_timer(timer_queue<Time_Traits>& queue, | |
164 | const typename Time_Traits::time_type& time, | |
165 | typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); | |
166 | ||
167 | // Cancel the timer operations associated with the given token. Returns the | |
168 | // number of operations that have been posted or dispatched. | |
169 | template <typename Time_Traits> | |
170 | std::size_t cancel_timer(timer_queue<Time_Traits>& queue, | |
171 | typename timer_queue<Time_Traits>::per_timer_data& timer, | |
172 | std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); | |
173 | ||
b32b8144 FG |
174 | // Move the timer operations associated with the given timer. |
175 | template <typename Time_Traits> | |
176 | void move_timer(timer_queue<Time_Traits>& queue, | |
177 | typename timer_queue<Time_Traits>::per_timer_data& target, | |
178 | typename timer_queue<Time_Traits>::per_timer_data& source); | |
179 | ||
7c673cae | 180 | // Run epoll once until interrupted or events are ready to be dispatched. |
b32b8144 | 181 | BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops); |
7c673cae FG |
182 | |
183 | // Interrupt the select loop. | |
184 | BOOST_ASIO_DECL void interrupt(); | |
185 | ||
186 | private: | |
187 | // The hint to pass to epoll_create to size its data structures. | |
188 | enum { epoll_size = 20000 }; | |
189 | ||
190 | // Create the epoll file descriptor. Throws an exception if the descriptor | |
191 | // cannot be created. | |
192 | BOOST_ASIO_DECL static int do_epoll_create(); | |
193 | ||
194 | // Create the timerfd file descriptor. Does not throw. | |
195 | BOOST_ASIO_DECL static int do_timerfd_create(); | |
196 | ||
197 | // Allocate a new descriptor state object. | |
198 | BOOST_ASIO_DECL descriptor_state* allocate_descriptor_state(); | |
199 | ||
200 | // Free an existing descriptor state object. | |
201 | BOOST_ASIO_DECL void free_descriptor_state(descriptor_state* s); | |
202 | ||
203 | // Helper function to add a new timer queue. | |
204 | BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); | |
205 | ||
206 | // Helper function to remove a timer queue. | |
207 | BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); | |
208 | ||
209 | // Called to recalculate and update the timeout. | |
210 | BOOST_ASIO_DECL void update_timeout(); | |
211 | ||
212 | // Get the timeout value for the epoll_wait call. The timeout value is | |
213 | // returned as a number of milliseconds. A return value of -1 indicates | |
214 | // that epoll_wait should block indefinitely. | |
b32b8144 | 215 | BOOST_ASIO_DECL int get_timeout(int msec); |
7c673cae FG |
216 | |
217 | #if defined(BOOST_ASIO_HAS_TIMERFD) | |
218 | // Get the timeout value for the timer descriptor. The return value is the | |
219 | // flag argument to be used when calling timerfd_settime. | |
220 | BOOST_ASIO_DECL int get_timeout(itimerspec& ts); | |
221 | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | |
222 | ||
b32b8144 FG |
223 | // The scheduler implementation used to post completions. |
224 | scheduler& scheduler_; | |
7c673cae FG |
225 | |
226 | // Mutex to protect access to internal data. | |
227 | mutex mutex_; | |
228 | ||
229 | // The interrupter is used to break a blocking epoll_wait call. | |
230 | select_interrupter interrupter_; | |
231 | ||
232 | // The epoll file descriptor. | |
233 | int epoll_fd_; | |
234 | ||
235 | // The timer file descriptor. | |
236 | int timer_fd_; | |
237 | ||
238 | // The timer queues. | |
239 | timer_queue_set timer_queues_; | |
240 | ||
241 | // Whether the service has been shut down. | |
242 | bool shutdown_; | |
243 | ||
244 | // Mutex to protect access to the registered descriptors. | |
245 | mutex registered_descriptors_mutex_; | |
246 | ||
247 | // Keep track of all registered descriptors. | |
248 | object_pool<descriptor_state> registered_descriptors_; | |
249 | ||
250 | // Helper class to do post-perform_io cleanup. | |
251 | struct perform_io_cleanup_on_block_exit; | |
252 | friend struct perform_io_cleanup_on_block_exit; | |
253 | }; | |
254 | ||
255 | } // namespace detail | |
256 | } // namespace asio | |
257 | } // namespace boost | |
258 | ||
259 | #include <boost/asio/detail/pop_options.hpp> | |
260 | ||
261 | #include <boost/asio/detail/impl/epoll_reactor.hpp> | |
262 | #if defined(BOOST_ASIO_HEADER_ONLY) | |
263 | # include <boost/asio/detail/impl/epoll_reactor.ipp> | |
264 | #endif // defined(BOOST_ASIO_HEADER_ONLY) | |
265 | ||
266 | #endif // defined(BOOST_ASIO_HAS_EPOLL) | |
267 | ||
268 | #endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP |