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