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