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