1 // 2 // detail/epoll_reactor.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 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_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 22 #include <boost/asio/detail/atomic_count.hpp> 23 #include <boost/asio/detail/conditionally_enabled_mutex.hpp> 24 #include <boost/asio/detail/limits.hpp> 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> 33 #include <boost/asio/execution_context.hpp> 34 35 #if defined(BOOST_ASIO_HAS_TIMERFD) 36 # include <sys/timerfd.h> 37 #endif // defined(BOOST_ASIO_HAS_TIMERFD) 38 39 #include <boost/asio/detail/push_options.hpp> 40 41 namespace boost { 42 namespace asio { 43 namespace detail { 44 45 class epoll_reactor 46 : public execution_context_service_base<epoll_reactor> 47 { 48 private: 49 // The mutex type used by this reactor. 50 typedef conditionally_enabled_mutex mutex; 51 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]; 70 bool try_speculative_[max_ops]; 71 bool shutdown_; 72 73 BOOST_ASIO_DECL descriptor_state(bool locking); set_ready_events(uint32_t events)74 void set_ready_events(uint32_t events) { task_result_ = events; } add_ready_events(uint32_t events)75 void add_ready_events(uint32_t events) { task_result_ |= events; } 76 BOOST_ASIO_DECL operation* perform_io(uint32_t events); 77 BOOST_ASIO_DECL static void do_complete( 78 void* owner, operation* base, 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. 86 BOOST_ASIO_DECL epoll_reactor(boost::asio::execution_context& ctx); 87 88 // Destructor. 89 BOOST_ASIO_DECL ~epoll_reactor(); 90 91 // Destroy all user-defined handler objects owned by the service. 92 BOOST_ASIO_DECL void shutdown(); 93 94 // Recreate internal descriptors following a fork. 95 BOOST_ASIO_DECL void notify_fork( 96 boost::asio::execution_context::fork_event fork_ev); 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. post_immediate_completion(reactor_op * op,bool is_continuation)118 void post_immediate_completion(reactor_op* op, bool is_continuation) 119 { 120 scheduler_.post_immediate_completion(op, is_continuation); 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 136 // its registration from the reactor. The reactor resources associated with 137 // the descriptor must be released by calling cleanup_descriptor_data. 138 BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor, 139 per_descriptor_data& descriptor_data, bool closing); 140 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. 144 BOOST_ASIO_DECL void deregister_internal_descriptor( 145 socket_type descriptor, per_descriptor_data& descriptor_data); 146 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 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 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 180 // Run epoll once until interrupted or events are ready to be dispatched. 181 BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops); 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. 215 BOOST_ASIO_DECL int get_timeout(int msec); 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 223 // The scheduler implementation used to post completions. 224 scheduler& scheduler_; 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 269