1 //
2 // detail/select_reactor.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 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_SELECT_REACTOR_HPP
12 #define ASIO_DETAIL_SELECT_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 "asio/detail/config.hpp"
19 
20 #if defined(ASIO_HAS_IOCP) \
21   || (!defined(ASIO_HAS_DEV_POLL) \
22       && !defined(ASIO_HAS_EPOLL) \
23       && !defined(ASIO_HAS_KQUEUE) \
24       && !defined(ASIO_WINDOWS_RUNTIME))
25 
26 #include <cstddef>
27 #include "asio/detail/fd_set_adapter.hpp"
28 #include "asio/detail/limits.hpp"
29 #include "asio/detail/mutex.hpp"
30 #include "asio/detail/op_queue.hpp"
31 #include "asio/detail/reactor_op.hpp"
32 #include "asio/detail/reactor_op_queue.hpp"
33 #include "asio/detail/select_interrupter.hpp"
34 #include "asio/detail/socket_types.hpp"
35 #include "asio/detail/timer_queue_base.hpp"
36 #include "asio/detail/timer_queue_set.hpp"
37 #include "asio/detail/wait_op.hpp"
38 #include "asio/io_service.hpp"
39 
40 #if defined(ASIO_HAS_IOCP)
41 # include "asio/detail/thread.hpp"
42 #endif // defined(ASIO_HAS_IOCP)
43 
44 #include "asio/detail/push_options.hpp"
45 
46 namespace asio {
47 namespace detail {
48 
49 class select_reactor
50   : public asio::detail::service_base<select_reactor>
51 {
52 public:
53 #if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
54   enum op_types { read_op = 0, write_op = 1, except_op = 2,
55     max_select_ops = 3, connect_op = 3, max_ops = 4 };
56 #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
57   enum op_types { read_op = 0, write_op = 1, except_op = 2,
58     max_select_ops = 3, connect_op = 1, max_ops = 3 };
59 #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
60 
61   // Per-descriptor data.
62   struct per_descriptor_data
63   {
64   };
65 
66   // Constructor.
67   ASIO_DECL select_reactor(asio::io_service& io_service);
68 
69   // Destructor.
70   ASIO_DECL ~select_reactor();
71 
72   // Destroy all user-defined handler objects owned by the service.
73   ASIO_DECL void shutdown_service();
74 
75   // Recreate internal descriptors following a fork.
76   ASIO_DECL void fork_service(
77       asio::io_service::fork_event fork_ev);
78 
79   // Initialise the task, but only if the reactor is not in its own thread.
80   ASIO_DECL void init_task();
81 
82   // Register a socket with the reactor. Returns 0 on success, system error
83   // code on failure.
84   ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
85 
86   // Register a descriptor with an associated single operation. Returns 0 on
87   // success, system error code on failure.
88   ASIO_DECL int register_internal_descriptor(
89       int op_type, socket_type descriptor,
90       per_descriptor_data& descriptor_data, reactor_op* op);
91 
92   // Post a reactor operation for immediate completion.
post_immediate_completion(reactor_op * op,bool is_continuation)93   void post_immediate_completion(reactor_op* op, bool is_continuation)
94   {
95     io_service_.post_immediate_completion(op, is_continuation);
96   }
97 
98   // Start a new operation. The reactor operation will be performed when the
99   // given descriptor is flagged as ready, or an error has occurred.
100   ASIO_DECL void start_op(int op_type, socket_type descriptor,
101       per_descriptor_data&, reactor_op* op, bool is_continuation, bool);
102 
103   // Cancel all operations associated with the given descriptor. The
104   // handlers associated with the descriptor will be invoked with the
105   // operation_aborted error.
106   ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
107 
108   // Cancel any operations that are running against the descriptor and remove
109   // its registration from the reactor.
110   ASIO_DECL void deregister_descriptor(socket_type descriptor,
111       per_descriptor_data&, bool closing);
112 
113   // Remote the descriptor's registration from the reactor.
114   ASIO_DECL void deregister_internal_descriptor(
115       socket_type descriptor, per_descriptor_data& descriptor_data);
116 
117   // Move descriptor registration from one descriptor_data object to another.
118   ASIO_DECL void move_descriptor(socket_type descriptor,
119       per_descriptor_data& target_descriptor_data,
120       per_descriptor_data& source_descriptor_data);
121 
122   // Add a new timer queue to the reactor.
123   template <typename Time_Traits>
124   void add_timer_queue(timer_queue<Time_Traits>& queue);
125 
126   // Remove a timer queue from the reactor.
127   template <typename Time_Traits>
128   void remove_timer_queue(timer_queue<Time_Traits>& queue);
129 
130   // Schedule a new operation in the given timer queue to expire at the
131   // specified absolute time.
132   template <typename Time_Traits>
133   void schedule_timer(timer_queue<Time_Traits>& queue,
134       const typename Time_Traits::time_type& time,
135       typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
136 
137   // Cancel the timer operations associated with the given token. Returns the
138   // number of operations that have been posted or dispatched.
139   template <typename Time_Traits>
140   std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
141       typename timer_queue<Time_Traits>::per_timer_data& timer,
142       std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
143 
144   // Run select once until interrupted or events are ready to be dispatched.
145   ASIO_DECL void run(bool block, op_queue<operation>& ops);
146 
147   // Interrupt the select loop.
148   ASIO_DECL void interrupt();
149 
150 private:
151 #if defined(ASIO_HAS_IOCP)
152   // Run the select loop in the thread.
153   ASIO_DECL void run_thread();
154 
155   // Entry point for the select loop thread.
156   ASIO_DECL static void call_run_thread(select_reactor* reactor);
157 #endif // defined(ASIO_HAS_IOCP)
158 
159   // Helper function to add a new timer queue.
160   ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
161 
162   // Helper function to remove a timer queue.
163   ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
164 
165   // Get the timeout value for the select call.
166   ASIO_DECL timeval* get_timeout(timeval& tv);
167 
168   // Cancel all operations associated with the given descriptor. This function
169   // does not acquire the select_reactor's mutex.
170   ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
171       const asio::error_code& ec);
172 
173   // The io_service implementation used to post completions.
174   io_service_impl& io_service_;
175 
176   // Mutex to protect access to internal data.
177   asio::detail::mutex mutex_;
178 
179   // The interrupter is used to break a blocking select call.
180   select_interrupter interrupter_;
181 
182   // The queues of read, write and except operations.
183   reactor_op_queue<socket_type> op_queue_[max_ops];
184 
185   // The file descriptor sets to be passed to the select system call.
186   fd_set_adapter fd_sets_[max_select_ops];
187 
188   // The timer queues.
189   timer_queue_set timer_queues_;
190 
191 #if defined(ASIO_HAS_IOCP)
192   // Does the reactor loop thread need to stop.
193   bool stop_thread_;
194 
195   // The thread that is running the reactor loop.
196   asio::detail::thread* thread_;
197 #endif // defined(ASIO_HAS_IOCP)
198 
199   // Whether the service has been shut down.
200   bool shutdown_;
201 };
202 
203 } // namespace detail
204 } // namespace asio
205 
206 #include "asio/detail/pop_options.hpp"
207 
208 #include "asio/detail/impl/select_reactor.hpp"
209 #if defined(ASIO_HEADER_ONLY)
210 # include "asio/detail/impl/select_reactor.ipp"
211 #endif // defined(ASIO_HEADER_ONLY)
212 
213 #endif // defined(ASIO_HAS_IOCP)
214        //   || (!defined(ASIO_HAS_DEV_POLL)
215        //       && !defined(ASIO_HAS_EPOLL)
216        //       && !defined(ASIO_HAS_KQUEUE)
217        //       && !defined(ASIO_WINDOWS_RUNTIME))
218 
219 #endif // ASIO_DETAIL_SELECT_REACTOR_HPP
220