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