1 | // |
2 | // detail/task_io_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_TASK_IO_SERVICE_HPP |
12 | #define BOOST_ASIO_DETAIL_TASK_IO_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 | |
20 | #if !defined(BOOST_ASIO_HAS_IOCP) |
21 | |
22 | #include <boost/system/error_code.hpp> |
23 | #include <boost/asio/io_service.hpp> |
24 | #include <boost/asio/detail/atomic_count.hpp> |
25 | #include <boost/asio/detail/call_stack.hpp> |
26 | #include <boost/asio/detail/event.hpp> |
27 | #include <boost/asio/detail/mutex.hpp> |
28 | #include <boost/asio/detail/op_queue.hpp> |
29 | #include <boost/asio/detail/reactor_fwd.hpp> |
30 | #include <boost/asio/detail/task_io_service_operation.hpp> |
31 | |
32 | #include <boost/asio/detail/push_options.hpp> |
33 | |
34 | namespace boost { |
35 | namespace asio { |
36 | namespace detail { |
37 | |
38 | struct task_io_service_thread_info; |
39 | |
40 | class task_io_service |
41 | : public boost::asio::detail::service_base<task_io_service> |
42 | { |
43 | public: |
44 | typedef task_io_service_operation operation; |
45 | |
46 | // Constructor. Specifies the number of concurrent threads that are likely to |
47 | // run the io_service. If set to 1 certain optimisation are performed. |
48 | BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service, |
49 | std::size_t concurrency_hint = 0); |
50 | |
51 | // Destroy all user-defined handler objects owned by the service. |
52 | BOOST_ASIO_DECL void shutdown_service(); |
53 | |
54 | // Initialise the task, if required. |
55 | BOOST_ASIO_DECL void init_task(); |
56 | |
57 | // Run the event loop until interrupted or no more work. |
58 | BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); |
59 | |
60 | // Run until interrupted or one operation is performed. |
61 | BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); |
62 | |
63 | // Poll for operations without blocking. |
64 | BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); |
65 | |
66 | // Poll for one operation without blocking. |
67 | BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); |
68 | |
69 | // Interrupt the event processing loop. |
70 | BOOST_ASIO_DECL void stop(); |
71 | |
72 | // Determine whether the io_service is stopped. |
73 | BOOST_ASIO_DECL bool stopped() const; |
74 | |
75 | // Reset in preparation for a subsequent run invocation. |
76 | BOOST_ASIO_DECL void reset(); |
77 | |
78 | // Notify that some work has started. |
79 | void work_started() |
80 | { |
81 | ++outstanding_work_; |
82 | } |
83 | |
84 | // Notify that some work has finished. |
85 | void work_finished() |
86 | { |
87 | if (--outstanding_work_ == 0) |
88 | stop(); |
89 | } |
90 | |
91 | // Return whether a handler can be dispatched immediately. |
92 | bool can_dispatch() |
93 | { |
94 | return thread_call_stack::contains(k: this) != 0; |
95 | } |
96 | |
97 | // Request invocation of the given handler. |
98 | template <typename Handler> |
99 | void dispatch(Handler& handler); |
100 | |
101 | // Request invocation of the given handler and return immediately. |
102 | template <typename Handler> |
103 | void post(Handler& handler); |
104 | |
105 | // Request invocation of the given operation and return immediately. Assumes |
106 | // that work_started() has not yet been called for the operation. |
107 | BOOST_ASIO_DECL void post_immediate_completion( |
108 | operation* op, bool is_continuation); |
109 | |
110 | // Request invocation of the given operation and return immediately. Assumes |
111 | // that work_started() was previously called for the operation. |
112 | BOOST_ASIO_DECL void post_deferred_completion(operation* op); |
113 | |
114 | // Request invocation of the given operations and return immediately. Assumes |
115 | // that work_started() was previously called for each operation. |
116 | BOOST_ASIO_DECL void post_deferred_completions(op_queue<operation>& ops); |
117 | |
118 | // Process unfinished operations as part of a shutdown_service operation. |
119 | // Assumes that work_started() was previously called for the operations. |
120 | BOOST_ASIO_DECL void abandon_operations(op_queue<operation>& ops); |
121 | |
122 | private: |
123 | // Structure containing thread-specific data. |
124 | typedef task_io_service_thread_info thread_info; |
125 | |
126 | // Enqueue the given operation following a failed attempt to dispatch the |
127 | // operation for immediate invocation. |
128 | BOOST_ASIO_DECL void do_dispatch(operation* op); |
129 | |
130 | // Run at most one operation. May block. |
131 | BOOST_ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock, |
132 | thread_info& this_thread, const boost::system::error_code& ec); |
133 | |
134 | // Poll for at most one operation. |
135 | BOOST_ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock, |
136 | thread_info& this_thread, const boost::system::error_code& ec); |
137 | |
138 | // Stop the task and all idle threads. |
139 | BOOST_ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); |
140 | |
141 | // Wake a single idle thread, or the task, and always unlock the mutex. |
142 | BOOST_ASIO_DECL void wake_one_thread_and_unlock( |
143 | mutex::scoped_lock& lock); |
144 | |
145 | // Helper class to perform task-related operations on block exit. |
146 | struct task_cleanup; |
147 | friend struct task_cleanup; |
148 | |
149 | // Helper class to call work-related operations on block exit. |
150 | struct work_cleanup; |
151 | friend struct work_cleanup; |
152 | |
153 | // Whether to optimise for single-threaded use cases. |
154 | const bool one_thread_; |
155 | |
156 | // Mutex to protect access to internal data. |
157 | mutable mutex mutex_; |
158 | |
159 | // Event to wake up blocked threads. |
160 | event wakeup_event_; |
161 | |
162 | // The task to be run by this service. |
163 | reactor* task_; |
164 | |
165 | // Operation object to represent the position of the task in the queue. |
166 | struct task_operation : operation |
167 | { |
168 | task_operation() : operation(0) {} |
169 | } task_operation_; |
170 | |
171 | // Whether the task has been interrupted. |
172 | bool task_interrupted_; |
173 | |
174 | // The count of unfinished work. |
175 | atomic_count outstanding_work_; |
176 | |
177 | // The queue of handlers that are ready to be delivered. |
178 | op_queue<operation> op_queue_; |
179 | |
180 | // Flag to indicate that the dispatcher has been stopped. |
181 | bool stopped_; |
182 | |
183 | // Flag to indicate that the dispatcher has been shut down. |
184 | bool shutdown_; |
185 | |
186 | // Per-thread call stack to track the state of each thread in the io_service. |
187 | typedef call_stack<task_io_service, thread_info> thread_call_stack; |
188 | }; |
189 | |
190 | } // namespace detail |
191 | } // namespace asio |
192 | } // namespace boost |
193 | |
194 | #include <boost/asio/detail/pop_options.hpp> |
195 | |
196 | #include <boost/asio/detail/impl/task_io_service.hpp> |
197 | #if defined(BOOST_ASIO_HEADER_ONLY) |
198 | # include <boost/asio/detail/impl/task_io_service.ipp> |
199 | #endif // defined(BOOST_ASIO_HEADER_ONLY) |
200 | |
201 | #endif // !defined(BOOST_ASIO_HAS_IOCP) |
202 | |
203 | #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP |
204 | |