1 //
2 // detail/dev_poll_reactor.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 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_DEV_POLL_REACTOR_HPP
12 #define BOOST_ASIO_DETAIL_DEV_POLL_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_DEV_POLL)
21 
22 #include <cstddef>
23 #include <vector>
24 #include <sys/devpoll.h>
25 #include <boost/asio/detail/hash_map.hpp>
26 #include <boost/asio/detail/limits.hpp>
27 #include <boost/asio/detail/mutex.hpp>
28 #include <boost/asio/detail/op_queue.hpp>
29 #include <boost/asio/detail/reactor_op.hpp>
30 #include <boost/asio/detail/reactor_op_queue.hpp>
31 #include <boost/asio/detail/select_interrupter.hpp>
32 #include <boost/asio/detail/socket_types.hpp>
33 #include <boost/asio/detail/timer_queue_base.hpp>
34 #include <boost/asio/detail/timer_queue_set.hpp>
35 #include <boost/asio/detail/wait_op.hpp>
36 #include <boost/asio/execution_context.hpp>
37 
38 #include <boost/asio/detail/push_options.hpp>
39 
40 namespace boost {
41 namespace asio {
42 namespace detail {
43 
44 class dev_poll_reactor
45   : public execution_context_service_base<dev_poll_reactor>
46 {
47 public:
48   enum op_types { read_op = 0, write_op = 1,
49     connect_op = 1, except_op = 2, max_ops = 3 };
50 
51   // Per-descriptor data.
52   struct per_descriptor_data
53   {
54   };
55 
56   // Constructor.
57   BOOST_ASIO_DECL dev_poll_reactor(boost::asio::execution_context& ctx);
58 
59   // Destructor.
60   BOOST_ASIO_DECL ~dev_poll_reactor();
61 
62   // Destroy all user-defined handler objects owned by the service.
63   BOOST_ASIO_DECL void shutdown();
64 
65   // Recreate internal descriptors following a fork.
66   BOOST_ASIO_DECL void notify_fork(
67       boost::asio::execution_context::fork_event fork_ev);
68 
69   // Initialise the task.
70   BOOST_ASIO_DECL void init_task();
71 
72   // Register a socket with the reactor. Returns 0 on success, system error
73   // code on failure.
74   BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
75 
76   // Register a descriptor with an associated single operation. Returns 0 on
77   // success, system error code on failure.
78   BOOST_ASIO_DECL int register_internal_descriptor(
79       int op_type, socket_type descriptor,
80       per_descriptor_data& descriptor_data, reactor_op* op);
81 
82   // Move descriptor registration from one descriptor_data object to another.
83   BOOST_ASIO_DECL void move_descriptor(socket_type descriptor,
84       per_descriptor_data& target_descriptor_data,
85       per_descriptor_data& source_descriptor_data);
86 
87   // Post a reactor operation for immediate completion.
post_immediate_completion(reactor_op * op,bool is_continuation)88   void post_immediate_completion(reactor_op* op, bool is_continuation)
89   {
90     scheduler_.post_immediate_completion(op, is_continuation);
91   }
92 
93   // Start a new operation. The reactor operation will be performed when the
94   // given descriptor is flagged as ready, or an error has occurred.
95   BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor,
96       per_descriptor_data&, reactor_op* op,
97       bool is_continuation, bool allow_speculative);
98 
99   // Cancel all operations associated with the given descriptor. The
100   // handlers associated with the descriptor will be invoked with the
101   // operation_aborted error.
102   BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
103 
104   // Cancel any operations that are running against the descriptor and remove
105   // its registration from the reactor. The reactor resources associated with
106   // the descriptor must be released by calling cleanup_descriptor_data.
107   BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor,
108       per_descriptor_data&, bool closing);
109 
110   // Remove the descriptor's registration from the reactor. The reactor
111   // resources associated with the descriptor must be released by calling
112   // cleanup_descriptor_data.
113   BOOST_ASIO_DECL void deregister_internal_descriptor(
114       socket_type descriptor, per_descriptor_data&);
115 
116   // Perform any post-deregistration cleanup tasks associated with the
117   // descriptor data.
118   BOOST_ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);
119 
120   // Add a new timer queue to the reactor.
121   template <typename Time_Traits>
122   void add_timer_queue(timer_queue<Time_Traits>& queue);
123 
124   // Remove a timer queue from the reactor.
125   template <typename Time_Traits>
126   void remove_timer_queue(timer_queue<Time_Traits>& queue);
127 
128   // Schedule a new operation in the given timer queue to expire at the
129   // specified absolute time.
130   template <typename Time_Traits>
131   void schedule_timer(timer_queue<Time_Traits>& queue,
132       const typename Time_Traits::time_type& time,
133       typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
134 
135   // Cancel the timer operations associated with the given token. Returns the
136   // number of operations that have been posted or dispatched.
137   template <typename Time_Traits>
138   std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
139       typename timer_queue<Time_Traits>::per_timer_data& timer,
140       std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
141 
142   // Move the timer operations associated with the given timer.
143   template <typename Time_Traits>
144   void move_timer(timer_queue<Time_Traits>& queue,
145       typename timer_queue<Time_Traits>::per_timer_data& target,
146       typename timer_queue<Time_Traits>::per_timer_data& source);
147 
148   // Run /dev/poll once until interrupted or events are ready to be dispatched.
149   BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops);
150 
151   // Interrupt the select loop.
152   BOOST_ASIO_DECL void interrupt();
153 
154 private:
155   // Create the /dev/poll file descriptor. Throws an exception if the descriptor
156   // cannot be created.
157   BOOST_ASIO_DECL static int do_dev_poll_create();
158 
159   // Helper function to add a new timer queue.
160   BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
161 
162   // Helper function to remove a timer queue.
163   BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
164 
165   // Get the timeout value for the /dev/poll DP_POLL operation. The timeout
166   // value is returned as a number of milliseconds. A return value of -1
167   // indicates that the poll should block indefinitely.
168   BOOST_ASIO_DECL int get_timeout(int msec);
169 
170   // Cancel all operations associated with the given descriptor. The do_cancel
171   // function of the handler objects will be invoked. This function does not
172   // acquire the dev_poll_reactor's mutex.
173   BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
174       const boost::system::error_code& ec);
175 
176   // Add a pending event entry for the given descriptor.
177   BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
178 
179   // The scheduler implementation used to post completions.
180   scheduler& scheduler_;
181 
182   // Mutex to protect access to internal data.
183   boost::asio::detail::mutex mutex_;
184 
185   // The /dev/poll file descriptor.
186   int dev_poll_fd_;
187 
188   // Vector of /dev/poll events waiting to be written to the descriptor.
189   std::vector< ::pollfd> pending_event_changes_;
190 
191   // Hash map to associate a descriptor with a pending event change index.
192   hash_map<int, std::size_t> pending_event_change_index_;
193 
194   // The interrupter is used to break a blocking DP_POLL operation.
195   select_interrupter interrupter_;
196 
197   // The queues of read, write and except operations.
198   reactor_op_queue<socket_type> op_queue_[max_ops];
199 
200   // The timer queues.
201   timer_queue_set timer_queues_;
202 
203   // Whether the service has been shut down.
204   bool shutdown_;
205 };
206 
207 } // namespace detail
208 } // namespace asio
209 } // namespace boost
210 
211 #include <boost/asio/detail/pop_options.hpp>
212 
213 #include <boost/asio/detail/impl/dev_poll_reactor.hpp>
214 #if defined(BOOST_ASIO_HEADER_ONLY)
215 # include <boost/asio/detail/impl/dev_poll_reactor.ipp>
216 #endif // defined(BOOST_ASIO_HEADER_ONLY)
217 
218 #endif // defined(BOOST_ASIO_HAS_DEV_POLL)
219 
220 #endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP
221