1 //
2 // detail/scheduler.hpp
3 // ~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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.
103   BOOST_ASIO_DECL bool can_dispatch();
104 
105   /// Capture the current exception so it can be rethrown from a run function.
106   BOOST_ASIO_DECL void capture_current_exception();
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 operations and return immediately. Assumes
114   // that work_started() has not yet been called for the operations.
115   BOOST_ASIO_DECL void post_immediate_completions(std::size_t n,
116       op_queue<operation>& ops, bool is_continuation);
117 
118   // Request invocation of the given operation and return immediately. Assumes
119   // that work_started() was previously called for the operation.
120   BOOST_ASIO_DECL void post_deferred_completion(operation* op);
121 
122   // Request invocation of the given operations and return immediately. Assumes
123   // that work_started() was previously called for each operation.
124   BOOST_ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
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   // Process unfinished operations as part of a shutdownoperation. Assumes that
131   // work_started() was previously called for the operations.
132   BOOST_ASIO_DECL void abandon_operations(op_queue<operation>& ops);
133 
134   // Get the concurrency hint that was used to initialise the scheduler.
concurrency_hint() const135   int concurrency_hint() const
136   {
137     return concurrency_hint_;
138   }
139 
140 private:
141   // The mutex type used by this scheduler.
142   typedef conditionally_enabled_mutex mutex;
143 
144   // The event type used by this scheduler.
145   typedef conditionally_enabled_event event;
146 
147   // Structure containing thread-specific data.
148   typedef scheduler_thread_info thread_info;
149 
150   // Run at most one operation. May block.
151   BOOST_ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,
152       thread_info& this_thread, const boost::system::error_code& ec);
153 
154   // Run at most one operation with a timeout. May block.
155   BOOST_ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock,
156       thread_info& this_thread, long usec, const boost::system::error_code& ec);
157 
158   // Poll for at most one operation.
159   BOOST_ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,
160       thread_info& this_thread, const boost::system::error_code& ec);
161 
162   // Stop the task and all idle threads.
163   BOOST_ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
164 
165   // Wake a single idle thread, or the task, and always unlock the mutex.
166   BOOST_ASIO_DECL void wake_one_thread_and_unlock(
167       mutex::scoped_lock& lock);
168 
169   // Helper class to run the scheduler in its own thread.
170   class thread_function;
171   friend class thread_function;
172 
173   // Helper class to perform task-related operations on block exit.
174   struct task_cleanup;
175   friend struct task_cleanup;
176 
177   // Helper class to call work-related operations on block exit.
178   struct work_cleanup;
179   friend struct work_cleanup;
180 
181   // Whether to optimise for single-threaded use cases.
182   const bool one_thread_;
183 
184   // Mutex to protect access to internal data.
185   mutable mutex mutex_;
186 
187   // Event to wake up blocked threads.
188   event wakeup_event_;
189 
190   // The task to be run by this service.
191   reactor* task_;
192 
193   // Operation object to represent the position of the task in the queue.
194   struct task_operation : operation
195   {
task_operationboost::asio::detail::scheduler::task_operation196     task_operation() : operation(0) {}
197   } task_operation_;
198 
199   // Whether the task has been interrupted.
200   bool task_interrupted_;
201 
202   // The count of unfinished work.
203   atomic_count outstanding_work_;
204 
205   // The queue of handlers that are ready to be delivered.
206   op_queue<operation> op_queue_;
207 
208   // Flag to indicate that the dispatcher has been stopped.
209   bool stopped_;
210 
211   // Flag to indicate that the dispatcher has been shut down.
212   bool shutdown_;
213 
214   // The concurrency hint used to initialise the scheduler.
215   const int concurrency_hint_;
216 
217   // The thread that is running the scheduler.
218   boost::asio::detail::thread* thread_;
219 };
220 
221 } // namespace detail
222 } // namespace asio
223 } // namespace boost
224 
225 #include <boost/asio/detail/pop_options.hpp>
226 
227 #if defined(BOOST_ASIO_HEADER_ONLY)
228 # include <boost/asio/detail/impl/scheduler.ipp>
229 #endif // defined(BOOST_ASIO_HEADER_ONLY)
230 
231 #endif // BOOST_ASIO_DETAIL_SCHEDULER_HPP
232